Compare commits

...

1165 Commits

Author SHA1 Message Date
Chris Forbes
39a9bd7e20 Fix GPS being given to *everyone* 2011-02-04 18:45:47 +13:00
Paul Chote
504fe9e427 Fix infantry group damage 2011-02-04 18:39:04 +13:00
Paul Chote
45e89491d7 Work around a crash. 2011-02-04 18:39:04 +13:00
Paul Chote
b69388b5e7 Fix jerky movement 2011-02-04 18:39:03 +13:00
Paul Chote
e28ed916aa Improve spacing 2011-02-04 18:39:03 +13:00
Paul Chote
310556877f Fix GDI01 2011-02-04 18:39:03 +13:00
Paul Chote
9c63292a83 Allow units to move between subcells. Visually not quite right. 2011-02-04 18:39:03 +13:00
Chris Forbes
4aaafd18f1 fix compile failure 2011-02-04 18:39:03 +13:00
Paul Chote
73a08624ef Hacky fix for group movement 2011-02-04 18:39:03 +13:00
Paul Chote
7c2a7db794 Fold SharesCell into Mobile 2011-02-04 18:39:03 +13:00
Paul Chote
4b3c6cc62a Add a SubCell field to UIM. Allow UIM to query for units by subcell. 2011-02-04 18:39:03 +13:00
Paul Chote
451e06190f Sync harvester contents. Add ISync to ProductionQueue. 2011-02-03 08:27:35 +13:00
Paul Chote
bf2f3cacd9 Sync ProductionQueue 2011-02-02 10:33:33 +13:00
Paul Chote
8002ed0893 (cnc) Support structures don't grant build radius. 2011-02-02 09:22:23 +13:00
Paul Chote
d85411f816 SAM and ATWR require power (#518 and #519). 2011-02-02 09:12:51 +13:00
Paul Chote
2daeb45bfe Fix a subtle bug with flying units in spatialbins. Fixes #489. 2011-02-01 22:06:09 +13:00
Paul Chote
467c2a969d Fix missiles 2011-02-01 18:19:38 +13:00
Chris Forbes
ee144373a0 Fix unshareable GPS 2011-02-01 18:08:21 +13:00
Paul Chote
e234816c13 Extract parameters into Info for mods to tweak. 2011-02-01 17:11:17 +13:00
Paul Chote
8fca705077 Sam sites take 50% damage when closed. 2011-01-31 21:21:38 +13:00
Paul Chote
5f65d4102b cnc sams rotate to home position before closing, lower ROT to something sane. 2011-01-31 21:17:07 +13:00
Paul Chote
cd5e7409ef First attempt. Problems: doesn't move back to zero-facing before closing. Flickers turret-up frame sometimes when being attacked. 2011-01-30 23:11:16 +13:00
Chris Forbes
0c4bf5b2b3 split Target out into its own file 2011-01-30 21:47:04 +13:00
Chris Forbes
51ab2b4969 fix targets staying valid across owner changes 2011-01-30 21:45:08 +13:00
Paul Chote
6e1cb23f10 "Repairing" eva notification for ra and cnc. 2011-01-30 18:35:44 +13:00
Chris Forbes
d595b36cf5 add note in legacymapimporter about colorramp bitrot 2011-01-30 17:47:44 +13:00
Chris Forbes
c8a68659a0 add INotifyOtherCaptured, for reacting to other units changing ownership 2011-01-30 17:43:25 +13:00
Chris Forbes
a0926a49ec hack around bad interaction between firing anims and idle anims finishing 2011-01-30 17:38:34 +13:00
Paul Chote
ccf04240cf Fix some more cases of stale Player references after capture. 2011-01-30 17:35:40 +13:00
Paul Chote
7f3f783187 Update cached PlayerResources when a silo is captured. 2011-01-30 17:35:40 +13:00
Chris Forbes
7a4380e7bd fix exploitable SetStance order 2011-01-30 17:33:04 +13:00
Chris Forbes
79a46272ac remove some crap from viewport 2011-01-30 17:27:39 +13:00
Chris Forbes
1c8cd44465 fix bogosity in SpecialPowerBinWidget (manifests as crash after mod change) 2011-01-30 16:53:20 +13:00
Chris Forbes
3c9891cdea blah 2011-01-30 15:55:46 +13:00
Matthew Bowra-Dean
7b7900bda2 [windows] Fix mod sections in installer to not show expansion buttons. 2011-01-30 14:29:26 +13:00
Chris Forbes
39aa171425 fix visibility of perf graph in ingame and observer roots too. 2011-01-30 14:23:09 +13:00
Chris Forbes
5fce6ec2c4 blah 2011-01-30 14:23:08 +13:00
Chris Forbes
4be20e7aac move waypoint namer into WaypointTool 2011-01-30 14:23:07 +13:00
Chris Forbes
40f88e5c47 clean up editor drawing code some more 2011-01-30 14:23:07 +13:00
Chris Forbes
81468a5190 yet more duplication removal 2011-01-30 14:23:06 +13:00
Chris Forbes
c3b08a60b8 more cleanup 2011-01-30 14:23:06 +13:00
Chris Forbes
8874b6ef72 remove an unused function 2011-01-30 14:23:05 +13:00
Chris Forbes
1dc8de3fc1 split out hardcoded editor tools into ITool impls 2011-01-30 14:23:05 +13:00
Paul Chote
4b538fd2fe Fix palette issues with Oil Derricks and walls (fixes #501). 2011-01-29 13:21:55 +13:00
Paul Chote
9b17bfe697 Fix AFLD production eva (#494). 2011-01-29 13:04:26 +13:00
Paul Chote
d45db9eb9c Shift production audio onto ProductionQueue. 2011-01-29 12:58:56 +13:00
Paul Chote
9a4fb0a5b9 Fix RMBO c4 2011-01-29 12:10:07 +13:00
Chris Forbes
4d7cf23521 updated Nuclear Winter maps from nudalz 2011-01-28 18:40:54 +13:00
Chris Forbes
1e241ebd56 fix editor init 2011-01-28 18:37:00 +13:00
Chris Forbes
add5c0ee6d restore ability to force mod on commandline in editor 2011-01-28 18:10:40 +13:00
Chris Forbes
95e259db3b slightly clean up usings 2011-01-28 18:07:07 +13:00
Chris Forbes
ce8d787a9c fix crash in build palette keyboard handler after winning/losing 2011-01-28 17:32:35 +13:00
Chris Forbes
a8d848b3c4 fix LockTeams checkbox by not using the binder 2011-01-28 17:31:24 +13:00
Paul Chote
0f3b6a7cd4 Add nuclear winter' and seaside' maps by nudalz. 2011-01-28 17:18:06 +13:00
Paul Chote
22c146d056 Fix mod selector visibility on returning to main menu. 2011-01-28 16:42:07 +13:00
Paul Chote
1185386f96 [windows] Remove mod-specific start menu shortcuts and don't download packages in the installer. 2011-01-28 09:15:38 +13:00
Paul Chote
08fd311c4b Hide cnc install `From CD' button. 2011-01-28 09:10:14 +13:00
Paul Chote
687406ccbd Remove mod.html 2011-01-28 09:01:06 +13:00
Paul Chote
37f26c652b Fix installing from cd 2011-01-28 08:59:55 +13:00
Matthew Bowra-Dean
3aac953522 Removed outdated debian menu file. 2011-01-28 08:49:33 +13:00
Matthew Bowra-Dean
5d623b6ca8 Add mod selector to map editor. 2011-01-28 08:49:33 +13:00
Chris Forbes
e543c3b8c1 fix cursors in ra mod 2011-01-28 08:22:23 +13:00
Chris Forbes
6ddce1c171 remove shared 'window' field, fix crashes in GameIniDelegate 2011-01-28 07:34:57 +13:00
Chris Forbes
d3ddefbaa3 add ActionQueue, rather than leaving random variables lying around in Game.cs 2011-01-27 21:46:36 +13:00
Chris Forbes
c1fefe0b96 fix projectfile so it compiles 2011-01-27 21:25:07 +13:00
Paul Chote
8470399a0c [osx] Load packages from the support dir. 2011-01-27 20:50:04 +13:00
Paul Chote
492c025844 Load last mod on startup. 2011-01-27 20:50:04 +13:00
Paul Chote
38b98bf358 Hide the menubar only when going fullscreen. 2011-01-27 20:50:04 +13:00
Paul Chote
746c3d068c Use the existing settings mechanism for --settings-value. Allows the defaults to be queried. 2011-01-27 20:50:04 +13:00
Paul Chote
562d07f11a Fix sln 2011-01-27 20:50:03 +13:00
Paul Chote
ef462c5164 Take SpecialPackageRoot into account when installing packages 2011-01-27 20:50:03 +13:00
Paul Chote
817ac42954 Call as non-admin if gksudo and kdesu aren't available. 2011-01-27 20:50:03 +13:00
Matthew Bowra-Dean
1474cd147a Executable permissions on openra-bin 2011-01-27 20:50:03 +13:00
Matthew Bowra-Dean
d74c93c66e Fixed syntax error in package-all.sh. 2011-01-27 20:50:03 +13:00
Matthew Bowra-Dean
4eaf97f90e Reverted packaging changes from launchers. 2011-01-27 20:50:03 +13:00
Paul Chote
a81c865620 Install Music button - installing not implemented. 2011-01-27 20:50:03 +13:00
Paul Chote
1c67242210 Fix prompt title. 2011-01-27 20:50:03 +13:00
Paul Chote
96a6bda142 Remove obsolete maps dir 2011-01-27 20:50:03 +13:00
Paul Chote
580b9014b3 Install map button (does not verify that maps are valid). 2011-01-27 20:50:03 +13:00
Matthew Bowra-Dean
4c053dae24 Elevation for utility app on unix platforms that have gksudo or kdesudo. Small change to Folder.cs to create empty folder if it doesn't exist. 2011-01-27 20:50:03 +13:00
Paul Chote
1bdadb6631 Clear widgets on mod change 2011-01-27 20:50:03 +13:00
Paul Chote
646863b85b Remove unused InitDelegates() method. Don't mutate the Children list directly. 2011-01-27 20:50:03 +13:00
Paul Chote
3fe549d0a4 don't fork bomb. 2011-01-27 20:50:02 +13:00
Paul Chote
5353ae32a6 Authenticate windows commands. Untested. 2011-01-27 20:50:02 +13:00
Paul Chote
a6900c256d Implement --display-filepicker in OpenRA.Utility. Remove all the functionality that windows doesn't support. 2011-01-27 20:50:02 +13:00
Paul Chote
44d8e83773 Rework OpenRA.Utility 2011-01-27 20:50:02 +13:00
Paul Chote
c93bdf73aa Have a single utility app per platform. Route zip extraction and ra package install to the .net utility app under osx. 2011-01-27 20:50:02 +13:00
Paul Chote
8e5f307ba8 Remove some duplication 2011-01-27 20:50:02 +13:00
Paul Chote
724a72c98e Show the mod switcher during the initial install screen. 2011-01-27 20:50:02 +13:00
Paul Chote
a3f26cec46 Fix sound after mod switching. 2011-01-27 20:50:02 +13:00
Paul Chote
aa319ee403 Begin refactoring utility process launching. 2011-01-27 20:50:02 +13:00
Paul Chote
388e5df377 Show mod version in the main menu. 2011-01-27 20:50:02 +13:00
Paul Chote
d39adf67b2 Indeterminate progress bar 2011-01-27 20:50:02 +13:00
Paul Chote
3609de8ca5 Fix compile warnings 2011-01-27 20:50:02 +13:00
Paul Chote
be9d8d96ce Fix the utility app 2011-01-27 20:50:02 +13:00
Paul Chote
2c0a928b48 Fix terrain being drawn using the cursor palette. 2011-01-27 20:50:02 +13:00
Paul Chote
11aab8705e Display the selector in all menus. Fix information leakage from previous mod. 2011-01-27 20:50:01 +13:00
Paul Chote
37fc836b46 Ingame mod selector ui. 2011-01-27 20:50:01 +13:00
Paul Chote
f44903b50f Support ingame mod switching. 2011-01-27 20:50:01 +13:00
Paul Chote
d32e2be941 Extract zips using background thread. 2011-01-27 20:50:01 +13:00
Paul Chote
84cc94bcb6 Implement install from cd for ra (the cnc installshield decompressor is bugged, so not implementing it yet). 2011-01-27 20:50:01 +13:00
Paul Chote
9227e09f18 Refactoring. Add a missing file. 2011-01-27 20:50:01 +13:00
Paul Chote
b7357b1711 Fix crash when canceling download, fix a runtime warning in osx. 2011-01-27 20:50:01 +13:00
Paul Chote
792c82c2d4 Automatically extract packages. Fix ra. 2011-01-27 20:50:01 +13:00
Paul Chote
5ce5d48b04 Extracting packages 2011-01-27 20:50:01 +13:00
Paul Chote
775ccc112b Progress bars. 2011-01-27 20:50:01 +13:00
Paul Chote
421058866d Better install menu and package downloading. 2011-01-27 20:50:01 +13:00
Paul Chote
7dad013b31 Fix cnc. 2011-01-27 20:50:01 +13:00
Paul Chote
42a5b0a993 Fix the hyperspeed shellmap by setting the initial tick time *after* we're done loading. 2011-01-27 20:50:00 +13:00
Paul Chote
ea9003d6fc Port cursors to yaml. 2011-01-27 20:50:00 +13:00
Paul Chote
827a19adef Fix the cursor during init. 2011-01-27 20:50:00 +13:00
Paul Chote
6a90f00298 Start tidying things up 2011-01-27 20:50:00 +13:00
Paul Chote
abcc43222a Add missing files. 2011-01-27 20:50:00 +13:00
Paul Chote
908a927929 Add "Install from web" "Install from CD" and "Quit" buttons to the install menu. "From CD" prompts a system file picker (osx only). 2011-01-27 20:50:00 +13:00
Paul Chote
6c14b78b7c Load the game into an intermediate state where RAInitDelegate can install packages, etc (an even bigger hack). 2011-01-27 20:50:00 +13:00
Paul Chote
6776d6f906 Load the main menu without loading mixes or creating a shellmap world. A giant hack. 2011-01-27 20:50:00 +13:00
Paul Chote
8d2a78abc6 Expose a native filepicker dialog. 2011-01-27 20:50:00 +13:00
Paul Chote
108b90f192 Allow the ra/cnc package dir to be overridden at launch-time. 2011-01-27 20:50:00 +13:00
Paul Chote
3c1f5e18f9 Use Pseudofullscreen under all platforms by default. 2011-01-27 20:50:00 +13:00
Paul Chote
cae65ddd05 Gut the osx launcher of everything except for the necessary platform shims (Ensure mono is installed, set DYLD_LIBRARY_PATH, Hide dock/menubar if running in fullscreen).
TODO: Parse the yaml to disable menubar only if running fullscreen, register openra:// urls.
2011-01-27 20:50:00 +13:00
Chris Forbes
8cda9d6d8b restore previous sequence after IdleAnimation; apply randomness to idle animation wait 2011-01-27 18:36:36 +13:00
Paul Chote
0bd466a9e9 Use a lookup table for fvecs. 2011-01-27 12:05:13 +13:00
Paul Chote
9db41f5638 Remove fp from facing calculation. 2011-01-27 12:01:02 +13:00
Chris Forbes
ad0e0a18bd fix format80 encoder to actually work 2011-01-26 21:47:54 +13:00
Chris Forbes
6f807c4501 fix bogus writing of EOF header 2011-01-26 21:47:53 +13:00
Chris Forbes
1b3f769f34 shp writer 2011-01-26 21:47:53 +13:00
Chris Forbes
848622054d unstatic SpriteLoader 2011-01-26 21:09:07 +13:00
Chris Forbes
f032322948 remove System.Xml using from SequenceProvider 2011-01-26 21:07:54 +13:00
Chris Forbes
1d7f57941e rename SpriteSheetBuilder to SpriteLoader; it's dumb otherwise 2011-01-26 21:07:54 +13:00
Chris Forbes
0f84ac5215 RenderBuilding.BuildingPreview pushed down to RenderSimple and renamed to .RenderPreview() 2011-01-26 21:06:05 +13:00
Chris Forbes
e6c6e8aa96 remove a bit of dumb duplication 2011-01-26 21:06:05 +13:00
Chris Forbes
180d58c35a only bother hashing traits that have ISync 2011-01-26 21:00:31 +13:00
Chris Forbes
f52620f6fc add ISync to all traits that have [Sync] members 2011-01-26 21:00:28 +13:00
Chris Forbes
b7ea695f0c better error when no sequences defined at all 2011-01-26 20:55:23 +13:00
Paul Chote
272ba08c21 Likewise for PlayerResources 2011-01-25 18:26:15 +13:00
Paul Chote
58f1589f95 Add debug traits to Aircraft so we can see what is desyncing. 2011-01-25 18:19:36 +13:00
Paul Chote
b9e32e5c06 Load maps from <support dir>/maps/<mod>/ too. 2011-01-21 17:38:28 +13:00
Paul Chote
2fca9b0b19 Fix broken first tick rendering in BuildPaletteWidget. 2011-01-20 00:51:13 +13:00
Paul Chote
1fb42f47b6 Remove redundant serverbrowser checks (these are now handled by the handshake process). 2011-01-20 00:32:43 +13:00
Paul Chote
481cc7807b Don't require a WorldRenderer to draw non-world-rendering widgets. 2011-01-19 20:41:32 +13:00
Paul Chote
e3c090a201 More drop messages. 2011-01-15 13:56:52 +13:00
Paul Chote
2f31928a53 Fix packaging clean script. 2011-01-15 13:51:38 +13:00
Paul Chote
06612d0f68 Add a mechanism for custom drop messages. Implement for kick. 2011-01-15 13:49:46 +13:00
Chris Forbes
d835c14988 fix crash in windows launcher 2011-01-11 11:25:50 +13:00
Chris Forbes
a25087a9f3 fix weap door crash in cnc 2011-01-09 17:32:59 +13:00
Chris Forbes
b362d9f9fc fix bogus interpretation of range parameter 2011-01-09 16:09:58 +13:00
Chris Forbes
cb3eca9d5f remove unused NukeLaunch.Silo field 2011-01-09 14:26:32 +13:00
Chris Forbes
4b3f0e9a4b fix breakage in ServerBrowserDelegate which prevented any joins 2011-01-09 14:23:50 +13:00
Chris Forbes
808cc59c59 fix bogus colors in chat 2011-01-09 14:02:15 +13:00
Chris Forbes
727d72123f sync GpsPower.Granted 2011-01-09 13:35:25 +13:00
Chris Forbes
c76822531e shareable, revokable gps 2011-01-09 13:31:53 +13:00
Chris Forbes
9387029b51 remove some sillyness in PlayerResources.Tick 2011-01-09 13:24:54 +13:00
Chris Forbes
b4109b12ca less dumb PlayerResources init 2011-01-09 13:23:29 +13:00
Chris Forbes
70afea85a9 new map format introduced: 4. format3 player colors are automatically upgraded to ColorRamp 2011-01-08 18:17:19 +13:00
Chris Forbes
3426b52247 add ColorRamp type; change everything to use it; maps not yet upgraded 2011-01-08 18:17:18 +13:00
Chris Forbes
e2ff40dc7f better fix for chrono bug 2011-01-08 17:30:29 +13:00
Chris Forbes
07abeffc5e #363 tabs should change color visibly when a building is ready 2011-01-08 16:22:18 +13:00
Chris Forbes
126e200e2e fix chronoshift/shroud interaction desync 2011-01-08 16:08:05 +13:00
alzeih
5c343caeaf Mod version validation
- Game.CurrentMods property to query the current mods when no orderManager accessible
- Server sends mod versions to master server on ping
- Client sends mod versions on handshake response
- Validate match on server side of handshake, not client side
2011-01-08 16:00:29 +13:00
Paul Chote
8264c6c8dc Play "Unable to build more" eva when the production exit is blocked. Also fixes #484. 2011-01-08 13:15:30 +13:00
Chris Forbes
db63724aeb add contrast surround to timer & chat which are displayed straight over the world 2011-01-08 12:21:12 +13:00
Chris Forbes
303525a5ba be fast by default; add 'Check Sync around Unsynced Code' option in debug panel 2011-01-08 11:49:31 +13:00
Chris Forbes
93a56f9a18 #250 resources should have a list of allowed terrain types 2011-01-08 09:31:36 +13:00
Chris Forbes
712eb437ea blah 2011-01-07 20:38:36 +13:00
Paul Chote
e46b00f9c4 Missed a file when unmangling a dirty rebase. 2011-01-07 20:33:14 +13:00
Paul Chote
9f38df013e Target uses int2. 2011-01-07 20:21:47 +13:00
Paul Chote
60e3f7621f Remove fp from CenterLocation and aircraft. 2011-01-07 20:14:22 +13:00
Paul Chote
d395c5e05d Remove dead helicopter instability code, and some unnecessary fp. 2011-01-07 20:00:53 +13:00
Chris Forbes
975682c57b fix silly debug popup in JSBridge 2011-01-07 15:34:28 +13:00
Matthew Bowra-Dean
e50dc9a550 Remove arch 64 package for the moment until packaging tools are sorted out 2011-01-07 15:29:50 +13:00
Matthew Bowra-Dean
63ee3ebf9f Make sure build root is correct (no override from rpmmacros). 2011-01-07 15:29:50 +13:00
Matthew Bowra-Dean
a993116085 Few more changes to rpm. 2011-01-07 15:29:49 +13:00
Matthew Bowra-Dean
eb158e6d21 pkgbuild and RPM fixes 2011-01-07 15:29:48 +13:00
Matthew Bowra-Dean
6a7c968e25 More fixes. 2011-01-07 15:29:47 +13:00
Matthew Bowra-Dean
5665d40e29 Separate root dirs for different architectures. 2011-01-07 15:29:47 +13:00
Matthew Bowra-Dean
3aff455fba Fix some syntax errors 2011-01-07 15:29:46 +13:00
Matthew Bowra-Dean
0d038f00ba 64bit linux packages 2011-01-07 15:29:45 +13:00
Paul Chote
8dcba13491 Fix osx launcher. 2011-01-06 18:51:40 +13:00
Paul Chote
0cef2e4f53 CheckboxWidget delegate methods. 2011-01-06 11:40:06 +13:00
Paul Chote
7443b3ce89 Fix button MouseUp handling. 2011-01-05 23:19:37 +13:00
Paul Chote
7cabe920db Restrict ClickThrough to what it was originally intended for. 2011-01-05 23:15:03 +13:00
Paul Chote
5254deedcb Remove some bogosity from widget mouse handling. 2011-01-05 23:01:17 +13:00
Paul Chote
df460d7407 Add extension methods to Rectangle/RectangleF, remove a pile of ToPoint()'s. 2011-01-05 22:24:11 +13:00
Paul Chote
3e1db3e8ae Move MapPreviewWidget.HandleInputInner to the lobby delegate. 2011-01-05 22:23:23 +13:00
Paul Chote
7b5b84b1b7 Unstatic MakeButton and MakeModifiers. Fixes mouse clicks in vs `Release' builds. 2011-01-05 15:32:21 +13:00
Paul Chote
2e9a0b8162 Fix for nonstandard mono paths. 2011-01-05 15:26:47 +13:00
Paul Chote
22bf9e7aff Further refactoring of Repair. 2011-01-05 13:29:38 +13:00
Paul Chote
40b0408ce7 Fix #453. Bogus crash when desyncing. 2011-01-05 13:09:25 +13:00
Paul Chote
c6fb1b641e Fix MouseButton orthogonality and remove unnecessary winforms dep. 2011-01-05 12:56:11 +13:00
Matthew Bowra-Dean
6998871adf Fix GTK launcher to change to correct working directory. 2011-01-05 09:13:53 +13:00
Matthew Bowra-Dean
2885fbb99b Few more tweaks to packaging 2011-01-05 09:13:37 +13:00
Chris Forbes
cc1c183d66 fix initial placement and facing of mig/yak on afld 2011-01-05 09:12:29 +13:00
Chris Forbes
418284672c clean up some potential fp misbehavior in Repair.cs 2011-01-05 09:12:29 +13:00
Chris Forbes
558647b987 blah 2011-01-05 09:12:28 +13:00
Chris Forbes
f03e6e6258 make it sortof work 2011-01-05 09:12:28 +13:00
Chris Forbes
f44ac769bf use a closure for the request state rather than dicts 2011-01-05 09:12:27 +13:00
Paul Chote
e02ed86088 Content mix files may be inside main.mix. redalert.mix should always be there. 2011-01-04 20:18:54 +13:00
Chris Forbes
dcbb6ee4eb small tweak to HttpUtil - we don't support 1.1, so dont pretend we do; also, set WebClient.Proxy everywhere to null 2011-01-04 20:02:23 +13:00
Chris Forbes
fe720186f5 add fast HttpUtil.DownloadData() 2011-01-04 17:53:00 +13:00
Matthew Bowra-Dean
0803d10746 Changed linux package target platforms to i686 (due to gtklauncher) 2011-01-04 17:50:55 +13:00
Matthew Bowra-Dean
d26ee1094a Rework GTK launcher and linux packages slightly 2011-01-04 17:35:50 +13:00
Matthew Bowra-Dean
68a38c85f9 Uses process IDs in dictionary for httpRequests 2011-01-04 17:34:07 +13:00
Matthew Bowra-Dean
4de390d173 Fix missed call to Call function in Windows launcher. 2011-01-04 17:34:07 +13:00
Matthew Bowra-Dean
fb8812a7fd Fix for concurrent child processes while using pipes for IPC. 2011-01-04 17:34:07 +13:00
Paul Chote
c8a74ef05a fix make install. 2011-01-04 17:12:03 +13:00
Paul Chote
de562939d4 Hacky fix for LabelWidget eating our MouseMove events. 2011-01-04 14:42:38 +13:00
Paul Chote
cc356bcfee Refactoring. 2011-01-04 14:34:00 +13:00
Paul Chote
ece50b0d57 RA Harvester docking sequence. 2011-01-04 14:34:00 +13:00
Paul Chote
76216b8dd9 Move damage sounds and shaking from Building/RenderBuilding into their own traits. Fix wall damage/death sounds under cnc. 2011-01-04 14:34:00 +13:00
Paul Chote
4a47641656 Tweak cnc wall sounds. 2011-01-04 14:34:00 +13:00
Paul Chote
03185fe46b Fix #429. Capturable Oil Derricks. 2011-01-04 14:34:00 +13:00
Paul Chote
cbd3baa6d4 Fix #469. C&C Nuke detonation sound. 2011-01-04 14:33:59 +13:00
Paul Chote
6287b132a0 #438. Show # Players in the map selector. 2011-01-04 14:33:59 +13:00
Paul Chote
6e7156e023 Mousewheel scrolls ScrollPanel. 2011-01-04 14:33:59 +13:00
Paul Chote
1ced0d7ab9 Require LMB for common widget interactions. 2011-01-04 14:33:59 +13:00
Chris Forbes
abeffbbbf7 fix a bunch of errors in the editor; fix minimap export to not suck 2011-01-04 13:45:10 +13:00
Chris Forbes
7f7c7217ba fix missing includes in gtklaunch 2011-01-04 12:53:33 +13:00
Matthew Bowra-Dean
a4de4cc266 Added renderer selection to GTK launcher. 2011-01-02 16:12:07 +13:00
Matthew Bowra-Dean
8ead8635c2 Updated dependencies for gtk launcher, statically link libmicrohttpd 2011-01-02 16:12:07 +13:00
Matthew Bowra-Dean
ecea2471ca Updated linux packaging scripts to remove the need for post install actions and to use the launcher. 2011-01-02 16:12:06 +13:00
Matthew Bowra-Dean
a3e67611e6 Use graphical sudo client for operations that potentially require elevation in gtk launcher. 2011-01-02 16:12:05 +13:00
Matthew Bowra-Dean
562ab0eee0 httpRequest implemented properly in Windows launcher. 2011-01-02 16:12:05 +13:00
Matthew Bowra-Dean
ad478e8872 httpRequest JS bridge function implemented in gtk launcher. 2011-01-02 16:12:04 +13:00
Matthew Bowra-Dean
ec572635b7 metadata JS bridge function implemented. 2011-01-02 16:12:04 +13:00
Matthew Bowra-Dean
44fae60dbd String handling in JS bridge changed to safer glib functions. Added path sanitization. 2011-01-02 16:12:03 +13:00
Matthew Bowra-Dean
0a1e6d16bd Converted most of GTK launcher to use glib's string functions. 2011-01-02 16:12:03 +13:00
Matthew
9739e7f51f Download extraction in GTK+ Launcher. 2011-01-02 16:12:02 +13:00
Matthew
1e4196e8d3 Download cancellation 2011-01-02 16:12:02 +13:00
Matthew Bowra-Dean
2e309b46e8 Downloading works. Still to come: cancelling downloads and extraction. 2011-01-02 16:12:01 +13:00
Matthew Bowra-Dean
5991ecdcf5 Makefile target for gtklauncher. 2011-01-02 16:12:01 +13:00
Matthew Bowra-Dean
360c572e14 launchMod working in JS bridge. 2011-01-02 16:12:00 +13:00
Matthew Bowra-Dean
16a84ba86e Selects last played mod in launcher. 2011-01-02 16:12:00 +13:00
Matthew Bowra-Dean
fcec3cb590 Updated utility app for better compatibility with GTK launcher. 2011-01-02 16:11:59 +13:00
Matthew Bowra-Dean
61f7e1df7f Generate mod tree in GTK tree view. 2011-01-02 16:11:59 +13:00
Matthew Bowra-Dean
650195e31c Utility app helper functions for listing mods in the GTK+ launcher. 2011-01-02 16:11:58 +13:00
Matthew Bowra-Dean
6fbc7bc7c4 Print mod list in an order where dependencies come after prerequisites. 2011-01-02 16:11:58 +13:00
Matthew Bowra-Dean
7e41e75643 Made existsInMod work, added stub for launchMod. 2011-01-02 16:11:57 +13:00
Matthew Bowra-Dean
df00b8cf23 Some refactoring. 2011-01-02 16:11:57 +13:00
Matthew Bowra-Dean
69ee1399b9 Bind to JavaScriptCore. Serve files through embedded web server. 2011-01-02 16:11:56 +13:00
Matthew Bowra-Dean
a561dd376e Proof of concept browser + embedded web server communicating via XMLHttpRequest.
Compile with "gcc -Wall `pkg-config --cflags --libs gtk+-2.0 webkit-1.0 libmicrohttpd` -o launcher main.c server.c"
Requires GTK, libwebkit and libmicrohttpd.
2011-01-02 16:11:55 +13:00
Matthew Bowra-Dean
c9bd3e8a1f Start of GTK launcher in C.
Webkit embedded in GTK window.
2011-01-02 16:11:55 +13:00
Matthew Bowra-Dean
a4493f48d5 httpRequest in win launcher uses utility program. Clean up usings and add missing license notices. 2011-01-02 16:11:54 +13:00
Paul Chote
de5d9abec3 Delayed unloading. Remove LocalStorage from proc. 2011-01-02 15:27:29 +13:00
Paul Chote
3674accd0c Improved cnc proc/harv docking. 2011-01-02 14:56:29 +13:00
Paul Chote
9ffdce7957 Fix #439; Dropdowns stay open when the host force-starts the game. 2011-01-02 14:54:25 +13:00
Paul Chote
38df0a28cd Remove fp from building refund calculation. 2011-01-02 14:54:25 +13:00
Paul Chote
f659f55801 Sync StoresOre.Stored 2011-01-02 14:54:25 +13:00
Paul Chote
f3da258763 Remove GetSiloFullness. 2011-01-02 14:54:25 +13:00
Chris Forbes
2048900c10 fix some dumbness in Production/ITeleportable 2011-01-02 14:41:48 +13:00
Chris Forbes
7b5a8cf089 #394 nuke without a launch site crashes -- fixed 2011-01-01 21:52:43 +13:00
Chris Forbes
a4bbce32b8 cleanup SyncReport.cs header 2011-01-01 21:43:37 +13:00
Chris Forbes
19aed01822 show real player names in syncreport 2011-01-01 21:42:57 +13:00
Chris Forbes
ba2ec557bc fix another dumb bug in ZipFile 2011-01-01 21:24:42 +13:00
Paul Chote
a8b4e640e7 Fix dropdown lists. Visual tweaks. 2011-01-01 17:54:09 +13:00
Paul Chote
d1966ab476 Improved scrollpanel thumb behavior. 2011-01-01 17:21:40 +13:00
Paul Chote
d90dec9c8e Remove a pile of unnecessary state management from Scrollpanels. 2011-01-01 16:47:52 +13:00
Chris Forbes
e2b739cd3e fix bogus spawn on central-conflict 2011-01-01 15:29:45 +13:00
Chris Forbes
dffb5293d0 hack up ZipFile to fix #464; filesystem needs rework to be sane 2011-01-01 15:28:07 +13:00
Chris Forbes
cf2ad68a7c add very basic Format80 encoder 2011-01-01 09:27:39 +13:00
Chris Forbes
119b0c063d don't show a kick button for the host while ready 2011-01-01 00:20:04 +13:00
Paul Chote
b948b9d2b7 Draggable thumbs 2010-12-31 23:59:23 +13:00
Paul Chote
d98e09e096 Draw scrollbar thumbs. 2010-12-31 23:19:13 +13:00
Chris Forbes
cf17bc7e5c clean up perf graph a bit 2010-12-31 20:31:57 +13:00
Paul Chote
42096cc5c9 Foo 2010-12-31 18:26:03 +13:00
Paul Chote
1d3b2334d0 Drop any remaining connections on gamestart. 2010-12-31 17:47:44 +13:00
Paul Chote
64304635b7 Fix dropping unvalidated clients. 2010-12-31 16:52:17 +13:00
Paul Chote
dc9de20553 Fix packaging scripts for BSD sed. 2010-12-31 13:36:37 +13:00
Paul Chote
486fa9a978 Handshake mod versions and map. Bump the protocol version. 2010-12-31 13:35:21 +13:00
Paul Chote
e2d1eec56e Shift Client creation to the client, sent in the handshake response. Fixes the `Newbie' bug and removes a lot of fragmented behaviour on player join. 2010-12-31 12:51:19 +13:00
Paul Chote
8f9e32dcc0 Client/server handshake. Only checks that the correct mods are active. 2010-12-31 11:41:25 +13:00
Paul Chote
dc012c0faf Fix server shutdown crash under mono. 2010-12-30 20:29:11 +13:00
Paul Chote
4f6f3eb80d Upgrade maps to oramap format. Save type field. 2010-12-30 18:00:44 +13:00
Paul Chote
fd49ca75d7 Forgot launcher files. 2010-12-30 17:51:23 +13:00
Paul Chote
cb50182fac Bugfixes: ZipFile.GetInputStream().GetAllBytes/.Length doesn't work; Divide by zero when no shellmaps are available; UseAsShellmap isn't saved by the editor; Duplicate maps crashes game. 2010-12-30 17:43:44 +13:00
Paul Chote
47bbc3a6de Wire up the rest of saving. Save-as will now properly overwrite existing contents. 2010-12-30 17:43:44 +13:00
Paul Chote
39ed6087cb Use utility app for http requests; Make them async. 2010-12-30 15:17:56 +13:00
Matthew Bowra-Dean
428999fc0b Create an empty zip file if it doesn't exist. 2010-12-30 02:21:39 +13:00
Paul Chote
b7975031bc Wire up most of saving again. 2010-12-29 22:13:51 +13:00
Paul Chote
e652a15b01 Remove some duplication 2010-12-29 21:41:04 +13:00
Paul Chote
fc6438e311 Use Filepaths instead of IFolders where possible. 2010-12-29 21:25:43 +13:00
Paul Chote
829fe6530a Start fixing the editor 2010-12-29 19:03:45 +13:00
Paul Chote
58797c0d37 packaging cleanup script. 2010-12-29 17:52:16 +13:00
Paul Chote
f6d9923305 Add SharpZipLib dep to INSTALL. 2010-12-29 11:51:29 +13:00
Paul Chote
c3ff679f3a Make map saving independent of Container type. Saving zip/oramap/mix untested as the editor cannot load non-folder maps. 2010-12-29 11:39:26 +13:00
Chris Forbes
fa36c71023 fix game failing to load compressed maps; convert 'a path beyond.' 2010-12-29 00:55:10 +13:00
Matthew
d4033f57bc Fix Makefile for Ubuntu. 2010-12-28 23:10:44 +13:00
Matthew Bowra-Dean
13f6a13ad9 Write maps to zip file from editor 2010-12-28 22:36:08 +13:00
Chris Forbes
44e668e804 choose a random map with MapStub.UseAsShellmap as the shellmap, rather than hardcoding a sha1 in mod.yaml; add editor support for the new flag too. 2010-12-28 19:13:56 +13:00
Chris Forbes
aecf19ed64 fix hash of RA shellmap 2010-12-28 19:04:33 +13:00
Chris Forbes
2a0c0bb991 remove unused Game.ConnectedToLobby event 2010-12-28 18:54:10 +13:00
Chris Forbes
99a0bd9609 remove legacy .uid junk 2010-12-28 18:53:15 +13:00
Chris Forbes
c20b3b90f4 dont use the .uid file hack -- compute them on demand 2010-12-28 18:52:19 +13:00
Chris Forbes
1cee570207 blah 2010-12-28 18:44:44 +13:00
Chris Forbes
382435e629 blah 2010-12-28 18:42:46 +13:00
Chris Forbes
637dbee32f remove support for loading from maps/ 2010-12-28 18:41:46 +13:00
Chris Forbes
81f6843791 bind .oramap -> ZipFile; search for .zip and .oramap in the map enumerator 2010-12-28 18:40:52 +13:00
Chris Forbes
cc6d445ef1 blah 2010-12-28 18:32:18 +13:00
Chris Forbes
cc2efdfa4a start reworking map enumerator 2010-12-28 18:27:40 +13:00
Chris Forbes
f7b34e1c5e #339 heli spawn offset is wrong fixed, and ReservableProduction folded back into Production 2010-12-28 18:27:00 +13:00
Chris Forbes
4d0f3b1554 #447 lock teams by default 2010-12-28 17:33:16 +13:00
Chris Forbes
ae1710896a add a tiny font; add labels in PerfGraphWidget 2010-12-28 17:24:20 +13:00
Chris Forbes
6425fc8a4b #268 fixed 2010-12-28 17:01:01 +13:00
Chris Forbes
38d267e439 fix sln file 2010-12-28 16:34:49 +13:00
Chris Forbes
95cf0bb827 fix bogus version subst. 2010-12-28 14:53:31 +13:00
Chris Forbes
d42bdfa102 show replays most recent first 2010-12-27 21:22:32 +13:00
Chris Forbes
5a7c62e24a fix bogus formatstring in ChooseReplayFilename() 2010-12-27 21:19:38 +13:00
Chris Forbes
29818ba60c remove dead RejoinLobby function 2010-12-27 21:10:58 +13:00
Chris Forbes
1c4f4b7886 removing some duplication 2010-12-27 21:03:51 +13:00
Chris Forbes
e127095437 remove some dumb state-tracking from OreRefinery 2010-12-27 20:03:19 +13:00
Chris Forbes
d8eaa7c841 shuffle exits 2010-12-27 19:43:32 +13:00
Chris Forbes
888fe35f08 make repath much less aggressive while attacking, to fix perf 2010-12-27 19:17:02 +13:00
Chris Forbes
59fdbe8725 CanTargetUnit -> CanTargetUnit 2010-12-27 18:43:32 +13:00
Chris Forbes
24a5b3ba03 simplification 2010-12-27 18:42:28 +13:00
Chris Forbes
9d768fa1c1 move some MobileInfo-related bits onto MobileInfo 2010-12-27 18:41:07 +13:00
Chris Forbes
31b98c0eb4 fix misleading name 2010-12-27 18:36:06 +13:00
Chris Forbes
3dd52a59c9 work around a verifier limitation 2010-12-27 18:30:24 +13:00
Chris Forbes
f3997ba3bd blah 2010-12-27 18:26:13 +13:00
Chris Forbes
4a94cf656b remove a redundant method from queries. 2010-12-27 18:26:12 +13:00
Chris Forbes
439bb7d02f multiplying by 0 makes the world hard to sync 2010-12-27 18:26:11 +13:00
Chris Forbes
9ad23b10f0 fix chronoshift being hard to cancel 2010-12-27 18:26:11 +13:00
Chris Forbes
e2a0134c5b not java. 2010-12-27 18:26:10 +13:00
Chris Forbes
c6f1740875 add a note for later 2010-12-27 18:26:09 +13:00
Chris Forbes
50834911fe don't disable everyone's shroud when someone's GPS goes up 2010-12-27 18:26:08 +13:00
Chris Forbes
2cce1ce23c fix warnings, and bogosity in projectfiles 2010-12-27 18:26:07 +13:00
Chris Forbes
3d47584cd8 use bidi pathing for moving into range (MoveToAdjacent-style hack) 2010-12-27 15:33:59 +13:00
Chris Forbes
3ce055da80 fix cnc mod script the same way 2010-12-24 14:13:12 +13:00
Chris Forbes
51d3743b18 fix ra mod script 2010-12-24 14:12:06 +13:00
Chris Forbes
ce609195cd make kicking actually work 2010-12-24 12:31:37 +13:00
Chris Forbes
54cf2e7993 add kick command to LobbyCommands 2010-12-24 12:31:36 +13:00
Paul Chote
b5b6b47e95 Implement metadata and httpRequest in the windows launcher. Untested. 2010-12-24 12:13:28 +13:00
Paul Chote
6ff0e41650 Remove fp from Aircraft. 2010-12-24 12:01:39 +13:00
Paul Chote
fcdb3b536d Latest version and MOTD in osx launcher. 2010-12-24 11:41:35 +13:00
Paul Chote
14ad5099a0 Show the mod version in the launcher 2010-12-24 11:41:35 +13:00
Paul Chote
dc3bf2515a Remove VERSION file, and version / motd display from the ingame menu. Write git-version into the individual mod versions. 2010-12-24 11:41:35 +13:00
Paul Chote
275dfc43be New launch mechanism: removes wrapper app bundle, and supports paths with spaces. 2010-12-24 11:41:34 +13:00
Chris Forbes
3149f3efa2 fix up some of the capturing duplication 2010-12-23 14:25:39 +13:00
Chris Forbes
e8a85db309 squash some warnings 2010-12-23 08:50:07 +13:00
Chris Forbes
c1fb6c2732 remove ability to not save syncreports 2010-12-23 08:48:54 +13:00
Chris Forbes
68e8565561 reduce size of attack forces to reduce base blockages 2010-12-23 08:42:45 +13:00
Chris Forbes
92e6570f50 fix a crash, add a normal bot (harder) 2010-12-23 08:42:45 +13:00
Chris Forbes
e94e21fd32 add name to cnc bot too 2010-12-23 08:42:44 +13:00
Chris Forbes
d320a689a2 wire up bot creation properly in CreateMPPlayers etc 2010-12-23 08:42:44 +13:00
Chris Forbes
29fbeb2c5d add enumeration of bots 2010-12-23 08:42:43 +13:00
Paul Chote
7ef884532d Fix osx launcher crash when there is a space in the launcher path. Launching the game still doesn't work in this case. 2010-12-22 20:35:43 +13:00
Paul Chote
54c49dfa15 OS X launcher: Create download directory if it doesn't exist. 2010-12-21 21:29:50 +13:00
Chris Forbes
8809cbb4f1 blah 2010-12-21 18:00:42 +13:00
Chris Forbes
112dd3b1f6 remove some random crap 2010-12-21 17:59:41 +13:00
Chris Forbes
92b0f77867 #381 fixed (thanks, [Arcturus]) 2010-12-20 20:00:41 +13:00
Chris Forbes
dcec748911 fix #436 bridges in wrong place in render sequence 2010-12-20 19:43:25 +13:00
Chris Forbes
7d61e75862 #413 fixed 2010-12-20 19:38:28 +13:00
Chris Forbes
2d2bb58054 fix #451 2010-12-20 19:32:00 +13:00
Chris Forbes
bd0b3edccb fix AI jamming up its base by enforcing 1-cell gaps 2010-12-20 19:19:54 +13:00
Chris Forbes
d66439aa0c fix cnc rules bug so it loads 2010-12-20 17:36:29 +13:00
Chris Forbes
c85dbfb53d fix dumb bug in replay viewer 2010-12-19 20:49:14 +13:00
Chris Forbes
d6c71c6618 fix crash in RA music dialog 2010-12-19 19:14:00 +13:00
Chris Forbes
7802931e54 SAM requires power to operate 2010-12-19 18:51:14 +13:00
Chris Forbes
14737cc1dc nerf 1tnk pretty hard; add more hp for 2tnk but increase price slightly 2010-12-19 18:48:51 +13:00
Matthew Bowra-Dean
d8d33811e4 Added minimize button to launcher. 2010-12-19 18:41:36 +13:00
Chris Forbes
c99f89c987 fix crash on server overfill, fix another problem preventing spec slots from autofilling 2010-12-19 18:40:10 +13:00
Chris Forbes
7c76b25a44 blah 2010-12-19 18:40:09 +13:00
Chris Forbes
4fdc8222e8 blah 2010-12-19 18:40:09 +13:00
Chris Forbes
07d2e54bcc fix another crash in replay browser 2010-12-19 17:48:53 +13:00
Chris Forbes
f3d0e4b8ed fix a crash in the replay browser 2010-12-19 17:48:53 +13:00
Chris Forbes
2fad6f3bf1 move replay viewer delegate into mod 2010-12-19 17:48:52 +13:00
Chris Forbes
9482955a83 blah, cleanup 2010-12-19 17:48:51 +13:00
Chris Forbes
9d75c8d820 fix breakage 2010-12-19 17:48:51 +13:00
Chris Forbes
e3925b752d add support for replay viewer to cnc 2010-12-19 17:48:50 +13:00
Chris Forbes
f990006587 hack around the local player being set in replays 2010-12-19 17:48:50 +13:00
Chris Forbes
0b7bee480c extract [final] lobbyinfo from replay order stream; show map name & preview in replay browser 2010-12-19 17:48:49 +13:00
Chris Forbes
05f4aeea9f show duration in the replay browser 2010-12-19 17:48:49 +13:00
Chris Forbes
5f37b9e7d2 fix crash in replay playback (no world) 2010-12-19 17:48:48 +13:00
Chris Forbes
734b464de3 wire up replay browser to actually start a game. doesnt work. 2010-12-19 17:48:48 +13:00
Chris Forbes
4206cf1b09 refactor game joining; add replay joining support 2010-12-19 17:48:47 +13:00
Chris Forbes
17e3ef131c actually populate the replay browser; fix listbox ContentHeight not being reset. 2010-12-19 17:48:47 +13:00
Chris Forbes
2c13ebc6e7 wire cancel button for replay viewer 2010-12-19 17:48:46 +13:00
Chris Forbes
4f3b16cab2 add non-functional replay browser 2010-12-19 17:48:46 +13:00
Chris Forbes
25ebdea758 hack in stop order support to various classes. not happy with this. 2010-12-19 17:48:18 +13:00
Paul Chote
8b82df8298 Remove broken powered-techtree hack. 2010-12-07 22:35:40 +13:00
Paul Chote
0298a9e3a9 Remove debug logging from ChronoshiftPower. 2010-12-07 22:27:16 +13:00
Paul Chote
f2f60fb1f7 Don't apply palette effects to shroud/fog. 2010-12-07 22:26:27 +13:00
Paul Chote
b07eb9b8a1 Fast charge devhack. 2010-12-07 22:21:52 +13:00
Paul Chote
f5bffc4da9 Restore sane timings. 2010-12-07 22:19:58 +13:00
Paul Chote
55d60bd466 Don't crash if two powers have the same icon. 2010-12-07 22:00:26 +13:00
Paul Chote
c2a945b7ed Fix Spy infiltration. 2010-12-07 22:00:26 +13:00
Paul Chote
48b7cdad44 InfiltrateForSupportPower / Sonar pulse. 2010-12-07 22:00:20 +13:00
Paul Chote
c7500084df Parabomb crates. Multiple can be collected and queued. Support uncharged powers (0 charge time) with appropriate tooltip. 2010-12-07 21:50:33 +13:00
Paul Chote
d1850e8b4b Fix a time format bug. Fix subsequent gps bug. 2010-12-07 21:49:33 +13:00
Paul Chote
c465a58976 Sonar Pulse power. It still doesn't do anything. 2010-12-07 21:49:26 +13:00
Paul Chote
6b05b2c2f0 Iron Curtain. 2010-12-07 21:45:04 +13:00
Paul Chote
cd10fb1db0 GPS Satellite. 2010-12-07 21:45:04 +13:00
Paul Chote
172e1eb295 Paratroopers, Spyplane. 2010-12-07 21:45:04 +13:00
Paul Chote
9e16eb513f Reimplemented chronoshift. (still has desync) 2010-12-07 21:45:04 +13:00
Paul Chote
24b322053c Fix ra shellmap; reimplement ra nuke. 2010-12-07 21:45:04 +13:00
Paul Chote
e52771c367 Reimplement Ion Cannon and cnc nuke. Disable ra shellmap nukes. 2010-12-07 21:45:04 +13:00
Paul Chote
76f792bfdf New special powers mechanism. Only cnc Airstrike has been reimplemented so far. Special power crates, and spy bonuses have also been disabled. 2010-12-07 21:45:03 +13:00
Paul Chote
c6fad7fe98 Render IPreRenderSelection independently of OG. 2010-12-07 21:45:03 +13:00
Paul Chote
915cb589b3 Fix some more special power exploits 2010-12-07 21:45:03 +13:00
Chris Forbes
664692cef9 #398 c4 vs friendly buildings goes through the motions, but does nothing 2010-12-06 20:46:44 +13:00
Chris Forbes
220579ff85 wire 's' (default binding) to issue 'Stop' order to each selected actor 2010-12-06 20:43:09 +13:00
Chris Forbes
1a8e964c04 clean up usings 2010-12-06 14:35:37 +13:00
Chris Forbes
3a309ec916 remap hotkeys 's' -> 'y' in prep for adding 'stop' order 2010-12-05 12:29:11 +13:00
Chris Forbes
d46c64fad5 blah 2010-12-05 12:24:11 +13:00
Chris Forbes
3f47715c36 harvesters show colors for each resource type 2010-12-05 12:10:52 +13:00
Chris Forbes
94715a1561 add AutoTargetIgnore to ^Wall in ra and cnc 2010-12-05 11:41:14 +13:00
Chris Forbes
a752c47b5a allow marking things with AutoTargetIgnore so AutoTarget won't go for them 2010-12-05 11:39:44 +13:00
Chris Forbes
4d0535daa9 fix exploit in sonar pulse power 2010-12-05 11:36:05 +13:00
Chris Forbes
a3e64d1733 add AutoTargetIgnore 2010-12-05 11:32:30 +13:00
Chris Forbes
2618a7dadc fix perf of floodfill in editor 2010-12-05 11:31:24 +13:00
Chris Forbes
5617465294 remove sync attribute from DisplayCash/DisplayOre 2010-12-04 11:14:40 +13:00
Chris Forbes
9c20fba4a0 fix spy crashing things when disguised as a unit with fewer idle anims 2010-12-04 11:02:53 +13:00
Chris Forbes
05718f9e8e #400 bogus pip color for e7 fixed 2010-12-04 10:36:01 +13:00
Chris Forbes
81dad0bd34 tidying 2010-12-04 10:35:34 +13:00
Chris Forbes
c177cf9f9a #401 bogus footprint for ATWR fixed 2010-12-03 20:49:43 +13:00
Chris Forbes
e1761d8969 cleanup some usings 2010-12-03 20:43:27 +13:00
Paul Chote
0ae464d1f7 New attack-move cursor for cnc. 2010-12-02 10:28:34 +13:00
Paul Chote
4913d82bce Autotarget sets target line 2010-12-01 21:14:10 +13:00
Paul Chote
4f6027e772 Add Autotarget to cnc helis. 2010-12-01 21:03:41 +13:00
Paul Chote
fa84cfb26e Rebalance Invulnerability and Chronoshift. 2010-12-01 18:43:12 +13:00
Paul Chote
971287e989 Fix shroud crash 2010-12-01 18:22:46 +13:00
Paul Chote
deed6c7267 Make LST unbuildable; it is completely broken. 2010-12-01 13:19:56 +13:00
Paul Chote
f58f460355 Fix copypasta bogosity that mono accepts as valid code. 2010-12-01 13:19:09 +13:00
Paul Chote
2c897d4454 Fix ra shellmap low power and broken GAP position 2010-11-30 23:16:40 +13:00
Paul Chote
b4101c03ee MSLO requires power and can be powered down. 2010-11-30 23:13:51 +13:00
Paul Chote
200e90a590 Right click cancel chronoshift targeting. 2010-11-30 23:02:45 +13:00
Paul Chote
be8f042e49 Fix autoattack target flashes 2010-11-30 22:53:11 +13:00
Paul Chote
4b1eb993e4 Swap map selector button order 2010-11-30 22:30:18 +13:00
Paul Chote
f6ce673345 Fix KOTH maps 2010-11-30 22:28:28 +13:00
Paul Chote
08eeec4d99 More lobby polish (mainly map chooser). 2010-11-30 21:20:57 +13:00
Matthew Bowra-Dean
564a4598b9 Added renderer selection to Windows launcher. 2010-11-30 19:08:34 +13:00
Matthew Bowra-Dean
7e25b6e58e Moved map description to bottom of labels. 2010-11-30 19:08:24 +13:00
Matthew Bowra-Dean
57f74606f0 Added author and description to map chooser, fixes #290. Added word wrap to the LabelWidget to support it. 2010-11-30 19:08:18 +13:00
Paul Chote
b44cb9ad57 Pulse the rally point circles when a new location is set. 2010-11-30 19:07:41 +13:00
Paul Chote
dfd5906d7f Refactor AutoHeal. 2010-11-30 14:20:15 +13:00
Paul Chote
2e7b5e8712 Fix moonwalking infantry 2010-11-30 14:17:39 +13:00
Paul Chote
eb8682fd0e Fix AutoHeal 2010-11-30 13:37:10 +13:00
Paul Chote
2d224a207c Fix idle animations / prone. 2010-11-30 12:51:25 +13:00
Paul Chote
5070a81db4 Move CancelableActivity into the Activities namespace. Remove the Idle activity. 2010-11-30 11:11:14 +13:00
Paul Chote
e97dd2ee47 make currentActivity private. 2010-11-29 13:47:50 +13:00
Paul Chote
da74c6ad23 Add some logging to see what is going on. 2010-11-29 13:43:00 +13:00
Paul Chote
c7f1d08748 Some thoughts towards improving our bogus idle handling. Untested. 2010-11-29 13:15:44 +13:00
Paul Chote
7850acc6fb Fix AttackLeap. 2010-11-29 11:52:27 +13:00
Matthew Bowra-Dean
ec5b9a1150 Select last mod at start of launcher. Don't run download action elevated. 2010-11-28 23:12:19 +13:00
Matthew Bowra-Dean
83f67a9d48 Revert Window installer to not having launcher as default. 2010-11-28 23:12:18 +13:00
Paul Chote
fb799ad436 Fix dropdown miscompile bug under mono 2.6.7. 2010-11-28 22:23:50 +13:00
Paul Chote
60186efca6 Change rpm deps to target fedora. 2010-11-28 15:35:07 +13:00
Paul Chote
20ab3b6caa Fix observers in cnc. 2010-11-28 15:26:34 +13:00
Paul Chote
32db66eb7e Normalize ra/cnc chrome yaml 2010-11-28 15:24:31 +13:00
Paul Chote
112844a9f7 Normalize lineendings. 2010-11-28 15:14:31 +13:00
Paul Chote
745df591e0 Hide the join slot buttons when ready. 2010-11-28 15:11:57 +13:00
Paul Chote
9c7759d131 More polish. 2010-11-28 15:09:25 +13:00
Paul Chote
4bb70f11e9 Tweak header positioning and scrollpanel scissoring (don't draw contents over the 1px border). 2010-11-28 13:53:38 +13:00
Paul Chote
ce5ca9dbca Color selector as a drop panel. 2010-11-28 13:44:53 +13:00
Paul Chote
0b9a984b7a Team dropdown. 2010-11-28 12:00:14 +13:00
Paul Chote
45cd6caeec Faction dropdown flags. 2010-11-28 11:46:14 +13:00
Paul Chote
4c517c0e59 Initial lobby rework progress 2010-11-28 11:25:42 +13:00
Paul Chote
7884cb310b Polish: Offset button children by pressed state. 2010-11-28 11:18:03 +13:00
Paul Chote
306bece709 Tweak ra lobby scrollpanel margins. 2010-11-28 10:41:41 +13:00
Paul Chote
748a055a24 Disable FrozenUnderFog for this release. 2010-11-28 10:29:05 +13:00
Paul Chote
240b26a265 Remove bogus WorldGameOver trait. 2010-11-28 09:54:29 +13:00
Paul Chote
ac82121460 Fix diplomacy stance cycling exploit. 2010-11-28 09:42:37 +13:00
Matthew Bowra-Dean
3189a4f457 Give sensible default range to CarpetBomb and make sure its target location is in the correct units. 2010-11-28 01:45:24 +13:00
Paul Chote
291e7588e1 Workaround for persistent dropdowns. 2010-11-27 23:55:09 +13:00
Matthew Bowra-Dean
b8e274e0f9 Revert misguided attempt at allowing preservation of user installed maps. 2010-11-27 23:25:34 +13:00
Paul Chote
e81a1f78a4 Fix visibility that mono 2.8 happily ignores. 2010-11-27 22:39:50 +13:00
Matthew Bowra-Dean
51c3455ffe Linux post install scripts brought up to date with Utility app syntax changes. 2010-11-27 22:19:40 +13:00
Matthew Bowra-Dean
583fa0aa39 Made PipeAccessRights explicit to get around Mono fail. 2010-11-27 18:54:43 +13:00
Matthew Bowra-Dean
f768f8d969 Include SharpZipLib in Windows installer. 2010-11-27 18:54:42 +13:00
Matthew Bowra-Dean
0e26f0ce26 Updated packaging scripts for winlauncher. 2010-11-27 18:54:42 +13:00
Matthew Bowra-Dean
2a8beca0f8 Updated Windows installer for launcher. 2010-11-27 18:54:42 +13:00
Matthew Bowra-Dean
b5813ebff8 Update Makefile for Winlauncher 2010-11-27 18:54:42 +13:00
Matthew Bowra-Dean
0f6f36411a Fix cnc & ra mod page layout on Windows. 2010-11-27 18:54:42 +13:00
Paul Chote
f798639125 New loadscreen artwork for cnc; needs texturing. 2010-11-27 18:54:28 +13:00
Paul Chote
6014095ab3 Untextured GDI and Nod logos. 2010-11-27 17:16:37 +13:00
Paul Chote
52e265557c Oil Derricks spurt fire when dead. 2010-11-27 15:50:46 +13:00
Paul Chote
f9f9fbf3e4 Reinit the sheetbuilder too - appending more sprites to the old sheets isn't the best of ideas. Fixes "Terrain sprites span multiple sheets" on cnc tundra map. 2010-11-27 15:11:38 +13:00
Paul Chote
d559b5cdb7 Rallypoint Polish: Improved artwork, correct positioning, doesn't disappear when the building is offscreen, targeting cursor. 2010-11-27 14:54:29 +13:00
Paul Chote
d6733e62d6 Extra sounds extracted from the c&c demo. 2010-11-27 14:08:31 +13:00
Paul Chote
00a0aac7a3 Scale is now set via a field on Render* and interacts properly with chronoshift and building previews. 2010-11-27 13:30:08 +13:00
Paul Chote
840ade5b78 Remove LineBuild preview (no preview is better than broken preview). 2010-11-27 13:18:06 +13:00
geckosoft
13d3137ae4 Fixed: Issue #376 : Captured Refineries cannot receive Ore + harv not unlinked 2010-11-27 11:28:22 +13:00
Paul Chote
62c652a645 Fix a fog information leak introduced by 8d8c6c67. 2010-11-27 11:28:22 +13:00
Paul Chote
76428cbda2 Move ShroudRenderer into Graphics. 2010-11-27 11:28:22 +13:00
Paul Chote
434ea26950 Fix cloaked units. 2010-11-27 11:28:22 +13:00
Paul Chote
9655b34e5f Fix FrozenUnderFog; add to cnc. 2010-11-27 11:28:22 +13:00
Paul Chote
e91caa4e7a Save some perf. 2010-11-27 11:28:22 +13:00
Paul Chote
3b0810a096 Simply the localplayer hack, and prevent vis dirtying when shroud is disabled. 2010-11-27 11:28:17 +13:00
Paul Chote
1d81e71bcb Allow vis to extend outside the map, but not explored. 2010-11-27 11:20:04 +13:00
Paul Chote
29ac9a594a Add a hack to support our old "no player means total vis" behavior. 2010-11-27 11:20:04 +13:00
Paul Chote
fb0e399ab9 Consolidate viewport clip calculations into one place (except for TerrainRenderer, but changing that calculation crashes my gfx card). 2010-11-27 11:20:04 +13:00
Paul Chote
7c5c989eb2 Introduce World.LocalShroud. Breaks targeting stealth tanks. Probably breaks FrozenUnderFog. 2010-11-27 11:20:04 +13:00
Paul Chote
41fd19c766 Begin refactoring Shroud. ShroudRenderer is now internal to WorldRenderer; all traits interact with Shroud directly. Gives soft-edges at the map border for free, but breaks shellmap and observers. 2010-11-27 11:20:03 +13:00
Paul Chote
b423889c06 Remove a pile of duplication from target lines.
Remove MoveFlash.
2010-11-27 11:20:03 +13:00
Paul Chote
5f43923b80 Polish: Show the "move-blocked" cursor for locations outside the map. Clamp move orders to the map bounds for these orders. 2010-11-27 11:20:03 +13:00
Paul Chote
5470264f00 Show move-blocked cursor if we can know the unit can't move there. 2010-11-27 11:20:03 +13:00
Paul Chote
06ed722b7a Render healthbars / target lines / minefield grids *above* shroud. 2010-11-27 11:20:02 +13:00
Paul Chote
8565b7be0c Always render actor selection boxes. 2010-11-27 11:20:02 +13:00
Paul Chote
a3861823c9 Fix scissoring for LocalPlayer != null. 2010-11-27 11:20:02 +13:00
Paul Chote
84fd45ad69 Scissor to map edge. 2010-11-27 11:20:02 +13:00
Paul Chote
dd6a431af2 Start scripting the cnc shellmap. 2010-11-27 11:20:02 +13:00
Paul Chote
fa31fb199f Setup factions on cnc shellmap 2010-11-27 11:20:02 +13:00
Paul Chote
fbeb638582 Center the viewport by default. 2010-11-27 11:20:01 +13:00
Paul Chote
1aebd59062 Fix some compiler warnings 2010-11-27 11:20:01 +13:00
Paul Chote
7182908728 Rename ListBoxWidget -> ScrollPanelWidget. 2010-11-27 11:20:01 +13:00
Paul Chote
58a92de5a1 Move widget delegates into Mods. 2010-11-27 11:20:01 +13:00
Paul Chote
4ea04f461a Fix license info. 2010-11-27 11:19:39 +13:00
Paul Chote
26c084cfb8 Update makefile. 2010-11-27 11:17:00 +13:00
Matthew Bowra-Dean
ac513557a1 Removed old code, made installing mods work. 2010-11-26 01:01:12 +13:00
Matthew Bowra-Dean
db5b5698a7 Implemented remaining JS bridge functions for Win launcher. 2010-11-26 00:47:22 +13:00
Paul Chote
1f61d22489 RA package download/install (copied from cnc) 2010-11-25 22:51:30 +13:00
Paul Chote
520f602f23 Disable some currently unimplemented bits (to be re-enabled later). 2010-11-25 22:51:30 +13:00
Paul Chote
8c5c63a4b5 Use the launcher in osx packaged builds. Leopard support. Fix some wording. Remove old osx launcher project. 2010-11-25 22:51:29 +13:00
Paul Chote
a0741ba26b Set the game path to the launcher resource dir. Can be overwritten using the system defaults mechanism. 2010-11-25 22:51:29 +13:00
Paul Chote
9f21d944d1 Gl renderer is now default, don't need to override it. 2010-11-25 22:51:28 +13:00
Paul Chote
10f9e3e787 Zip extraction support. 2010-11-25 22:51:28 +13:00
Paul Chote
eff5e409c0 More utility tweaks 2010-11-25 22:51:28 +13:00
Paul Chote
f108735f74 Keep the bs inside the launcher 2010-11-25 22:51:28 +13:00
Paul Chote
e62149398b Clean up after failed extraction. 2010-11-25 22:51:28 +13:00
Paul Chote
d6e831eb07 Utility changes to support extracting a zip relative to a mod. Can also be used to install new mods. 2010-11-25 22:51:28 +13:00
Paul Chote
dcf3912d24 Add mono version check 2010-11-25 22:51:28 +13:00
Paul Chote
efad699d4b Prompt user when quitting with active downloads. Remove js debug logging. 2010-11-25 22:51:28 +13:00
Paul Chote
77a35fd132 Close the app when the main window is closed. Terminate all in progress downloads when the app is closed. 2010-11-25 22:51:28 +13:00
Paul Chote
2fe7e10750 Handle download errors 2010-11-25 22:51:27 +13:00
Paul Chote
6f66a19b18 Clean up file downloading. 2010-11-25 22:51:27 +13:00
Paul Chote
2fc88e439d Progress towards in-launcher download ui. Works, but is very fragile. 2010-11-25 22:51:27 +13:00
Paul Chote
b4b05c3f4e Notify javascript when download status changes. Allow js to query information about a download. 2010-11-25 22:51:27 +13:00
Paul Chote
0ee1d39bac Refactor download mechanism to allow multiple concurrent downloads. Allow downloads to be cancelled. Allow js to query if files exist in the cache. Fix some compiler warnings. 2010-11-25 22:51:27 +13:00
Paul Chote
c3521a2490 Expose the package downloading to js. Todo: cancel support, status callbacks. 2010-11-25 22:51:27 +13:00
Paul Chote
cb93955cc5 Generalize package downloading to support arbitrary urls and download locations. 2010-11-25 22:51:27 +13:00
Matthew Bowra-Dean
666efc94d1 Bring Makefile up to date with Win launcher changes. 2010-11-25 22:51:27 +13:00
Matthew Bowra-Dean
d2a52fd529 Bring Windows launcher into line with pchote's ideas. 2010-11-25 22:51:26 +13:00
Paul Chote
085685a769 Use ~/Library/Application Support/OpenRA/ as the support dir. 2010-11-25 22:51:26 +13:00
Paul Chote
034196ddd6 Build a list of parent mods before launching. 2010-11-25 22:51:26 +13:00
Paul Chote
3dc16bdbb4 Support launching an arbitrary mod. Hook up package detection for cnc. 2010-11-25 22:51:26 +13:00
Paul Chote
f42f39f9c9 Refactor JSBridge to simplify adding new methods. Add log(message) and a stub for fileExistsInMod(file,mod). 2010-11-25 22:51:26 +13:00
Paul Chote
40235db52e Bind the js bridge properly. Display the selected mod page on load. 2010-11-25 22:51:25 +13:00
Paul Chote
810b73e1f0 Fix encoding issue with OpenRA.Utility. Refactor SidebarEntry. Add launcher pages to all mods. 2010-11-25 22:51:25 +13:00
Paul Chote
82850cf4fb Use window.external instead of Launcher in js for windows support. Tweak the OpenRA.Utility calls - still doesn't work 100%. 2010-11-25 22:51:25 +13:00
Paul Chote
21e597ca2d Hook up the "Play" button to launch the game. 2010-11-25 22:51:25 +13:00
Paul Chote
ed8203c896 Load mod.html into the right pane when clicked. Refactoring. 2010-11-25 22:51:25 +13:00
Paul Chote
de7668e8ff Add a WebView in preparation for the page info. Refactor SidebarEntry out of Mod. Add an "Other" category with links for support/credits+legal. 2010-11-25 22:51:25 +13:00
Paul Chote
7271dd5248 List installed mods in the sidebar. Changes utility mod info syntax. 2010-11-25 22:51:24 +13:00
Paul Chote
16dd07bab3 Add support for launching the game. 2010-11-25 22:51:24 +13:00
Paul Chote
5cbfc45819 Beginnings of the new mac launcher. 2010-11-25 22:51:24 +13:00
Chris Forbes
6a238ab51a open/closed/bot dropdown for cnc lobby too 2010-11-25 20:04:56 +13:00
Chris Forbes
4d9c2a30df Dropdown listboxes 2010-11-25 20:04:56 +13:00
Chris Forbes
8b18927c67 #378 crash in IdleHealActivity fixed 2010-11-25 19:48:28 +13:00
Chris Forbes
d77563bdb0 reduce coverage of UiOverlay sprites so you can see the building you're placing 2010-11-24 20:10:14 +13:00
Paul Chote
d0466714c8 Allow Chronoshifted/paradropped units to pick up crates, etc. 2010-11-24 15:55:41 +13:00
Paul Chote
08c9c1a92f Make Iron Curtain targeting consistent with Chronoshift. 2010-11-24 15:49:52 +13:00
Paul Chote
ea3943daf4 Do the same for chronoshifted units 2010-11-24 15:45:47 +13:00
Paul Chote
6ac92c45f1 Cache the sprites. Draw linebuild cells too. 2010-11-24 15:31:29 +13:00
Paul Chote
96cd0e2259 Render building previews 2010-11-24 13:43:07 +13:00
Paul Chote
fc5830a687 Added int2.Clamp(Rectangle). All queries for map geometry use map.Bounds. 2010-11-24 12:24:48 +13:00
Paul Chote
1dfe437641 Refactor Viewport. 2010-11-24 11:57:18 +13:00
Paul Chote
b8eda5a152 Tidy more uses of BottomRight/TopLeft, bogus location of FormatTime. 2010-11-24 11:37:18 +13:00
Paul Chote
de8603832f Use Map.Bounds instead. 2010-11-24 11:12:37 +13:00
Paul Chote
f11bcd27cc Kill Map.XOffset / Map.YOffset. 2010-11-24 10:26:38 +13:00
Paul Chote
00dc91cf49 Standardise Theater -> Tileset. 2010-11-24 10:09:51 +13:00
Paul Chote
8b0255e2f7 Fix the RA shellmap. 2010-11-23 22:53:14 +13:00
Paul Chote
3a2279f378 Set cursor position based on mouse click location. 2010-11-23 21:39:34 +13:00
geckosoft
8085bcb232 Textfield cursor support and forward-delete (rewritten by pchote). 2010-11-23 21:39:34 +13:00
Chris Forbes
5e6f325df1 #377 fixed 2010-11-23 21:39:34 +13:00
Chris Forbes
f892eb629e fix exploitability of nuke and ion cannon 2010-11-23 21:39:34 +13:00
Chris Forbes
1629958970 remove bogus sandbag-in-water on equal-opportunity 2010-11-23 21:39:34 +13:00
Chris Forbes
2079627030 fix APB spawn 2010-11-23 21:39:34 +13:00
Paul Chote
2072b78489 Remove duplication from PasswordFieldWidget. 2010-11-23 21:39:34 +13:00
Paul Chote
3d1d4a1aff AOE Chronosphere 2010-11-23 21:39:31 +13:00
Paul Chote
41665f7e95 AOE Iron Curtain 2010-11-23 21:38:28 +13:00
geckosoft
604aae5980 Fixed: #281 for regular (read: right-click) commands (Modified by pchote) 2010-11-23 15:59:05 +13:00
geckosoft
ac613f7bea Fixed: #334 Flares should now be destroyed if the drop plane is destroyed 2010-11-23 15:59:05 +13:00
geckosoft
46d0a6d00d Fixed: Potential exploit with ChronoshiftPower 2010-11-23 15:59:05 +13:00
geckosoft
402afc82ca Fixed: Potential exploit on Iron Curtain 2010-11-23 15:59:04 +13:00
geckosoft
1cd59a0892 Fixed: Iron Curtainable doesnt stack 'InvulnEffect' effects anymore 2010-11-23 15:59:04 +13:00
geckosoft
7b7bcf1005 Fixed: Crash when selling iron curtained' buildings 2010-11-23 15:59:04 +13:00
geckosoft
be701007df Changed: DrawRangeCircle now accepts a float instead of an int 2010-11-23 15:59:04 +13:00
geckosoft
fef6285436 Fixed: issue #277 (Surrender button no longer visible when won or lost) 2010-11-23 15:59:04 +13:00
Matthew Bowra-Dean
b3c4afa620 Bring Makefile up to date. 2010-11-23 15:59:04 +13:00
Paul Chote
8df1813afd Rework the makefile. 2010-11-23 15:59:04 +13:00
Paul Chote
6a28bcb49a GL Renderer: Print available extensions on error and test for vbos. 2010-11-23 15:59:04 +13:00
Chris Forbes
730ed8c597 finished removing ctors from Order 2010-11-23 15:33:15 +13:00
Chris Forbes
7b5be4a0ec remove more ctors 2010-11-23 15:30:21 +13:00
Chris Forbes
30fb1250b3 remove some stupid duplication in HackyAI 2010-11-23 15:27:27 +13:00
Chris Forbes
a363bf841c remove some dead code 2010-11-23 15:25:10 +13:00
Chris Forbes
da5830845b remove another ctor 2010-11-23 15:24:45 +13:00
Chris Forbes
23e6eada26 another ctor removed 2010-11-23 15:20:11 +13:00
Chris Forbes
490b0801a0 start removing weird ctors on Order 2010-11-23 15:14:48 +13:00
Chris Forbes
49ab704a84 add ctor & readonlys for required args 2010-11-23 14:04:39 +13:00
Chris Forbes
4a12b78f14 experiment -- _Order is a mutable builder-object for Order, implicitly convertible 2010-11-23 13:59:43 +13:00
Chris Forbes
656dbdcd28 add Order.ExtraLocation as a second int2 parameter 2010-11-23 13:56:04 +13:00
Chris Forbes
88398afba6 symmetry between reading and writing int2 2010-11-23 13:06:37 +13:00
Chris Forbes
2f74207bf6 tighten order encoding 2010-11-23 12:58:59 +13:00
Chris Forbes
f4f9abe4d4 import 'A Path Beyond' from original RA 2010-11-22 08:21:22 +13:00
Matthew Bowra-Dean
e50b8ec7dc Added Gecko to AUTHORS 2010-11-21 23:11:22 +13:00
Chris Forbes
70f92494b2 fixed player setup for koth-crossroads 2010-11-21 22:10:43 +13:00
Matthew Bowra-Dean
c07fee3b3b More fixes for upload scripts. 2010-11-21 20:25:50 +13:00
Matthew Bowra-Dean
07b635672e Fix upload-all.sh subscript calling. 2010-11-21 20:07:48 +13:00
Matthew Bowra-Dean
edc4c7ab2b +x on upload-all.sh 2010-11-21 19:59:57 +13:00
Matthew Bowra-Dean
6edcc36f17 Fixed upload scripts. 2010-11-21 19:51:50 +13:00
Matthew Bowra-Dean
3a2a6c231e checkout-and-build script updated. 2010-11-21 18:28:30 +13:00
Chris Forbes
cf26e4aa8a improve appearance of smoketrails 2010-11-21 18:28:29 +13:00
Paul Chote
8ca1da8828 Remove Cg dep from linux packages 2010-11-21 13:30:48 +13:00
Paul Chote
5764bc1c1c Tweak the packaging scripts. Add a starting point for the uploader. 2010-11-21 13:10:22 +13:00
Paul Chote
dba7335594 Fix a pile of compiler warnings. 2010-11-21 13:10:22 +13:00
Paul Chote
1461309dba Use the Gl renderer by default on all platforms. 2010-11-21 13:10:22 +13:00
Paul Chote
d7e8388600 Make our IFolder zip support actually work. 2010-11-21 13:10:22 +13:00
Paul Chote
e79d039aa0 Add an install from cd option for cnc. Remove music install options. 2010-11-21 13:10:21 +13:00
Paul Chote
3d8b3efb9e Don't die when installing over an existing set of packages 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
58367fdeac Fixed a case where package downloading erroring out will hang the Utility app. 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
63d54952d0 Downloading packages now shows progress to the user. Utility app no longer immediately exits after downloading packages. 2010-11-21 13:10:21 +13:00
Paul Chote
5904563653 Fix packaging scripts (OpenRA.Utility wasn't built, and SharpZipLib wasn't included). 2010-11-21 13:10:21 +13:00
Paul Chote
5d0b750a64 Hack to allow temp download dir to be specified relative to home dir. 2010-11-21 13:10:21 +13:00
Paul Chote
43e99631a8 Build all renderers on make game 2010-11-21 13:10:21 +13:00
Paul Chote
8cd6d60839 Rewrite the download status over the same console line. May break the windows launcher (which doesn't run under osx, so can't test). 2010-11-21 13:10:21 +13:00
Paul Chote
047d012fff Fix broken dependencies in the Makefile. 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
0064543989 Allow building of Winforms launcher with Mono 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
b61b7b5431 Only modify pipe ACL when running as admin 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
0c319e88c3 Utility now uses named pipe if passed --pipe. Installing mods now works properly too. 2010-11-21 13:10:21 +13:00
Matthew Bowra-Dean
da384af339 Refactoring of OpenRA.Utility. Whole lot of work on OpenRA.Launcher
Mod configuration dialog now fully functional, launch button also works.
2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
f98f3d0b39 Mod tree in configure mods dialog. 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
439c366ba2 Winforms launcher beginnings. 2010-11-21 13:10:20 +13:00
Matthew
d93c42e89c added another function to the Utility app. 2010-11-21 13:10:20 +13:00
Matthew
850d26a628 Install RA packages from CD. Fixes bug in case-sensitive filesystems for Folder.cs. 2010-11-21 13:10:20 +13:00
Matthew
c3e79405f7 Make sure mod package dir exists before extraction. 2010-11-21 13:10:20 +13:00
Paul Chote
03b23d88d2 Make the OSX packaged build use the Gl renderer. 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
d5d6cea84c More Windows installer fixes 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
fb173af647 Fixed Windows installer file list. 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
a1bc31883b Changed shaders dir to renderer specific shader dirs in file list. 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
52854c77c2 Added new files to packages, made RPM script auto-generate its file list 2010-11-21 13:10:20 +13:00
Matthew
8f58e41304 Fixed pkgbuild and reimplemented RPM scripts. 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
25525b4155 Fixed PKGBUILD 2010-11-21 13:10:20 +13:00
Matthew Bowra-Dean
66cc0bd8ff Made debian package to architecture independent. Brought arch package up to date. 2010-11-21 13:10:19 +13:00
Paul Chote
01c6127545 Remove gacutil steps from rpm and pkgbuild 2010-11-21 13:10:19 +13:00
Paul Chote
2794e1f62d Actually remove the mdb files, and simplify calling syntax 2010-11-21 13:10:19 +13:00
Paul Chote
83c9e9e6dd A few fixes when running package scripts under debian. 2010-11-21 13:10:19 +13:00
Paul Chote
39742d02bb Produce a windows installer (untested). 2010-11-21 13:10:19 +13:00
Paul Chote
f1b68a5207 Begin rework of packaging scripts. Restructure packaging system, and make osx and debian packages work.
Changed semantics:
- package upload is handled by a separate script
- dropped syntax highlighting (unnecessary, and had concurrency issues)
- `make install' is no longer used in the packaging process
- debian package changelog points to the forum, instead of showing out of date info
- debian package ships tao dlls in the game root, and doesn't insert them in the gac
- debian package refers users to the website for help manually installing packages
2010-11-21 13:10:19 +13:00
Paul Chote
493631cd90 Switch to the ARB apis and add capability and compile/link status checking. 2010-11-21 13:10:19 +13:00
Matthew Bowra-Dean
9a1ce6945b Make OpenRA.Renderer.Gl compile into the right place with VS. 2010-11-21 13:10:19 +13:00
Paul Chote
ccf66cde2f Expose Graphics.Renderer setting; Refactor Renderer.Null. 2010-11-21 13:10:19 +13:00
Paul Chote
233e9326f0 Cleanup some cruft. 2010-11-21 13:10:19 +13:00
Bob
ba97c99f98 assign texunits to samplers, instead of (wrongly) using unitid==textureid 2010-11-21 13:10:19 +13:00
Paul Chote
37edd072a6 shp shaders 2010-11-21 13:10:18 +13:00
Paul Chote
00358e9fe8 Working line shader 2010-11-21 13:10:18 +13:00
Paul Chote
888710cbc5 Enable alpha blending 2010-11-21 13:10:18 +13:00
Paul Chote
518e00c78a Fix setting uniforms; chrome-rgba shader works, but lacks alpha blending. 2010-11-21 13:10:18 +13:00
Paul Chote
f2a20a182e Begin work on the glsl renderer. Renders blue blocks for chrome-rgba. 2010-11-21 13:10:18 +13:00
Paul Chote
a058eb06b2 Duplicate the Cg renderer as a base for the glsl renderer. 2010-11-21 13:10:18 +13:00
Paul Chote
64a7592fed Rename OpenRA.Gl -> OpenRA.Renderer.Cg 2010-11-21 13:10:18 +13:00
Paul Chote
bfb076b9bc Refactor IShader to take a name instead of a stream. 2010-11-21 13:10:18 +13:00
Chris Forbes
5292272902 #186 unlimited power devhack 2010-11-21 12:36:18 +13:00
Chris Forbes
1db3ce4b59 some usings cleanup 2010-11-21 12:25:22 +13:00
Chris Forbes
060d544390 add smoke trails for damaged aircraft 2010-11-21 11:48:09 +13:00
Chris Forbes
b0e3364a77 make unit smoke optional 2010-11-21 11:28:16 +13:00
Chris Forbes
d78dde4db1 fix ModData still being bogus about custom sequences 2010-11-21 11:26:22 +13:00
Chris Forbes
a94b2df865 #361 weap doesnt play sell animation correctly -- fixed 2010-11-21 11:14:36 +13:00
Chris Forbes
e4bb788fb9 #366 only host can see AI players in a lobby -- fixed 2010-11-21 11:11:29 +13:00
Chris Forbes
6dcc401342 add missing EditorAppearance for trees & cnc rocks 2010-11-21 10:59:36 +13:00
Chris Forbes
26a7e06b40 finish initial work on koth-crossroads 2010-11-21 10:59:35 +13:00
Chris Forbes
2ba8120d79 WiP KoTH map 'crossroads' 2010-11-21 10:59:35 +13:00
geckosoft
b9b045098b Changed: People can no longer build structures near the strategic point, once they captured it, without having a regular structure near. 2010-11-21 10:59:35 +13:00
geckosoft
a0682d80c0 Fixed: koth-island-hoppers (map) now correctly sets MustBeClear 2010-11-21 10:59:34 +13:00
geckosoft
1ff39761b7 Fixed: Bug in StrategicProgressWidget.FindFirstWinningPlayer 2010-11-21 10:59:34 +13:00
geckosoft
bddd058b38 Changed: Rules for the koth map (need to hold it for 2 seconds, both poins, and it gets reset if the hold is broken) 2010-11-21 10:59:33 +13:00
geckosoft
8efb717cf4 Changed: Cleaned up the StrategicProgressWidget a bit 2010-11-21 10:59:33 +13:00
geckosoft
65ac607d90 Fixed: ProximityCaptureable now allows allies nearby 2010-11-21 10:59:33 +13:00
geckosoft
0af653b101 Changed: KotH Island Hoppers (map) should be working now! victory after holding it for 5 minutes. 2010-11-21 10:59:32 +13:00
geckosoft
175b07c0ff Added: StrategicProgressWidget to show the capturing progress (including custom gfx)
Fixed: Sync on unsyncable field type
Added: StrategicProgressWidget to both cnc & ra
2010-11-21 10:59:32 +13:00
geckosoft
585cba8af8 Added: StrategicVictoryConditions & StrategicPoint => allows 'koth' gameplay if used 2010-11-21 10:59:32 +13:00
geckosoft
2a7525122e Changed: Made ConquestVictoryConditions public (same for Surrender / Win methods) 2010-11-21 10:59:31 +13:00
geckosoft
7f7c293856 Added: Island Hoppers KoTH map (wip, not done yet) 2010-11-21 10:59:31 +13:00
geckosoft
fbb117705e Changed: Owner maps to Self.Owner now IF captured, otherwise returns the OriginalOwner 2010-11-21 10:59:30 +13:00
geckosoft
78dea9eecb Added: ProximityCaptureable 2010-11-21 10:59:30 +13:00
geckosoft
be9f52e029 Changed: Mounts the map' IFolder with least possible priority, allowing the map to has its own assets 2010-11-21 10:59:26 +13:00
geckosoft
000dd6de7b ed: Made it possible for maps to define custom & override existing voices 2010-11-21 10:57:36 +13:00
geckosoft
5e8e4dd9d5 Changed: Made it possible for maps to define custom & override existing weapons 2010-11-21 10:57:36 +13:00
geckosoft
b31a35d34b Changed: Made it possible for maps to contain custom sequences (allowing 100% custom map-specific units to be 'build') 2010-11-21 10:57:16 +13:00
Matthew Bowra-Dean
414b3a03c3 Updated docs. 2010-11-18 17:47:24 +13:00
Bob
a7f42dcf0c fix interaction between autoattack and idleanimation 2010-11-16 20:32:00 +13:00
Chris Forbes
7bd7f4e56b remove bogus AttackMoveInteraction trait from cnc 2010-11-15 20:03:49 +13:00
Chris Forbes
9584c78500 hack around ICE in gmcs-2.6.7; feature wasn't used anyway 2010-11-15 19:59:07 +13:00
Chris Forbes
bc7a9c14d0 fix helicopters landing in silly places 2010-11-14 21:27:17 +13:00
Chris Forbes
c1eacc225d fix DrawLineToTarget drawing from the ground below flying units 2010-11-14 21:27:17 +13:00
Chris Forbes
e56bbe367d add missing WorldCommand trait to cnc 2010-11-14 21:27:16 +13:00
Bob
6cf9939ab3 remove staticness on Server 2010-11-14 21:26:50 +13:00
Bob
b2f3b8f2af make AutoTarget use an activity. add AutoTarget to teslatank 2010-11-14 19:44:58 +13:00
Bob
80e897abfb add Util.RunActivity, and have Actor.Tick use it. fix medic autoheal 2010-11-14 18:36:36 +13:00
Bob
d152d21338 fix teslazap OutOfMemory exception 2010-11-14 17:32:23 +13:00
Bob
f4e04ece12 fix tesla animations and firing at multiple targets 2010-11-14 16:35:53 +13:00
Bob
e7a07ea9c3 Add target param to INotifyAttack. Remove target field from AttackOmni 2010-11-14 16:03:01 +13:00
Bob
f8e6245903 make order queuing work for buildings and turreted units, too 2010-11-14 15:48:02 +13:00
geckosoft
7c146a9d5d Changed: Made "Move" orders queueable 2010-11-13 17:54:16 +13:00
geckosoft
846286c988 Added: QueuedActivity (to be used for chaining orders) 2010-11-13 17:53:00 +13:00
geckosoft
ba25bc6df4 Added: More constructor overloads for Order (accepting a queued boolean now)
Added: Changed all IssueOrders to make use of the IOrderTargeter.IsQueued
Added: A 'hack' for SetChronoTankDestination so it also sets the queued value
2010-11-13 17:52:48 +13:00
geckosoft
622f9bfe71 Added: forceQueue to IOrderTarget' CanTargetUnit / CanTargetLocation
Added: forceQueue to all related methods
Added: Only shows the select cursor IF hovering over a unit AND the orders return the 'default' icon
2010-11-13 17:46:36 +13:00
geckosoft
8df47f5a60 Added: UnitStanceDefensive 2010-11-13 17:44:45 +13:00
geckosoft
d2a0647085 Added: OnOrder & OnTick event at UnitStance 2010-11-13 17:43:55 +13:00
geckosoft
0e750a3f25 Cleanup: Idle activity now reuses itself instead of returning null (causing another Idle object to be created) 2010-11-13 17:43:41 +13:00
geckosoft
0e6dbe28a8 Changed: Renamed UnitStanceGuard => UnitStanceHoldGround 2010-11-13 17:43:09 +13:00
geckosoft
cc0c45bceb Removed: Reference to AttackMoveInteraction.cs from the project 2010-11-13 17:42:55 +13:00
geckosoft
af3e734561 Changed: HackyAI uses AttackMove now instead of Move 2010-11-13 17:42:14 +13:00
geckosoft
1ac61c5e3e Changed: AttackMove actually works 2010-11-13 17:40:38 +13:00
geckosoft
5d3622b79d Removed: Unused AttackMoveInteraction 2010-11-13 17:39:58 +13:00
geckosoft
b3ddf1ae86 Changed: Rendering of the colored shape (adds a shadow + resizes the shape on larger actors) 2010-11-13 17:39:34 +13:00
geckosoft
17770631a2 Added: Rendering of 'SelectionColor'ed shapes at top left of the selection rectangle (using a simple format to define shapes) 2010-11-13 17:38:47 +13:00
geckosoft
05f6958286 Changed: From running on the local player, to running on all players 2010-11-13 17:38:41 +13:00
geckosoft
bd9c748b17 Fixed: SurrenderOnDisconnect (needs testing 2010-11-13 17:33:16 +13:00
geckosoft
6b40abb58c Implemented: Stances
Added: Basic stances (Aggressive, Guard (Hold Ground), Hold Fire, None (dummy), Return Fire)
Added: WorldCommandWidget (to be able to set said stances)
Added: WorldCommandWidget to ra (cnc will follow, later on)
Changed: Added support to AttackBase for firing with movement disabled + utility method ScanForTarget (used by stances)
Added: AssignUnitStance (attach this to unit-producing actors, together with what stances can be picked as 'default')
2010-11-13 17:26:42 +13:00
geckosoft
6d67ab2240 Changed: Attack-move now only triggers when you use 'a' without any modifier 2010-11-13 17:08:46 +13:00
geckosoft
8b3512e2f1 Changed: Build palette hotkeys cannot be triggered anymore when used together with a modifier 2010-11-13 17:08:30 +13:00
geckosoft
5b71bee4c8 Added: ISelectionColorModifier 2010-11-13 17:08:00 +13:00
Bob
75e7124af0 oops 2010-11-13 17:07:48 +13:00
geckosoft
9ad55d5e28 Changed: AttackMoveInteraction now uses a + the 'right' mouse button to do an attack-move (extra nice thing => it wont lose focus of the selected units!) 2010-11-13 17:04:27 +13:00
geckosoft
9e93edf336 Changed: Made GenericSelectTarget & GenericSelectTargetWithBuilding more generic (now it accepts an optional 'expected' mouse button) default => left (as it was hardcoded) 2010-11-13 17:03:24 +13:00
geckosoft
5608756a24 Moved: AutoAttack key handling out of core => RA
Added: AttackMoveInteraction to RA & CNC rules
2010-11-13 17:02:48 +13:00
geckosoft
ebca421856 Moved: BaseBuilding out of core => RA
Implemented: INotifyKeyPress for World traits (to respond on key pressed)
Moved: GotoNextBase (backspace key) out of core => RA
Added: GotoNextBase trait to both RA & CNC
2010-11-13 17:01:35 +13:00
Bob
22e61a5700 refactor QueueAttack -> GetAttackActivity 2010-11-13 16:42:13 +13:00
Bob
7306de3730 make attacks queuable 2010-11-13 15:53:10 +13:00
Bob
10ed3db71d made all orders queuable 2010-11-13 15:53:08 +13:00
Bob
04e05d9aed remove the default impl of QueueAttack; implement it in AttackFrontal and AttackLeap 2010-11-13 14:59:33 +13:00
Chris Forbes
caae95f12e make Server.Server public so it works. 2010-11-10 11:34:37 +13:00
Paul Chote
dfa14f16d3 Move ServerTraits into Mods. 2010-11-10 10:30:26 +13:00
Paul Chote
8e007131c9 Define ServerTraits in mod.yaml 2010-11-10 10:30:26 +13:00
Paul Chote
ed4c588701 Allow custom commands to be parsed when the player is in a ready state. 2010-11-10 10:30:26 +13:00
Paul Chote
d33806e932 More refactoring 2010-11-10 10:30:25 +13:00
Paul Chote
e83838e9ff Pass the client into InterpretCommand 2010-11-10 10:30:25 +13:00
Paul Chote
b77dcd476c Pull the master server communication into a ServerTrait 2010-11-10 10:30:25 +13:00
Paul Chote
836b3a598b Pull out potentially mod-specific player join code (slightly bogus, will fix properly later) 2010-11-10 10:30:25 +13:00
Paul Chote
967b16fc0e Pull LoadMap out of the server 2010-11-10 10:30:25 +13:00
Paul Chote
ee3437d0f6 Pull the traits into their own files 2010-11-10 10:30:25 +13:00
Paul Chote
e20c736e3f Handle server orders in their own traits - needs further refactoring 2010-11-10 10:30:25 +13:00
Paul Chote
a98d20ea72 Start hacking on a server traits model 2010-11-10 10:30:25 +13:00
Paul Chote
38486e8184 Move some mod-specific UI code out of Game 2010-11-10 10:30:25 +13:00
Paul Chote
047a09bbbd Excise previous server extensions code 2010-11-10 10:30:24 +13:00
Paul Chote
d55e58ea1c Map Tweaks: Remove algernon, remove hospital on chokepoint, fix broken water tiles on wargames. 2010-11-09 23:22:34 +13:00
Paul Chote
17afe80a54 Included attribution 2010-11-09 21:44:58 +13:00
Paul Chote
42bf568d80 Use Blast to decrypt data on extraction. 2010-11-09 21:17:09 +13:00
Paul Chote
50157c43de Port Blast from zlib/contribute to c# 2010-11-09 20:10:51 +13:00
Paul Chote
41988a1298 Save PackageEntries into the index so the compressed data can be extracted. 2010-11-09 14:33:02 +13:00
Paul Chote
86058ec19f Initial IFolder Installshield (.Z) package impl. Parses the package header/toc and prints a file list. 2010-11-09 13:29:37 +13:00
Paul Chote
356c750b23 Refactor Package -> MixFile; group filesystem related classes in FileFormats. 2010-11-09 11:02:13 +13:00
Bob
26cbb9d9c6 fix wrong output in Order.ToString 2010-11-07 21:17:11 +13:00
Chris Forbes
4a0b78c1e6 make all other engine widgets public, for Gecko 2010-11-07 17:16:51 +13:00
Bob
fcb7c845ba adjust Mobile so that it also can't double-add to uim 2010-11-07 17:16:17 +13:00
Bob
12f9c0bce9 fix uim-crate crash 2010-11-07 17:16:14 +13:00
Bob
47ed79b912 rename some of Mobile's Activity-builders 2010-11-07 17:16:11 +13:00
Chris Forbes
a265d11a5f make JoinServer public [at Gecko's request] 2010-11-07 08:41:16 +13:00
Bob
8a96c5f7b5 fix infantry entering buildings 2010-11-06 22:27:28 +13:00
Chris Forbes
5e5456191c fix missing assembly reference FileFormats -> System.Windows.Forms in makefile 2010-11-06 20:33:12 +13:00
Chris Forbes
aae7f56e7d extend RevealMapCrateAction to optionally reveal for allies 2010-11-06 20:18:18 +13:00
Chris Forbes
3645b3ee13 increase ParaBomb spread 3 -> 6 2010-11-06 20:02:01 +13:00
Chris Forbes
e0f357390c clean up usings in AirstrikePower 2010-11-06 19:58:41 +13:00
Chris Forbes
9c3cb62838 reduce redeye damage 50 -> 40 2010-11-06 19:55:53 +13:00
Chris Forbes
14225b8e79 reduce dragon damage from 60 to 50 2010-11-06 19:55:10 +13:00
Chris Forbes
e01bf735d9 reduce cooldown on Chronoshift and Invulnerability to 2min each; reduce invuln duration to 30 seconds 2010-11-06 19:51:57 +13:00
Chris Forbes
1904f8ced1 fix weap door never closing 2010-11-06 17:47:11 +13:00
Caleb Anderson
3caca8c323 some noise on shellmap 2010-11-06 17:00:36 +13:00
Chris Forbes
dd7ce2d45e fix dumb crash in UIM 2010-11-06 16:56:50 +13:00
geckosoft
f793f4548b Added: A PasswordField widget (based on the TextField widget) 2010-11-06 16:49:46 +13:00
Chris Forbes
56675a61f5 rationalize the mess of Sound.Play[ToPlayer] functions. 2010-11-06 16:49:08 +13:00
Bob
3dd27fcb77 fix crash involving crushing and dead walls 2010-11-06 16:35:51 +13:00
Chris Forbes
13d76f8e9c removed editor -> ra dep; added EditorAppearance for inconvenient bits that the editor must have _some_ understanding of, but can't see 2010-11-06 15:10:29 +13:00
Bob
9a2cdcde11 move Selectable.Radius into Health 2010-11-06 14:35:26 +13:00
Bob
155e7320cb add support for decimal to fieldLoader. use decimal for speedmodifiers 2010-11-06 14:10:56 +13:00
Chris Forbes
750fd84494 reinstate order validation for ra & cnc 2010-11-06 13:36:53 +13:00
Bob
924adc68a9 fix aircraft desync 2010-11-06 13:36:11 +13:00
Bob
0f8d9d7fb3 fix heli repusion from grounded helis. cleanup flight code 2010-11-06 12:44:25 +13:00
Bob
801aa1156f move aircraft code into Mods.RA/Air/ 2010-11-06 12:18:04 +13:00
Bob
aa0c14c214 Fix crash when generating a syncreport when blaming something other than Tick. 2010-11-06 12:08:33 +13:00
Bob
8fcbb670d8 rename AllowOreAt => AllowResourceAt 2010-11-06 11:53:41 +13:00
Bob
85a26ecdf7 fix invincible aircraft, infantry 2010-11-06 11:06:12 +13:00
Bob
480c5edd75 move Building et al into Mods/ 2010-11-06 11:05:45 +13:00
Bob
fdfa1ddf97 extract DrawGrid from DrawBuildingGrid 2010-11-05 19:50:18 +13:00
Bob
80caf1818b fix off-by-one in IsInRange. use CenterLocation in combat code where appropriate 2010-11-05 19:50:17 +13:00
Bob
5c0cd50797 remove unnecessary parameters from Aircraft.MovementSpeedForCell, and rename to MovementSpeed 2010-11-05 19:50:17 +13:00
Bob
8129d5d7dc use CenterLocation, not Location, to determine facing during attack 2010-11-05 19:50:17 +13:00
Bob
a77b7af5fd add Target overload for IsInRange 2010-11-05 19:50:16 +13:00
Bob
ecf41722c3 rename TargetableSquares -> TargetableCells 2010-11-05 19:50:16 +13:00
Bob
39b09780f6 refactor Targetable into Targetable{Unit,Building} and ITargetable 2010-11-05 19:50:15 +13:00
Bob
98dec6dc8e revert sanity check that building is entirely within map (trees break it) 2010-11-05 19:50:15 +13:00
Bob
50b1ba3acc attack if in range of any cell of a building 2010-11-05 19:50:15 +13:00
Bob
c3fc7b98f3 use UIM (was BIM) to determine what cells a building blocks 2010-11-05 19:50:14 +13:00
geckosoft
f5b8b18d86 Core: Added trait 'SurrenderOnDisconnect' and the core changes required to make this work 2010-11-05 19:48:32 +13:00
geckosoft
e7c61fac5c Core: Added the attacker to IDamageModifier' GetDamageModifier 2010-11-05 19:48:31 +13:00
geckosoft
2640603f6c Added 'Health' and 'PreviousHealth' to the AttackInfo (so we can know how many 'real' damage is done!) 2010-11-05 19:48:31 +13:00
Chris Forbes
1a011276bf (gecko) add more overloads for Renderable, to support scaling 2010-11-05 19:48:31 +13:00
Chris Forbes
bc7cf09287 (gecko) Add support for custom order generators 2010-11-05 19:48:30 +13:00
Chris Forbes
7762241653 (gecko) Send damage notifications to the owner's player actor too. 2010-11-05 19:48:30 +13:00
geckosoft
9489196911 Added a new trait : Scale 2010-11-05 19:48:29 +13:00
Chris Forbes
e32e060d37 (gecko) make production queue content accessible to mod code 2010-11-05 19:48:29 +13:00
Chris Forbes
5e3fce6820 (gecko) Return the ISound when playing sounds, so you can stop it later 2010-11-05 19:48:28 +13:00
Chris Forbes
6655b6ba6a (gecko) make IonCannon and NukeLaunch effects public 2010-11-05 19:48:28 +13:00
Chris Forbes
0b4b003c10 (gecko) Make Parachute public so it can be used in other mods 2010-11-05 19:48:27 +13:00
geckosoft
380e7e8b20 Core: Made stuff public so people (read: openrg) can have its own lobby, based on the core lobby 2010-11-05 19:48:27 +13:00
geckosoft
9b3533abc0 Core: Made Corpse public 2010-11-05 19:48:27 +13:00
Chris Forbes
1409016cbd (gecko) Allow mods to override order validation 2010-11-05 19:48:26 +13:00
Chris Forbes
4aa1fb4b86 refactor mouse position label hooking for Surface 2010-11-02 11:16:30 +13:00
Chris Forbes
40126c52e8 render actors using correct palettes in editor 2010-11-02 10:30:22 +13:00
Chris Forbes
dd600d4590 indent, etc 2010-11-02 09:50:58 +13:00
Chris Forbes
532f420338 build 8bpp bitmaps in OpenRA.Editor 2010-11-02 09:39:35 +13:00
Chris Forbes
e25878e78d ai: dont build defenses if in low power; dont build random stuff if no power-producing item is available on the same queue 2010-11-02 07:51:07 +13:00
Chris Forbes
002cc4842a start reducing duplication in HackyAI 2010-11-02 07:27:31 +13:00
Chris Forbes
eac548ac8b disable bot debug by default 2010-11-01 20:38:28 +13:00
Chris Forbes
3fc4d1b219 fix cnc crashing on startup 2010-11-01 20:31:12 +13:00
Chris Forbes
80e3b8be0d more cleanups 2010-11-01 20:28:28 +13:00
Chris Forbes
fa35f6caa4 cleanups 2010-11-01 20:25:03 +13:00
Chris Forbes
526cf6059a remove Misc.cs; put its contents in sensible places. 2010-11-01 20:15:32 +13:00
Caleb Anderson
1527e472b6 potential fix for bug 312 : PlaceBuilding.ResolveOrder does not validate the requested build location 2010-11-01 18:42:51 +13:00
Bob
94f7c6db97 determine which sprites to render during Render, not Tick 2010-11-01 18:39:50 +13:00
Bob
e3ddb8f757 cache world.LocalPlayer instead of fetching it repeatedly within loops 2010-11-01 18:39:44 +13:00
Chris Forbes
d7d0d371c6 (bob) refactor input dispatch; remove public Dispatch*Input from game; (chris) fix build failures due to rebase past gecko 2010-11-01 18:39:37 +13:00
Chris Forbes
527c60daa7 some cleanup on gecko's stuff 2010-11-01 18:34:44 +13:00
geckosoft
c30050396a Fixed: Possible crash 2010-11-01 17:55:33 +13:00
geckosoft
60a8acf4d4 Added: Another hook for server extensions 2010-11-01 17:55:32 +13:00
geckosoft
5164c3cd7d Hack: Changed the ChooseFreePlayerIndex (hack on its own..) to loop till 256 instead of 8 (ie increasing max player support to 256) 2010-11-01 17:55:32 +13:00
geckosoft
6276e659cd Fixed: A crash when the host disconnects 2010-11-01 17:55:31 +13:00
geckosoft
298314626e Added: Dedicated server support
Added: The ability to not render anything when using the client as a dedicated server
Added: The basic server extension (NullServerExtension)
Exposed: Made some fields public, so that the server extension can access it
2010-11-01 17:55:31 +13:00
geckosoft
0112bc4df7 Added : Some missing changes to make WorldGameOver work (ie missing RejoinLobby etc)
Warning: Please add the following manually (if you cant find it):
	in Game.cs
		find
			'case ConnectionState.Connected:'
		add
			if (ConnectedToLobby != null) ConnectedToLobby();

Tried my best to add it in the patch but it failed :(
2010-11-01 17:55:31 +13:00
geckosoft
c8dbed938a Enable: WorldGameOver at the 'ra' mod (ie after 10 second delay, it'll return all players to the lobby) 2010-11-01 17:55:30 +13:00
geckosoft
278f35e4aa Added: If the 'Owner' ('who' said something) @ chat is null or "" it'll just render the text 2010-11-01 17:55:30 +13:00
geckosoft
dd38e45f2e Added: Lobby server command "spectator" - will attempt to put the player in an available spectator slot 2010-11-01 17:55:29 +13:00
geckosoft
3e08f9b1b1 Added: LocalAssemblies / LocalRules to Manifest.cs (can be used to add a custom set of rules / assemblies to be loaded, other than the ones defined in the mod) 2010-11-01 17:55:29 +13:00
geckosoft
8392a44314 Added: Support for not-synced traits (ITraitNotSynced) 2010-11-01 17:55:28 +13:00
geckosoft
d050d1a4b9 Added : OpenRA.Renderer.Null 2010-11-01 03:50:21 +01:00
geckosoft
56598ce2ff Fixed: crash when starting a new game after disconnecting from own server 2010-11-01 03:46:38 +01:00
geckosoft
2fb72155eb Added: Missing IngameObserverChromeDelegate.cs file (for spectator)
Fixed: Some spectator gui issues (@ gamelobby.yaml / LobbyDelegate.cs)
2010-11-01 03:35:55 +01:00
geckosoft
030bd4b28d Core: Added basic support for Spectators
TODO: Someone modify the files for cnc (chrome / rules)
2010-10-31 04:03:31 +01:00
Matthew Bowra-Dean
b9c40ad3ce Cleanup
Removed OpenRAUploader (long since obsolete) and master server hack from master server upgrade.
2010-10-28 23:03:14 +13:00
Matthew Bowra-Dean
4490a90332 Changed IFolder implementations' priorities to be based on listing order in mod.yaml 2010-10-28 22:21:54 +13:00
Matthew
15d6facdb9 Fix crash in WorldInteractionControllerWidget. 2010-10-25 17:14:14 +13:00
Chris Forbes
b80962b365 fix ore/tib growth -- we can always grow in a cell that already contains our resource type. buildable/terraintype checks only come into it when growing into *new* cells 2010-10-25 11:34:31 +13:00
Chris Forbes
814c6a8713 aircraft crash nicely now 2010-10-25 11:34:30 +13:00
Chris Forbes
eea89c1d33 make FallsToEarth significantly more flexible 2010-10-25 11:34:29 +13:00
Chris Forbes
9ec0367ecb add support for an explosion on aircraft falling out of the sky 2010-10-25 11:34:28 +13:00
Bob
f5fe1013ee remove AttackDefault; use AttackFrontal instead 2010-10-25 09:51:14 +13:00
Bob
c338d28d35 fix 'decided on Attack but ordered Heal' message on medic 2010-10-25 09:14:49 +13:00
Chris Forbes
2f962452e5 fix compile failure in prev 2010-10-25 09:14:22 +13:00
Bob
10f5e68f7f fix #166 (shroud artifacting at bounds) 2010-10-25 09:06:23 +13:00
Chris Forbes
1cde37f32b update cnc to work with updated engine (AttackBase -> AttackDefault) 2010-10-25 08:45:49 +13:00
Chris Forbes
291899de8a glitch-free. 2010-10-25 08:32:14 +13:00
Caleb Anderson
cc70669f1a use player color option 2010-10-25 08:29:55 +13:00
Caleb Anderson
c568dfa486 Contrail trait 2010-10-25 08:29:54 +13:00
Caleb Anderson
ff7daf8727 MoveViewport takes a float to allow for smoother panning. Added more scripting to shellmap 2010-10-25 08:16:08 +13:00
Caleb Anderson
fc72066ed2 Fixing last mouse position commit :( 2010-10-25 08:16:08 +13:00
Caleb Anderson
253ccd6d9b Status bar with mouse position in editor 2010-10-25 08:16:07 +13:00
Bob
01accaeb38 fix cargo 2010-10-25 08:03:13 +13:00
Bob
46c3bc09a1 fix harv bug in c&c 2010-10-25 08:03:12 +13:00
Bob
2f0b7566e5 partial fix for tsla 2010-10-25 08:03:12 +13:00
Bob
9b8ec714d2 add AutoTarget to v2 2010-10-25 08:03:11 +13:00
Bob
5d408fe3c7 make AttackMove use an activity 2010-10-25 08:03:11 +13:00
Bob
aa0b7bedf0 pass target to DoAttack 2010-10-25 08:03:10 +13:00
Bob
c5358f7c82 call DoAttack from activities instead of from Tick in AttackPlane/AttackHeli 2010-10-25 08:03:10 +13:00
Bob
158d6e5647 move CheckFire in Weapon 2010-10-25 08:03:09 +13:00
Bob
e091781104 use new AttackDefault trait instead of AttackBase; make AttackBase abstract 2010-10-25 08:03:09 +13:00
Bob
25582cb9f8 move CancelableActivity into its own file 2010-10-25 08:03:08 +13:00
Bob
fece294cc6 move RemoveSelf activity into Mods/ 2010-10-25 08:03:07 +13:00
Bob
c3501f68e3 move TurnActivity into Mods/ 2010-10-25 08:03:07 +13:00
Bob
c4ee5fbd41 add self param to OnCancel 2010-10-25 08:03:06 +13:00
Caleb Anderson
9a54074b1b motd failure avoidance 2010-10-23 21:27:36 +13:00
Chris Forbes
10e918c375 increase ftrk range 6 -> 8; spread 3 -> 5 2010-10-23 19:14:53 +13:00
Chris Forbes
bbcad99fa7 increase agun range 6 -> 10; increase zsu-23 spread 3 -> 5 2010-10-23 18:52:04 +13:00
Chris Forbes
c8198a1a1c reduce hind cost 2000 -> 1500 2010-10-23 18:52:03 +13:00
Chris Forbes
8d5241f419 reduce hpad cost 1500 -> 300; increase heli,hind cost 1200 -> 2000 2010-10-23 18:52:03 +13:00
Chris Forbes
448b681c5b reduce AFLD cost 1100 -> 300; increase YAK cost 800 -> 1000; increase MIG cost 1200 -> 2000 2010-10-23 18:52:02 +13:00
Chris Forbes
826f7a29b5 remove dead .mpr maps 2010-10-23 18:52:02 +13:00
Chris Forbes
0629b1e2d2 quick hack to fix aircraft fail in prev 2010-10-23 18:49:42 +13:00
Bob
0d9cf63dd2 move Mobile et al into Mods/ 2010-10-22 11:31:13 +13:00
Bob
6513bd5fe0 don't use Move directly 2010-10-22 11:10:32 +13:00
Bob
f933e3de3f fix entering buildings from the east or south 2010-10-22 10:20:34 +13:00
Bob
88a8d84153 use new Enter activity for engy, spy, c4 2010-10-21 20:58:07 +13:00
Bob
8e4f5da791 fix ironcurtain 2010-10-21 18:29:43 +13:00
Bob
a61d21e501 fix sync-checking in replays 2010-10-21 15:33:24 +13:00
Matthew Bowra-Dean
2bcf33661a Give folders higher priority than packages in FileSystem. Also fixes bug where folder contents were not being cached with the correct hash. 2010-10-21 07:44:26 +13:00
Matthew Bowra-Dean
f6df7a06f2 fixes #323 2010-10-21 07:43:52 +13:00
Bob
de92a2fc0c remove UIM-debug from settings (now in DeveloperMode trait) 2010-10-20 20:49:10 +13:00
Bob
6012f1d592 fix a water-walk bug 2010-10-20 20:39:18 +13:00
Chris Forbes
caf676dc33 fix client quits 2010-10-20 20:33:28 +13:00
Chris Forbes
e3ae1bec75 add Yellowstone II map 2010-10-19 21:04:00 +13:00
Chris Forbes
b98b517e35 add some decent 4p cnc maps 2010-10-19 19:25:05 +13:00
Chris Forbes
5d9f25eef5 add Slendermang's 'Into the River Below' C&C map 2010-10-18 18:54:16 +13:00
Chris Forbes
5bf69eb539 strip some dead crap from UnitOrders 2010-10-18 18:44:47 +13:00
Chris Forbes
09f7778294 fix bogus base-cycler 2010-10-18 18:07:08 +13:00
Bob
c8ec5f3579 fix sync 2010-10-17 13:38:16 +13:00
Chris Forbes
a54c7ecc18 reduce ra AFLD power requirement from 50 to 20 2010-10-17 12:34:21 +13:00
Chris Forbes
0064caf1f4 fix cnc missiles a bit; add trails to cnc sam missiles 2010-10-17 12:34:02 +13:00
Chris Forbes
fc2fbd4689 nerf v2 reload slightly (250 -> 280) 2010-10-17 12:27:49 +13:00
Chris Forbes
0f0793cde5 buff arty slightly 2010-10-17 12:27:12 +13:00
Chris Forbes
2fed6f61e9 fix version string showing up twice in bottom-right corner 2010-10-17 10:42:25 +13:00
Bob
3df310df6e halve bandwidth usage 2010-10-16 22:25:31 +13:00
Bob
c2b3a749ca change IConnection interface wrt sending 2010-10-16 21:05:14 +13:00
Chris Forbes
2d2220f38f issue a warning on the debug, rather than exploding on double-quit 2010-10-16 19:09:38 +13:00
Chris Forbes
7509bf85aa #309 add Tiberian's 'chokepoint' cnc 1v1 map 2010-10-16 18:54:04 +13:00
Chris Forbes
64e8088ae4 cnc: nerf apc speed 15 -> 11 2010-10-16 18:54:03 +13:00
Chris Forbes
15584b9b34 c&c unit tuning: orca various nerfs, bggy/jeep/bike speed nerfs 2010-10-16 18:54:03 +13:00
Matthew
79c1d1b0a6 Updated linux post-install scripts to use OpenRA.Utility.exe 2010-10-16 18:48:42 +13:00
Matthew
50860614cf Downloaded packages extracted. Added SharpZipLib in order to extract them. 2010-10-16 18:48:42 +13:00
Matthew
90d1d3e053 Makefile rule for OpenRA.Utility 2010-10-16 18:48:42 +13:00
Matthew Bowra-Dean
3bf83b52fb Download packages for mods action. 2010-10-16 18:48:42 +13:00
Matthew Bowra-Dean
5f57dd7a62 Options to install scores.mix from RA and CnC CDs 2010-10-16 18:48:42 +13:00
Matthew Bowra-Dean
8e1185b56f --mod-info now accepts a comma separated list of mods. 2010-10-16 18:48:41 +13:00
Matthew Bowra-Dean
26098df2a1 Added mod metadata listing to OpenRA.Utility 2010-10-16 18:48:41 +13:00
Matthew Bowra-Dean
9ac9d83745 Moved Mod class into OpenRA.FileFormats. Added OpenRA.Utility project, a CLI program for utility actions on a game install. 2010-10-16 18:48:41 +13:00
Chris Forbes
51edd5a3f4 #314 reduce effectiveness of GUN vs unarmored, 30% -> 20% 2010-10-16 17:19:04 +13:00
Paul Chote
fc07f90f91 Fix editor 2010-10-16 12:06:29 +13:00
Paul Chote
b64dcbf502 Fix HackyAI in cnc 2010-10-16 11:49:27 +13:00
Paul Chote
5694c113be undo testing changes 2010-10-16 09:56:01 +13:00
Paul Chote
01cf5c21a7 Add `roof' to lst 2010-10-16 09:56:01 +13:00
Paul Chote
4206d2e131 Add Katzsmile's transport remake; make it controllable on GDI01 while testing. 2010-10-16 09:56:01 +13:00
Paul Chote
83968553aa Allow maps to override and enforce race/colour selection 2010-10-16 09:56:01 +13:00
Paul Chote
aa2aba1250 Allow map slots to disallow bots 2010-10-16 09:56:00 +13:00
Chris Forbes
bba9c4b976 #313 fixed -- there's unsynced code that runs in Tick, too. 2010-10-16 09:48:39 +13:00
Chris Forbes
999eef2ec9 #157 explosions weren't taking altitude into account 2010-10-16 09:30:32 +13:00
Chris Forbes
f28c8903aa #297 planes get stuck on map edge -- fixed 2010-10-16 09:09:39 +13:00
Chris Forbes
f58eabe667 fix base cycling (and free mcv logic) for cnc 2010-10-15 18:51:25 +13:00
Chris Forbes
86695dfe29 #299 Updated version of 'The Sentinel' 1v1 map 2010-10-15 18:48:39 +13:00
Chris Forbes
9ae452e8d6 make GiveMcvCrateAction less stupid, if the GiveUnitCrateAction says it can't do it. 2010-10-15 18:38:09 +13:00
Chris Forbes
3e547102d2 #217 avoid dumping tanks in the sea, and ships on dry land 2010-10-15 18:36:34 +13:00
pdovy
e883e63c87 fixed bug where cloakable units were not targetable when uncloaked. removed ITargetable interface in favor of using the Targetable trait. fixed warnings in child classes of Targetable. 2010-10-15 18:13:01 +13:00
Caleb Anderson
a904047a16 Toggle-able teamchat on shift-enter 2010-10-15 18:07:36 +13:00
Chris Forbes
ad1af792e6 add CashTrickler trait, to support oil derricks, etc 2010-10-15 17:56:28 +13:00
Chris Forbes
6c9527d9dc #304 engineer goldwrench cursors were backwards 2010-10-15 17:44:18 +13:00
Chris Forbes
da2d461aa8 use fixed missile silo icon 2010-10-15 17:36:56 +13:00
Paul Chote
49bfd69707 Fix voice crash on adding a 3rd side (thanks raminator for finding this) 2010-10-15 12:33:15 +13:00
Paul Chote
2a02df9411 Fix crash on fmv completion 2010-10-15 00:03:15 +13:00
Paul Chote
185ba80e99 Fix FMV player widget display 2010-10-14 23:30:48 +13:00
Paul Chote
127cbf3f96 Start pulling out useful scripting components - stalled by widget changes having broken the fmv player. 2010-10-14 22:16:18 +13:00
Paul Chote
4bdf675def Mute shellmap combat 2010-10-14 20:03:36 +13:00
Paul Chote
9c944924de Fix a pile of compile warnings and debug log spam. Fix <playername> (Dead) in chat 2010-10-14 19:40:00 +13:00
Paul Chote
28f79533eb Customisable mcv crates 2010-10-14 19:27:43 +13:00
Paul Chote
5a834c9500 Add mcv, napalm, nuke crates to cnc. Reduce levelup and cash shares. 2010-10-14 19:27:43 +13:00
Chris Forbes
3255218d5c #298 MINE overlaps units wrong -- fixed 2010-10-14 19:22:16 +13:00
Chris Forbes
9befe377d5 fix invisible crates in cnc (where did that patch go?) 2010-10-14 19:15:37 +13:00
Chris Forbes
f39b4f0750 fix putting units back into badr/c17 and cursors 2010-10-14 18:09:59 +13:00
Chris Forbes
1794625cea #284 double-destroy in same frame fixed 2010-10-14 18:02:15 +13:00
Chris Forbes
42092fe6dd fix #291 2010-10-14 14:41:43 +13:00
Chris Forbes
1a451fe813 fix crash in TiberiumRefineryDockAction.CancelDock 2010-10-13 22:17:55 +13:00
Paul Chote
0e845a9f3a Make tundra slightly less boring 2010-10-13 21:44:14 +13:00
Chris Forbes
2a3c149769 rename oasis map, since that wasn't what it was. 2010-10-13 21:18:26 +13:00
Chris Forbes
7cfcd94e23 #181, #286 fixed -- sharedrandom seed from server is now used. 2010-10-13 21:00:27 +13:00
Chris Forbes
247a8c9717 add Tiberian's TD map: 'The Sentinel (1v1)' 2010-10-13 20:52:40 +13:00
Chris Forbes
4afd8ad783 #289 lobby title should show servername -- fixed 2010-10-13 20:45:03 +13:00
Paul Chote
dca77956cb Revert to saving only non-default settings. 2010-10-13 19:57:53 +13:00
Paul Chote
22c6c3b3f6 Remove the default westwood maps from cnc. 2010-10-13 19:57:52 +13:00
Paul Chote
1e8e5c8f5c Remove aftermath mod - it has bitrotted beyond all usefulness. 2010-10-13 19:57:52 +13:00
Paul Chote
c0fcc862d6 Add some more mod metadata for beedee. Todo: enforce dependencies and standalone during game init. 2010-10-13 19:57:52 +13:00
Paul Chote
5a3ccdf0c5 fix ssm launcher rockets 2010-10-13 19:57:52 +13:00
Paul Chote
1bd802c386 Add tech building definitions to cnc; noncapturable map decorations until they have behavior implemented. 2010-10-13 19:57:52 +13:00
Paul Chote
3a4e2abedd Fix snow theatre 2010-10-13 19:57:18 +13:00
Paul Chote
f13343ef2e Fix tilesets colours for snow and blue tib, fix unit speed over tib, fix lst pathability. 2010-10-13 19:57:18 +13:00
Paul Chote
2b1ac6a60f WIP 1v1 map 2010-10-13 19:57:18 +13:00
Chris Forbes
8aa180c1f4 cleaned up unused bits in attackmove 2010-10-13 19:20:17 +13:00
Chris Forbes
260e420f85 fix crash in attackmove 2010-10-13 19:12:20 +13:00
Chris Forbes
1a203afd89 fix all the buggy crap around chat/teamchat... still hacked 2010-10-13 08:13:21 +13:00
max621
c150fd9475 Added attack move 2010-10-13 08:13:20 +13:00
Chris Forbes
566303a8f1 #276 fixed 2010-10-12 21:19:48 +13:00
Chris Forbes
10f8364b99 #240 declaring war should set the reciprocal state too 2010-10-12 21:19:48 +13:00
Chris Forbes
7c31f72db6 quick hack around the teamchat crash in lobby 2010-10-12 21:19:27 +13:00
Bob
6b6c9639f9 fix crash wrt chat in lobby 2010-10-12 20:37:36 +13:00
Bob
7ca9fcdac9 run the shellmap even while the lobby shows. remove Widget.SpecialOneArg 2010-10-12 18:33:16 +13:00
Bob
20276291ce move Game.world onto OrderManager. use call IssueOrder on world and/or on orderManager, not on Game 2010-10-12 17:30:27 +13:00
Bob
34fc207a6c FUCK YES 2010-10-12 17:30:24 +13:00
Bob
c974e61680 remove refs to Game.world in widgets 2010-10-12 17:30:22 +13:00
Bob
09db76f89f remove ref to Game.world in Move 2010-10-12 17:29:11 +13:00
Bob
6bbf878314 remove ref to Game.world in Viewport.ShroudBounds 2010-10-12 17:29:09 +13:00
Bob
4cd3195f9f call refreshPalette in the right place. make Game.worldRenderer PRIVATE (yay) 2010-10-12 17:29:06 +13:00
Bob
6ea2a06e4b pass WorldRenderer to Widget.Draw, DrawInner 2010-10-12 17:27:08 +13:00
Bob
597dba8584 untangling WorldRenderer from World 2010-10-12 17:24:23 +13:00
Bob
1c1483377c remove ref to Game.world in Combat 2010-10-12 17:24:19 +13:00
Bob
0873741983 don't pass world to Widget.Tick, either 2010-10-12 17:24:17 +13:00
Bob
e0afc08e5f move an access of Viewport into Game 2010-10-12 17:24:14 +13:00
Bob
cb1deacbb2 pass world into CheckSync. don't pass world into Widget.DrawInner 2010-10-12 17:24:12 +13:00
Bob
ab1e930ba3 pass worldRenderer around as necessary 2010-10-12 17:24:07 +13:00
Bob
10bf85f57e move Game.Current{Host,Port} into orderManager 2010-10-12 17:24:03 +13:00
Bob
17990ab8b7 move LobbyInfo onto OrderManager 2010-10-12 17:24:00 +13:00
Bob
beecb8aeb1 remove redundant parameter from ObjectCreator.Param attribute 2010-10-12 17:23:57 +13:00
Bob
6a25d989a7 remove many references to Game.world 2010-10-12 17:23:55 +13:00
Bob
f8776d773d extract FrameData from OrderManager. fix disconnect bug in NetworkConnection 2010-10-12 17:22:17 +13:00
Bob
3724f46a3e remove world arg to SyncLobbyInfo and HandleInput 2010-10-12 17:22:14 +13:00
Bob
915ad7fb7b extract replay saving from OrderManager 2010-10-12 17:22:12 +13:00
Chris Forbes
07023b6c35 add yaml setup for blue tiberium 2010-10-12 16:59:58 +13:00
Chris Forbes
b78b5b22a3 add blue tiberium art 2010-10-12 16:59:58 +13:00
Bob
eca098b0b4 use a getter for Aircraft.Location 2010-10-12 07:59:40 +13:00
Bob
011a20e8b4 add IHasLocation 2010-10-12 07:59:40 +13:00
Bob
9c362f7d41 remove setters on Mobile.{from,to}Cell. use SetLocation instead 2010-10-12 07:59:39 +13:00
Chris Forbes
99d92ee095 move ColorFromHSL out of the ui code 2010-10-11 19:52:46 +13:00
Chris Forbes
b905d343af fix mishandled CancelProduction 2010-10-11 19:37:45 +13:00
Chris Forbes
024b564b8c maybe this works better 2010-10-11 19:10:34 +13:00
Chris Forbes
9c0e3ac4c9 allow AppearsOnRadar to use Location rather than OccupiedCells, for things that don't occupy any cells 2010-10-11 18:54:13 +13:00
Chris Forbes
a2205e9031 fix some dumb (nonfatal) crashes in the editor with nothing loaded 2010-10-11 18:21:41 +13:00
Chris Forbes
0df9815d2c fix base-cycling for mac build, too? 2010-10-10 15:11:53 +13:00
Chris Forbes
79d6eb4a2b some widgets cleanup 2010-10-10 15:09:26 +13:00
Chris Forbes
0d8557eadb fix NRE in CancelableActivity 2010-10-10 11:04:39 +13:00
Matthew Bowra-Dean
70f6fc7a7a Removed git describe from checkout-and-build.sh 2010-10-09 22:26:17 +13:00
Paul Chote
11f6a8b945 Revert mono 2.8 deps; causes desyncs. 2010-10-09 20:05:37 +13:00
Chris Forbes
e3d71acb05 fix crash in CrateEffect 2010-10-09 13:40:57 +13:00
Chris Forbes
580f1cfe97 bot and humans hate each other, even if the host is on a team. 2010-10-09 13:40:55 +13:00
Andrew Riedi
3d7434f42e Fixed under VS 2010. 2010-10-09 13:40:52 +13:00
Chris Forbes
ef96604f9e #231 scroll jumping fixed 2010-10-09 13:40:49 +13:00
Chris Forbes
465f5d295b force master server url update, if old. 2010-10-09 13:40:47 +13:00
Chris Forbes
1feb377d43 fix bogus target lines being drawn to 0,0 2010-10-09 13:40:33 +13:00
Caleb Anderson
a065fb464e bandage to fix dogs not killing infantry in certain cases 2010-10-09 13:40:21 +13:00
Chris Forbes
e39917ca19 trim bbox for ftrk 2010-10-08 19:09:18 +13:00
Chris Forbes
318f496bf9 #202 fixed 2010-10-08 19:03:01 +13:00
Chris Forbes
ed8a155249 if c17 gets confused, just fly away 2010-10-08 18:57:14 +13:00
Chris Forbes
40ac5f7b6e FallsToEarth for cnc helis too 2010-10-08 18:45:52 +13:00
Chris Forbes
517754027e 8Inch and SubMissile minimum ranges temporarily disabled, until combat bugs are fixed 2010-10-08 18:33:38 +13:00
Caleb Anderson
ef4f478e10 Strip newlines from scrolling text. Frame-friendly update of scrolling text 2010-10-08 18:29:20 +13:00
Chris Forbes
92c30b89f8 FACT hp 1000 -> 1500 2010-10-08 18:26:25 +13:00
Chris Forbes
7331a9c4fb prevent aircraft shooting while landed 2010-10-08 18:25:26 +13:00
Chris Forbes
d2b9e150f1 add FallsToEarth for helicopters dying 2010-10-08 18:24:08 +13:00
Chris Forbes
8ba329f1be reduce cost of CA 3200 -> 2400 2010-10-08 18:03:34 +13:00
Chris Forbes
8868eab247 nerf hind chaingun from [x2] 40@3 to 20@10 2010-10-08 18:03:13 +13:00
Caleb Anderson
f12889e684 Sensible scroll cursor positions for cnc. RA seems to be totally different, didn't touch atm 2010-10-08 17:39:00 +13:00
Caleb Anderson
5c095bc174 more politic default motd text for cnc 2010-10-08 17:38:55 +13:00
Caleb Anderson
0c24a08436 sane default scroll speed 2010-10-08 17:38:48 +13:00
Chris Forbes
9762b540b0 fix bogus reverse-enter-transport (in ResolveOrder this time) 2010-10-08 17:38:07 +13:00
Paul Chote
fd34f2ba99 Fix #225 and some other uses of a.IsInWorld / a.IsDead() 2010-10-08 10:56:50 +13:00
Paul Chote
ad6481c8e8 Change master server url. Won't work until dns is set correctly. 2010-10-07 22:46:44 +13:00
Paul Chote
7426d47cd5 Fix some compile warnings 2010-10-07 22:46:44 +13:00
pdovy
761f62292f missing files from previous commit 2010-10-07 22:46:44 +13:00
unknown
63b8555bc9 Fix bug that prevented ground units from attacking landed aircraft. 2010-10-07 22:46:44 +13:00
Bob
3209da4a4a fixed PlaceBuilding and Chronosphere ordergenerators 2010-10-07 22:07:13 +13:00
Bob
aebef4f1c8 rename IIssueOrder2 -> IIssueOrder 2010-10-07 22:07:13 +13:00
Bob
d3244184c1 implement order targeter for everything else 2010-10-07 22:07:13 +13:00
Bob
39e62354a8 implement order targeter for passenger 2010-10-07 22:07:12 +13:00
Bob
f525c3808e implement order targeter for cargo 2010-10-07 22:07:12 +13:00
Bob
87a0b52ce5 more order targeters 2010-10-07 22:07:12 +13:00
Bob
4bc9e01516 use new orders system in various traits 2010-10-07 22:07:12 +13:00
Bob
711d05da98 use IIssueOrder2 in AttackBase 2010-10-07 22:07:12 +13:00
Bob
3d805ff40d added IIssueOrder2. most orders are broken, but Minelayer is fixed 2010-10-07 22:07:12 +13:00
Bob
0cd140849b fix some support powers 2010-10-07 22:07:12 +13:00
Bob
d6110b9ef0 add Sync.AssertUnsynced. use it in OrderGenerator.set 2010-10-07 22:07:12 +13:00
Bob
26d1db778e push the check-synchash-doesn't-change pattern into a utility fn. furthur reduce the number of uses on Game.world 2010-10-07 22:07:11 +13:00
Bob
f41aa474aa remove more uses of Game.world 2010-10-07 22:07:11 +13:00
Paul Chote
0002e80a19 Use new deps package, built on mono 2.8. Enable new sgen garbage collector. 2010-10-07 22:05:43 +13:00
Chris Forbes
759a52d86e fix build failure from bad merge in prev 2010-10-07 18:24:40 +13:00
max621
44fe0396bb Added shift+right click on build menu cancels 5 orders. Added ctrl+shift+right click on build menu cancels all orders 2010-10-07 18:23:26 +13:00
rasco
dd6d8d916e hackyAI 2010-10-07 07:42:40 +13:00
Chris Forbes
5af8f5e2d9 bots choose random colors 2010-10-07 07:41:14 +13:00
Caleb Anderson
c85503811c Clamp, scroll, scrollspeed, sliders
Reduced clamp duplication
Fixed scrolling speed issue
Modified scrollspeed slider to use a range
Fixed scrollspeed, volume, and sound sliders not showing current setting.
2010-10-06 20:53:56 +13:00
Chris Forbes
ab431fe9ee fix crash on warhead=null 2010-10-06 20:17:03 +13:00
Chris Forbes
7ec9958d47 hackyai should only attack humans 2010-10-06 20:04:36 +13:00
rasco
cfc74a6dee HackyAI: builds defense now. rally points are rechosen so units are more scattered in the base. builds only e1-3 and 1-3tnks. 2010-10-06 19:14:29 +13:00
Chris Forbes
cecdd73e08 destroy ore in all smudged cells 2010-10-06 18:37:32 +13:00
Chris Forbes
381e080b11 tweak nuke timing back 2010-10-06 18:32:33 +13:00
Chris Forbes
c6a047cb1a fix silent nukes 2010-10-06 18:29:05 +13:00
Chris Forbes
4c51733e04 actually add the cratenuke warhead 2010-10-06 18:25:07 +13:00
Chris Forbes
8f613b80e8 ban cloak crate on infantry 2010-10-06 18:16:09 +13:00
Chris Forbes
10de282daa add mechanism to exclude particular actor types from picking up any crate 2010-10-06 18:13:29 +13:00
Chris Forbes
915e123956 add minimum ranges for mig/yak/ca/msub/hind/v2rl/arty 2010-10-06 18:05:31 +13:00
Chris Forbes
8cb7a7b8ce add support for WeaponInfo.MinRange 2010-10-06 17:41:52 +13:00
Chris Forbes
ce5cf93077 prevent infantry going prone due to tib damage 2010-10-06 17:37:23 +13:00
Chris Forbes
1390bb7428 ra: reduce parabombs charge to 1min 2010-10-06 17:32:04 +13:00
Chris Forbes
3c5b136216 ra: reduce nuke charge time 13min -> 9 min 2010-10-06 17:29:45 +13:00
Chris Forbes
66785e606a ra: brik hp 1500 => 1000 2010-10-06 17:23:12 +13:00
Chris Forbes
e2239fa50c #215 obli misses moving units fixed 2010-10-06 17:22:11 +13:00
Chris Forbes
7f7712aa64 #203 dogs eating walls fixed 2010-10-06 17:20:20 +13:00
Chris Forbes
b1605e115a #206 badr/badr.bomber appear in tooltips 2010-10-06 17:15:52 +13:00
Chris Forbes
69b2da86be RA: +20% 4tnk HP 2010-10-06 17:13:39 +13:00
Chris Forbes
18e965e5aa fix desync on destroying ore storage buildings 2010-10-06 10:59:46 +13:00
Chris Forbes
24f0c28f56 fix massive player/client confusion after people drop 2010-10-06 10:59:45 +13:00
Paul Chote
25af51b4ac Prevent a race condition 2010-10-05 19:00:36 +13:00
Paul Chote
ecd7064cc3 Add an example mod that adds a soviet supply truck 2010-10-05 18:48:00 +13:00
Chris Forbes
477a21e782 fix 'minv/minp' showing up in tooltips 2010-10-05 17:58:30 +13:00
Chris Forbes
899d9af62b CNC: +25% HP on FACT/MCV 2010-10-05 17:58:29 +13:00
Paul Chote
17eca983ef Fix wall sell exploit 2010-10-05 17:56:30 +13:00
max621
2fc219ecd5 Fixed auto attack not working properly due to code expecting 'Idle' activity but most units use 'IdleAnimation' in RA mod 2010-10-05 17:45:29 +13:00
Chris Forbes
49a645cd2d fix ubuntu-64 support (Tao.FreeType was quite bogus.) 2010-10-05 17:42:13 +13:00
Matthew
7cb8da411d Updated git url to point to new upstream location. 2010-10-05 17:42:13 +13:00
Matthew
4bcdf3cf11 Netcode discussion from Etherpad. 2010-10-05 17:36:03 +13:00
Matthew
1b525ff809 Export FTP server and added username/password to VERSION file upload. 2010-10-05 17:36:03 +13:00
Caleb Anderson
cdec3fce26 Don't tell all players about my yaks 2010-10-05 17:25:30 +13:00
Caleb Anderson
7bdf6a953f New slider Range parameter. Palette modifications. Potential crash fix. Clamp function.
Range parameter added to slider. Supports returning a range of values
rather than just 0-1. Allows you to not have to post process the offset.
Modified palette selector to not have full range, which was causing
blown out units.
Introduced exension method Clamp<T>(min, max)
Fixed crash deserializing out of bound color value using above
extension.
2010-10-05 17:25:25 +13:00
Chris Forbes
06b20c8ba5 fix blatant wrongness in parallel builds 2010-10-02 20:55:43 +13:00
Paul Chote
9b484b53ec Show mod info in server browser 2010-10-02 20:37:25 +13:00
Paul Chote
9620b4ed46 Add mod metadata, and filter valid mods on startup. 2010-10-02 20:37:22 +13:00
Caleb Anderson
d8908c44d0 Nicer default ticker text 2010-10-02 01:13:55 -05:00
Caleb Anderson
cfe705531a Async motd grab. Client and server version in MasterServerQuery 2010-10-02 01:13:53 -05:00
Caleb Anderson
9a2fd38ab6 MOTD ticker. ScrollingText Widget 2010-10-02 01:13:51 -05:00
Chris Forbes
911e7f62de fix retardedly putting everyone in slot 0. 2010-10-02 18:33:29 +13:00
Chris Forbes
403b81bdc9 apply the balance stick to BIKE 2010-10-02 15:49:42 +13:00
Chris Forbes
a0714b00b3 a bit of cleanup 2010-10-02 15:49:42 +13:00
Chris Forbes
d5239ee77a add tib and spawns to new map 2010-10-02 15:49:41 +13:00
Chris Forbes
03ec97f302 unfinished 2v2 cnc map 2010-10-02 15:49:41 +13:00
Chris Forbes
3255f95ee9 ffs, more paths 2010-10-02 15:35:48 +13:00
Chris Forbes
4c8fd5e73d oops 2010-10-02 15:30:16 +13:00
Chris Forbes
7179ef0f45 fix packaging script 2010-10-02 15:19:14 +13:00
Alli
6d5918b11d Remove compiler warnings 2010-10-02 14:30:54 +13:00
Matthew Bowra-Dean
81c484d1c9 Fixed debian package prereqs 2010-10-02 13:28:22 +13:00
Chris Forbes
de1044c24c hack around imagelist deserialization being completely busted across platforms 2010-10-02 13:22:54 +13:00
Paul Chote
e4c31939d9 Save all settings to settings.yaml, not just non-defaults. 2010-10-02 12:15:15 +13:00
Paul Chote
7f48d6796e Fix scroll ticks 2010-10-02 12:01:11 +13:00
Matthew Bowra-Dean
4fd77aec8e Only add 'Latest:' text if query succeeds. 2010-10-02 11:39:56 +13:00
Matthew Bowra-Dean
92fece01de Added latest version information underneath current version in main menu. 2010-10-02 11:39:54 +13:00
geckosoft
d8d987f844 Fixed Settings menu issue (overlapping text) 2010-10-02 11:38:42 +13:00
unknown
de429a4c62 Added new setting : Scroll Speed (added to cnc & ra) 2010-10-02 11:38:39 +13:00
Chris Forbes
c0ca35a4ff fix AI jam in cnc 2010-10-02 11:33:50 +13:00
Chris Forbes
1bff8559fb pull HasAdequatePower out into a function 2010-10-02 11:33:47 +13:00
Chris Forbes
de98274165 fix #184 crashes while placing minefield 2010-10-02 11:33:04 +13:00
Chris Forbes
59e2228b2a shader fallback path for cg-2.1, which misinterprets 'latest' 2010-10-02 11:32:14 +13:00
geckosoft
96d1408d45 Fixed crash bug #197 2010-10-02 11:31:55 +13:00
Paul Chote
ff45ae2d16 Fix direct connect in cnc 2010-10-02 11:31:19 +13:00
Chris Forbes
47950c9113 Revert "remove setters on Mobile.{from,to}Cell. use SetLocation instead"
This reverts commit 911db3feb1.
2010-09-28 07:45:14 +13:00
Chris Forbes
f402ec7898 Revert "add IHasLocation"
This reverts commit 699b4b1154.
2010-09-28 07:43:49 +13:00
Chris Forbes
a3c0448e15 fix broken mac packaging script 2010-09-27 21:44:23 +13:00
Bob
699b4b1154 add IHasLocation 2010-09-26 18:17:23 +12:00
Bob
911db3feb1 remove setters on Mobile.{from,to}Cell. use SetLocation instead 2010-09-26 16:46:22 +12:00
Paul Chote
c790db8e84 Fix and bulletproof osx packaging script; cleanup some obsolete .gitignore entries 2010-09-26 10:18:22 +13:00
Bob
d6dd392028 use Invariant culture for float parsing (workaround a mono bug) 2010-09-26 09:11:26 +12:00
Bob
636b2a8ea7 fix Direct Connect window 2010-09-25 19:26:02 +12:00
Chris Forbes
959d3f8bd7 fix crash in giving a harv DeliverOre order after its proc has died, but it hasnt noticed yet 2010-09-25 07:34:51 +12:00
Matthew
193cb929f1 Fixing error with Windows package script launching 2010-09-24 22:12:26 +12:00
Chris Forbes
f93e270fe4 reduce v2 range and damage slightly 2010-09-24 21:49:26 +12:00
Chris Forbes
f19953c39a nerf ftrk heavily vs most ground, and reduce hp from 300 to 120 2010-09-24 21:44:57 +12:00
Matthew
59d5ce1bc8 +x permissions for checkout-and-build.sh 2010-09-24 20:42:29 +12:00
Matthew
43cf7cd074 Yet another packaging script. 2010-09-24 20:42:26 +12:00
Chris Forbes
aba76f4b50 don't look up resource type every cell for ore, too 2010-09-24 20:40:56 +12:00
Bob
8021fc3b20 Deduplicate shroud rendering code 2010-09-24 18:11:11 +12:00
Bob
7bf4cb85fa fix perf in ShroudRenderer 2010-09-24 18:11:08 +12:00
Bob
6dd03bb339 bugfix in ResourceLayer 2010-09-24 18:11:06 +12:00
Bob
14e517cab5 Autoflush renderer. Sprite.DrawAt convenience function. 2010-09-24 18:11:03 +12:00
Bob
cdcfeb6276 render perf improvement: BufferSubData, and don't use the same buffer back-to-back 2010-09-24 18:11:00 +12:00
Matthew
c77c63a380 Fix #130.
Windows installer now checks version of OpenAL32.dll and downloads and updates if necessary.
2010-09-24 16:40:55 +12:00
Matthew
9921fe8fad Linux package parallelisation. 2010-09-24 16:40:55 +12:00
Matthew
f848c5d7d4 Parallel building of packages. 2010-09-24 16:40:55 +12:00
Matthew
62c47e3b12 Reordered packaging platforms due to popular demand. 2010-09-24 16:40:55 +12:00
Matthew
094986d066 Tag prefixes change upload location for packages. 2010-09-24 16:40:55 +12:00
Chris Forbes
d87e02ab41 more tweaks, make DD a detector again (wtf?) 2010-09-23 22:23:39 +12:00
Chris Forbes
3f415a8fdf tweak torps more 2010-09-23 22:09:56 +12:00
Chris Forbes
846371cf3e homing torps, bubble trail 2010-09-23 22:09:56 +12:00
Chris Forbes
45c77e64ee fix various desyncs when using cheats 2010-09-23 22:09:55 +12:00
Bob
66493031c8 fix crash with idle units and pathdebug 2010-09-23 21:06:44 +12:00
Bob
384b26db60 fix fieldloader bug caused by foreach language-bug 2010-09-23 17:24:06 +12:00
Bob
d66dbeb312 removing unused stuff from TraitsInterfaces 2010-09-23 15:43:34 +12:00
Chris Forbes
ba9611f544 un-FP Building.cs power stuff 2010-09-22 21:43:04 +12:00
Chris Forbes
b6e56560d4 fix a crash in RepairIndicator with a dead building 2010-09-22 20:48:45 +12:00
Chris Forbes
1f047d439f back out editor icon hack -- it breaks the packaged editor on windows 2010-09-22 19:26:09 +12:00
Chris Forbes
5233ae4770 remove spam from Util.GetFacing 2010-09-22 19:21:22 +12:00
Chris Forbes
562e07264a remove lots of debug spam 2010-09-22 19:19:18 +12:00
Chris Forbes
4dab4ed73f reenable crates 2010-09-22 19:15:45 +12:00
Chris Forbes
a97ddffa53 fix cnc movement (argh) 2010-09-22 19:00:07 +12:00
Bob
8e589e3c16 fix infantry anims 2010-09-22 13:32:58 +12:00
Bob
96f72ce842 new map in ra_perf 2010-09-22 13:08:02 +12:00
Bob
d8de477edb fix IdleAnimation. add IsAttacking to AttackBase 2010-09-22 12:21:49 +12:00
Bob
694fb6831a fix target line on Move that has not yet calculated path 2010-09-22 12:03:45 +12:00
Bob
c16a515224 make more activities cancelable. remove many uses of CurrentActivity is T 2010-09-22 11:53:58 +12:00
Bob
e2eae7973b removing warning 2010-09-22 11:18:47 +12:00
Bob
9e3c938706 removing cancelable from Move. remove unnecessary qualified names from Production 2010-09-22 10:46:54 +12:00
Bob
ef665df2e9 refactor activity queueing 2010-09-22 10:13:13 +12:00
Bob
271a3eea8d fix harv 2010-09-22 08:49:56 +12:00
Bob
2f6315b816 make the pathfinder use integers 2010-09-22 08:04:52 +12:00
Bob
ac8d408ba7 allow queuing non-buildings while the queue is ready 2010-09-22 08:02:20 +12:00
Bob
0fdd49c96a MovePart becomes an Activity 2010-09-22 08:02:17 +12:00
Bob
e390cf8ab0 fix real-ra map importer when map isn't in game root 2010-09-22 08:02:15 +12:00
Bob
64d700cd70 make c&c work too 2010-09-22 08:02:12 +12:00
Bob
d3db9d3710 yes, i do want += 2010-09-22 08:02:09 +12:00
Bob
9eb05a43f9 show perf widget 2010-09-22 08:02:06 +12:00
Bob
3165ec5359 create widgets on demand 2010-09-22 08:02:03 +12:00
Bob
f4699132d6 made OpenWindow and CloseWindow static 2010-09-22 08:02:00 +12:00
Bob
086bdfb4bd new object creation logic 2010-09-22 08:01:57 +12:00
Chris Forbes
61fd12c7da oops; prev didnt run 2010-09-22 07:19:18 +12:00
Chris Forbes
9979209c34 more useful debug, less debug 2010-09-21 22:42:31 +12:00
Chris Forbes
b0c06d4cd9 force consistent conversion to float in a few places 2010-09-21 22:08:40 +12:00
Chris Forbes
3a617f8934 sync the last path generated, to try and catch this MUCH earlier 2010-09-21 21:43:16 +12:00
Chris Forbes
b35a7d9f8d stacktrace on set_Facing too 2010-09-21 21:06:37 +12:00
Chris Forbes
67fa079658 more debug 2010-09-21 21:05:28 +12:00
827 changed files with 26012 additions and 30352 deletions

16
.gitignore vendored
View File

@@ -12,20 +12,11 @@ mods/*/*.dll
# Red Alert binary files
mods/*/packages/*.[mM][iI][xX]
# Crap generated by OpenRa
sheet-*.png
log.txt
*.rep
#binary stuff
/*.dll
*.pdb
*.mdb
*.exe
OpenRA
OpenRA.app
*.vqa
# backup files by various editors
*~
@@ -33,10 +24,8 @@ OpenRA.app
# dependency DLLs (different for every platform!)
cg.dll
cgGL.dll
glfw.dll
/OpenRa.Gl.dll
settings.ini
#monodevelop
*.pidb
@@ -55,6 +44,9 @@ packaging/osx/launcher/OpenRA.xcodeproj/*.mode1v3
temp.c
temp.o
temp.s
OpenRA.Launcher.Mac/build/
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.pbxuser
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.perspectivev3
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
*.config
*.resources

View File

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

View File

@@ -68,7 +68,7 @@ to flush the renderer (if you want to see anything).
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be
able to save values changed in game into settings.ini (not yet implemented)
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA .
Bugs: There is a list of known bugs and features at http://bugs.open-ra.org/ .
We also have a website at http://www.open-ra.org/ .
@@ -76,7 +76,7 @@ Our IRC channel is #openra on irc.freenode.net .
As far as using git, get your own repository on github. You probably want to set up the gitbot
to spam irc when you make commits (its nice to know). Push your changes into your git
repository, and it will/might :P be merged into chrisforbes/OpenRA .
repository, and it will/might :P be merged into http://github.com/OpenRA/OpenRA .
See http://help.github.com/ for working with GitHub and see http://progit.org/ for working
with Git.

12
INSTALL
View File

@@ -37,7 +37,11 @@ These need to be copied into the mods/cnc/packages/ directory.
If you have a case-sensitive filesystem you must change the filenames to
lower case.
The files can be downloaded from:
http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and
http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files.
Alternatively:
Red Alert and C&C have been released by EA Games as freeware. They can be
downloaded from http://www.commandandconquer.com/classic
Unfortunately the installer is 16-bit and so wont run on 64-bit operating
@@ -55,8 +59,7 @@ WINDOWS:
* .NET Framework >= 3.5-SP1
(http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en)
* Tao Framework >= 2.1.0
(http://sourceforge.net/projects/taoframework/)
(required libs: Tao.OpenGL, Tao.Cg, Tao.Platform.Windows)
This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory.
* OpenAL >= 1.1
(http://connect.creativelabs.com/openal/Downloads/oalinst.zip)
* Cg Toolkit >= 2.2
@@ -83,8 +86,8 @@ UBUNTU (substitute comparable packages for other linux distros):
OpenRA is incompatible with Compiz, please disable desktop effects when trying
to run OpenRA or the game will crash.
You will need to copy the Tao dependencies (.dll and .config) from the
thirdparty/Tao directory into the game root, or install them permanently into
You will need to copy the third party dependencies (.dll and .config) from the
thirdparty and thirdparty/Tao directories into the game root, or install them permanently into
your GAC with the following script
#!/bin/sh
@@ -93,6 +96,7 @@ gacutil -i thirdparty/Tao/Tao.OpenGl.dll
gacutil -i thirdparty/Tao/Tao.OpenAl.dll
gacutil -i thirdparty/Tao/Tao.Sdl.dll
gacutil -i thirdparty/Tao/Tao.FreeType.dll
gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll
To compile OpenRA, run `make' from the command line.
Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert

344
Makefile
View File

@@ -1,7 +1,191 @@
CSC = gmcs
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
DEFINE = DEBUG;TRACE
PROGRAMS =fileformats gl game ra cnc seqed editor ralint filex tsbuild
CSC = gmcs
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
DEFINE = DEBUG;TRACE
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll thirdparty/ICSharpCode.SharpZipLib.dll
PHONY = core tools package all mods clean distclean
.SUFFIXES:
core: game renderers mod_ra mod_cnc
tools: editor ralint seqed filex tsbuild utility
package: fixheader core editor utility
mods: mod_ra mod_cnc
all: core tools
clean:
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
distclean: clean
#
# Core binaries
#
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
fileformats_TARGET = OpenRA.FileFormats.dll
#fileformats_DEPS = fixheader
fileformats_KIND = library
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll
PROGRAMS = fileformats
fileformats: $(fileformats_TARGET)
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
game_TARGET = OpenRA.Game.exe
game_KIND = winexe
game_DEPS = $(fileformats_TARGET)
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
PROGRAMS += game
game: $(game_TARGET)
#
# Renderer dlls
#
rcg_SRCS = $(shell find OpenRA.Renderer.Cg/ -iname '*.cs')
rcg_TARGET = OpenRA.Renderer.Cg.dll
rcg_KIND = library
rcg_DEPS = $(fileformats_TARGET) $(game_TARGET)
rcg_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
$(rcg_DEPS) $(game_TARGET)
rgl_SRCS = $(shell find OpenRA.Renderer.Gl/ -iname '*.cs')
rgl_TARGET = OpenRA.Renderer.Gl.dll
rgl_KIND = library
rgl_DEPS = $(fileformats_TARGET) $(game_TARGET)
rgl_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
$(rgl_DEPS) $(game_TARGET)
rnull_SRCS = $(shell find OpenRA.Renderer.Null/ -iname '*.cs')
rnull_TARGET = OpenRA.Renderer.Null.dll
rnull_KIND = library
rnull_DEPS = $(fileformats_TARGET) $(game_TARGET)
rnull_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
$(rnull_DEPS) $(game_TARGET)
PROGRAMS += rcg rgl rnull
renderers: $(rcg_TARGET) $(rgl_TARGET) $(rnull_TARGET)
#
# Official Mods
#
# Red Alert
mod_ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
mod_ra_KIND = library
mod_ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
mod_ra_LIBS = $(COMMON_LIBS) $(mod_ra_DEPS)
PROGRAMS += mod_ra
mod_ra: $(mod_ra_TARGET)
# mono RALint.exe ra
# Command and Conquer
mod_cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
mod_cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
mod_cnc_KIND = library
mod_cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(mod_ra_TARGET)
mod_cnc_LIBS = $(COMMON_LIBS) $(mod_cnc_DEPS)
PROGRAMS += mod_cnc
mod_cnc: $(mod_cnc_TARGET)
# mono RALint.exe cnc
#
# Tools
#
# Sequence editor (defunct)
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
seqed_TARGET = SequenceEditor.exe
seqed_KIND = winexe
seqed_DEPS = $(fileformats_TARGET)
seqed_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(seqed_DEPS)
seqed_EXTRA = -resource:SequenceEditor.Form1.resources
PROGRAMS += seqed
SequenceEditor.Form1.resources:
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
# Map Editor
editor_SRCS = $(shell find OpenRA.Editor/ -iname '*.cs')
editor_TARGET = OpenRA.Editor.exe
editor_KIND = winexe
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
PROGRAMS += editor
OpenRA.Editor.MapSelect.resources:
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
OpenRA.Editor.Form1.resources:
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
# Analyses mod yaml for easy to detect errors
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
ralint_TARGET = RALint.exe
ralint_KIND = exe
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
PROGRAMS += ralint
ralint: $(ralint_TARGET)
# Extracts files from packages (mixfiles, zips, etc)
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
filex_TARGET = FileExtractor.exe
filex_KIND = exe
filex_DEPS = $(fileformats_TARGET)
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
PROGRAMS += filex
filex: $(filex_TARGET)
# Builds and exports tilesets from a bitmap
tsbuild_SRCS = $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
tsbuild_TARGET = TilesetBuilder.exe
tsbuild_KIND = winexe
tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
PROGRAMS += tsbuild
OpenRA.TilesetBuilder.Form1.resources:
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
#
# Launchers / Utilities
#
# Patches binary headers to work around a mono bug
fixheader: packaging/fixheader.cs
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
PHONY += fixheader
# Backend for the launcher apps - queries game/mod info and applies actions to an install
utility_SRCS = $(shell find OpenRA.Utility/ -iname '*.cs')
utility_TARGET = OpenRA.Utility.exe
utility_KIND = exe
utility_DEPS = $(fileformats_TARGET) $(game_TARGET)
utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/ICSharpCode.SharpZipLib.dll System.Windows.Forms.dll
PROGRAMS += utility
utility: $(utility_TARGET)
.PHONY: $(PHONY) $(PROGRAMS)
#
# Generate build rules for each target defined above in PROGRAMS
#
define BUILD_ASSEMBLY
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS)
@echo CSC $$(@)
@$(CSC) $$($(1)_LIBS:%=-r:%) \
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
-define:"$(DEFINE)" \
-t:"$$($(1)_KIND)" \
$$($(1)_EXTRA) \
$$($(1)_SRCS)
@test -e fixheader.exe && mono fixheader.exe $$(@) || ``
endef
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
#
# Install / Uninstall for *nix
#
prefix = /usr/local
datarootdir = $(prefix)/share
datadir = $(datarootdir)
@@ -10,96 +194,15 @@ BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
INSTALL = install
INSTALL_PROGRAM = $(INSTALL)
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 thirdparty/WindowsBase.dll
gl_SRCS = $(shell find OpenRA.Gl/ -iname '*.cs')
gl_TARGET = OpenRA.Gl.dll
gl_KIND = library
gl_DEPS = $(fileformats_TARGET) $(game_TARGET)
gl_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
$(gl_DEPS) $(game_TARGET)
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
game_TARGET = OpenRA.Game.exe
game_KIND = winexe
game_DEPS = $(fileformats_TARGET)
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
ra_KIND = library
ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
ra_LIBS = $(COMMON_LIBS) $(ra_DEPS)
cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
cnc_KIND = library
cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
cnc_LIBS = $(COMMON_LIBS) $(cnc_DEPS)
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
seqed_TARGET = SequenceEditor.exe
seqed_KIND = winexe
seqed_DEPS = $(fileformats_TARGET)
seqed_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(seqed_DEPS)
seqed_EXTRA = -resource:SequenceEditor.Form1.resources
editor_SRCS = $(shell find OpenRA.Editor/ -iname '*.cs')
editor_TARGET = OpenRA.Editor.exe
editor_KIND = winexe
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
ralint_TARGET = RALint.exe
ralint_KIND = winexe
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
filex_TARGET = FileExtractor.exe
filex_KIND = winexe
filex_DEPS = $(fileformats_TARGET)
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
tsbuild_SRCS = $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
tsbuild_TARGET = TilesetBuilder.exe
tsbuild_KIND = winexe
tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
# -platform:x86
.SUFFIXES:
.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)
clean:
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
distclean: clean
CORE = fileformats gl game editor
CORE = fileformats rcg rgl rnull game editor utility
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/cnc
@$(INSTALL_PROGRAM) $(cnc_TARGET) $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) $(mod_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
@@ -108,9 +211,9 @@ install: all
@cp -r mods/cnc/sequences $(INSTALL_DIR)/mods/cnc
@cp -r mods/cnc/tilesets $(INSTALL_DIR)/mods/cnc
@cp -r mods/cnc/uibits $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
@$(INSTALL_PROGRAM) $(ra_TARGET) $(INSTALL_DIR)/mods/ra
@$(INSTALL_PROGRAM) $(mod_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/bits $(INSTALL_DIR)/mods/ra
@@ -118,69 +221,20 @@ install: all
@cp -r mods/ra/rules $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/tilesets $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/uibits $(INSTALL_DIR)/mods/ra
@cp -r shaders $(INSTALL_DIR)
@cp -r glsl $(INSTALL_DIR)
@cp -r cg $(INSTALL_DIR)
@cp *.ttf $(INSTALL_DIR)
@cp --parents -r thirdparty/Tao $(INSTALL_DIR)
@$(INSTALL_PROGRAM) thirdparty/WindowsBase.dll $(INSTALL_DIR)
@-$(INSTALL_PROGRAM) VERSION $(INSTALL_DIR)
@$(INSTALL_PROGRAM) thirdparty/ICSharpCode.SharpZipLib.dll $(INSTALL_DIR)
@echo "#!/bin/sh" > openra
@echo "cd "$(datadir)"/openra" >> 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)
@echo "OpenRA is now installed. You will now want to download"
@echo "http://open-ra.org/get-dependency.php?ra-packages and"
@echo "http://open-ra.org/get-dependency.php?cnc-packages"
@echo "and extract their contents to"
@echo "$(INSTALL_DIR)/mods/ra/packages and "
@echo "$(INSTALL_DIR)/mods/cnc/packages respectively."
@echo "It is also advised to install the contents of $(INSTALL_DIR)/thirdparty to the Mono Global Assembly Cache \
with gacutil."
uninstall:
@-rm -r $(INSTALL_DIR)
@-rm $(DESTDIR)$(bindir)/openra
mod_ra: $(ra_TARGET) $(ralint_TARGET)
mono RALint.exe ra
mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
mono RALint.exe cnc
mods: mod_ra mod_cnc
OpenRA.Editor.MapSelect.resources:
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
OpenRA.Editor.Form1.resources:
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
ralint: $(ralint_TARGET)
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
SequenceEditor.Form1.resources:
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
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 filex tsbuild
all: game tools
fixheader: packaging/fixheader.cs
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
define BUILD_ASSEMBLY
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS) fixheader
@echo CSC $$(@)
@$(CSC) $$($(1)_LIBS:%=-r:%) \
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
-define:"$(DEFINE)" \
-t:"$$($(1)_KIND)" \
$$($(1)_EXTRA) \
$$($(1)_SRCS)
@mono fixheader.exe $$(@)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Editor
{
public Bitmap Bitmap;
public ActorInfo Info;
public bool Centered;
public EditorAppearanceInfo Appearance;
}
class BrushTemplate

View File

@@ -0,0 +1,55 @@
#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;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ActorTool : ITool
{
ActorTemplate Actor;
public ActorTool(ActorTemplate actor) { this.Actor = actor; }
public void Preview(Surface surface, SGraphics g)
{
/* todo: include the player
* in the brush so we can color new buildings too */
surface.DrawActor(g, surface.GetBrushLocation(), Actor, null);
}
public void Apply(Surface surface)
{
if (surface.Map.Actors.Any(a => a.Value.Location() == surface.GetBrushLocation()))
return;
var owner = "Neutral";
var id = NextActorName(surface);
surface.Map.Actors[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant())
{
new LocationInit( surface.GetBrushLocation() ),
new OwnerInit( owner)
};
}
string NextActorName(Surface surface)
{
var id = 0;
for (; ; )
{
var possible = "Actor{0}".F(id++);
if (!surface.Map.Actors.ContainsKey(possible)) return possible;
}
}
}
}

124
OpenRA.Editor/BrushTool.cs Normal file
View File

@@ -0,0 +1,124 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class BrushTool : ITool
{
BrushTemplate Brush;
public BrushTool(BrushTemplate brush) { this.Brush = brush; }
public void Apply(Surface surface)
{
// change the bits in the map
var tile = surface.TileSet.Tiles[Brush.N];
var template = surface.TileSet.Templates[Brush.N];
var pos = surface.GetBrushLocation();
if (surface.GetModifiers() == Keys.Shift)
{
FloodFillWithBrush(surface, pos);
return;
}
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
{
if (surface.Map.IsInMap(new int2(u, v) + pos))
{
var z = u + v * template.Size.X;
if (tile.TileBitmapBytes[z] != null)
surface.Map.MapTiles[u + pos.X, v + pos.Y] =
new TileReference<ushort, byte>
{
type = Brush.N,
index = template.PickAny ? byte.MaxValue : (byte)z,
image = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z,
};
var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
}
}
public void Preview(Surface surface, SGraphics g)
{
g.DrawImage(Brush.Bitmap,
surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X,
surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y,
Brush.Bitmap.Width * surface.Zoom,
Brush.Bitmap.Height * surface.Zoom);
}
void FloodFillWithBrush(Surface s, int2 pos)
{
var queue = new Queue<int2>();
var replace = s.Map.MapTiles[pos.X, pos.Y];
var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y];
Action<int, int> MaybeEnqueue = (x, y) =>
{
if (s.Map.IsInMap(x, y) && !touched[x, y])
{
queue.Enqueue(new int2(x, y));
touched[x, y] = true;
}
};
queue.Enqueue(pos);
while (queue.Count > 0)
{
var p = queue.Dequeue();
if (!s.Map.MapTiles[p.X, p.Y].Equals(replace))
continue;
var a = FindEdge(s, p, new int2(-1, 0), replace);
var b = FindEdge(s, p, new int2(1, 0), replace);
for (var x = a.X; x <= b.X; x++)
{
s.Map.MapTiles[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, image = (byte)0, index = (byte)0 };
if (s.Map.MapTiles[x, p.Y - 1].Equals(replace))
MaybeEnqueue(x, p.Y - 1);
if (s.Map.MapTiles[x, p.Y + 1].Equals(replace))
MaybeEnqueue(x, p.Y + 1);
}
}
/* todo: optimize */
foreach (var ch in s.Chunks.Values) ch.Dispose();
s.Chunks.Clear();
}
int2 FindEdge(Surface s, int2 p, int2 d, TileReference<ushort, byte> replace)
{
for (; ; )
{
var q = p + d;
if (!s.Map.IsInMap(q)) return p;
if (!s.Map.MapTiles[q.X, q.Y].Equals(replace)) return p;
p = q;
}
}
}
}

923
OpenRA.Editor/Form1.Designer.cs generated Normal file → Executable file
View File

@@ -28,221 +28,248 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
this.pmMiniMap = new System.Windows.Forms.PictureBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tilePalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.actorPalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.resourcePalette = new System.Windows.Forms.FlowLayoutPanel();
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.mnuExport = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMinimapToPNG = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.exotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
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.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.layersFloaterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tt = new System.Windows.Forms.ToolTip(this.components);
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.surface1 = new OpenRA.Editor.Surface();
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.toolStripContainer1.ContentPanel.SuspendLayout();
this.toolStripContainer1.TopToolStripPanel.SuspendLayout();
this.toolStripContainer1.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.splitContainer2.Panel1.SuspendLayout();
this.splitContainer2.Panel2.SuspendLayout();
this.splitContainer2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).BeginInit();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// toolStripContainer1
//
//
// toolStripContainer1.ContentPanel
//
this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1);
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 727);
this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.toolStripContainer1.Location = new System.Drawing.Point(0, 0);
this.toolStripContainer1.Name = "toolStripContainer1";
this.toolStripContainer1.Padding = new System.Windows.Forms.Padding(0, 0, 0, 22);
this.toolStripContainer1.Size = new System.Drawing.Size(985, 773);
this.toolStripContainer1.TabIndex = 1;
this.toolStripContainer1.Text = "toolStripContainer1";
//
// toolStripContainer1.TopToolStripPanel
//
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip1);
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.splitContainer2);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.surface1);
this.splitContainer1.Size = new System.Drawing.Size(985, 727);
this.splitContainer1.SplitterDistance = 198;
this.splitContainer1.TabIndex = 0;
//
// splitContainer2
//
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
this.splitContainer2.Name = "splitContainer2";
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer2.Panel1
//
this.splitContainer2.Panel1.Controls.Add(this.pmMiniMap);
//
// splitContainer2.Panel2
//
this.splitContainer2.Panel2.Controls.Add(this.tabControl1);
this.splitContainer2.Size = new System.Drawing.Size(198, 727);
this.splitContainer2.SplitterDistance = 160;
this.splitContainer2.TabIndex = 1;
//
// pmMiniMap
//
this.pmMiniMap.BackColor = System.Drawing.Color.Black;
this.pmMiniMap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pmMiniMap.Dock = System.Windows.Forms.DockStyle.Fill;
this.pmMiniMap.Location = new System.Drawing.Point(0, 0);
this.pmMiniMap.Name = "pmMiniMap";
this.pmMiniMap.Size = new System.Drawing.Size(198, 160);
this.pmMiniMap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pmMiniMap.TabIndex = 1;
this.pmMiniMap.TabStop = false;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.Padding = new System.Drawing.Point(6, 0);
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(198, 563);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tilePalette);
this.tabPage1.Location = new System.Drawing.Point(4, 20);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(190, 539);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Templates";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tilePalette
//
this.tilePalette.AutoScroll = true;
this.tilePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.tilePalette.Location = new System.Drawing.Point(3, 3);
this.tilePalette.Name = "tilePalette";
this.tilePalette.Size = new System.Drawing.Size(184, 533);
this.tilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.actorPalette);
this.tabPage2.Location = new System.Drawing.Point(4, 20);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(190, 539);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Actors";
this.tabPage2.UseVisualStyleBackColor = true;
//
// actorPalette
//
this.actorPalette.AutoScroll = true;
this.actorPalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.actorPalette.Location = new System.Drawing.Point(3, 3);
this.actorPalette.Name = "actorPalette";
this.actorPalette.Size = new System.Drawing.Size(184, 533);
this.actorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.resourcePalette);
this.tabPage3.Location = new System.Drawing.Point(4, 20);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(190, 539);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Resources";
this.tabPage3.UseVisualStyleBackColor = true;
//
// resourcePalette
//
this.resourcePalette.AutoScroll = true;
this.resourcePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
this.resourcePalette.Name = "resourcePalette";
this.resourcePalette.Size = new System.Drawing.Size(190, 539);
this.resourcePalette.TabIndex = 3;
//
// menuStrip1
//
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
this.pmMiniMap = new System.Windows.Forms.PictureBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tilePalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.actorPalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.resourcePalette = new System.Windows.Forms.FlowLayoutPanel();
this.surface1 = new OpenRA.Editor.Surface();
this.tt = new System.Windows.Forms.ToolTip(this.components);
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.splitContainer3 = new System.Windows.Forms.SplitContainer();
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.mnuExport = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMinimapToPNG = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.exitToolStripMenuItem = 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.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.layersFloaterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripComboBox1 = new System.Windows.Forms.ToolStripComboBox();
this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabelFiller = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabelMousePosition = new System.Windows.Forms.ToolStripStatusLabel();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.splitContainer2.Panel1.SuspendLayout();
this.splitContainer2.Panel2.SuspendLayout();
this.splitContainer2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).BeginInit();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.splitContainer3.Panel1.SuspendLayout();
this.splitContainer3.Panel2.SuspendLayout();
this.splitContainer3.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.splitContainer2);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.surface1);
this.splitContainer1.Size = new System.Drawing.Size(985, 744);
this.splitContainer1.SplitterDistance = 198;
this.splitContainer1.TabIndex = 0;
//
// splitContainer2
//
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
this.splitContainer2.Name = "splitContainer2";
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer2.Panel1
//
this.splitContainer2.Panel1.Controls.Add(this.pmMiniMap);
//
// splitContainer2.Panel2
//
this.splitContainer2.Panel2.Controls.Add(this.tabControl1);
this.splitContainer2.Size = new System.Drawing.Size(198, 744);
this.splitContainer2.SplitterDistance = 164;
this.splitContainer2.TabIndex = 1;
//
// pmMiniMap
//
this.pmMiniMap.BackColor = System.Drawing.Color.Black;
this.pmMiniMap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pmMiniMap.Dock = System.Windows.Forms.DockStyle.Fill;
this.pmMiniMap.Location = new System.Drawing.Point(0, 0);
this.pmMiniMap.Name = "pmMiniMap";
this.pmMiniMap.Size = new System.Drawing.Size(198, 164);
this.pmMiniMap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pmMiniMap.TabIndex = 1;
this.pmMiniMap.TabStop = false;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.Padding = new System.Drawing.Point(6, 0);
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(198, 576);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tilePalette);
this.tabPage1.Location = new System.Drawing.Point(4, 20);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(190, 552);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Templates";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tilePalette
//
this.tilePalette.AutoScroll = true;
this.tilePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.tilePalette.Location = new System.Drawing.Point(3, 3);
this.tilePalette.Name = "tilePalette";
this.tilePalette.Size = new System.Drawing.Size(184, 546);
this.tilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.actorPalette);
this.tabPage2.Location = new System.Drawing.Point(4, 20);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(190, 552);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Actors";
this.tabPage2.UseVisualStyleBackColor = true;
//
// actorPalette
//
this.actorPalette.AutoScroll = true;
this.actorPalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.actorPalette.Location = new System.Drawing.Point(3, 3);
this.actorPalette.Name = "actorPalette";
this.actorPalette.Size = new System.Drawing.Size(184, 546);
this.actorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.resourcePalette);
this.tabPage3.Location = new System.Drawing.Point(4, 20);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(190, 552);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Resources";
this.tabPage3.UseVisualStyleBackColor = true;
//
// resourcePalette
//
this.resourcePalette.AutoScroll = true;
this.resourcePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
this.resourcePalette.Name = "resourcePalette";
this.resourcePalette.Size = new System.Drawing.Size(190, 552);
this.resourcePalette.TabIndex = 3;
//
// surface1
//
this.surface1.BackColor = System.Drawing.Color.Black;
this.surface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.surface1.Location = new System.Drawing.Point(0, 0);
this.surface1.Name = "surface1";
this.surface1.Size = new System.Drawing.Size(783, 744);
this.surface1.TabIndex = 5;
this.surface1.Text = "surface1";
//
// tt
//
this.tt.ShowAlways = true;
//
// saveFileDialog
//
this.saveFileDialog.DefaultExt = "*.png";
this.saveFileDialog.Filter = "PNG Image (*.png)|";
this.saveFileDialog.Title = "Export minimap to PNG";
//
// splitContainer3
//
this.splitContainer3.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer3.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer3.IsSplitterFixed = true;
this.splitContainer3.Location = new System.Drawing.Point(0, 0);
this.splitContainer3.Name = "splitContainer3";
this.splitContainer3.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer3.Panel1
//
this.splitContainer3.Panel1.Controls.Add(this.menuStrip1);
//
// splitContainer3.Panel2
//
this.splitContainer3.Panel2.Controls.Add(this.splitContainer1);
this.splitContainer3.Size = new System.Drawing.Size(985, 773);
this.splitContainer3.SplitterDistance = 25;
this.splitContainer3.TabIndex = 6;
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem,
this.mapToolStripMenuItem,
this.toolsToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(985, 24);
this.menuStrip1.TabIndex = 1;
this.menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolsToolStripMenuItem,
this.toolStripComboBox1,
this.toolStripLabel1});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(985, 27);
this.menuStrip1.TabIndex = 1;
this.menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.newToolStripMenuItem,
this.toolStripSeparator1,
this.openToolStripMenuItem,
@@ -252,233 +279,248 @@
this.toolStripMenuItem1,
this.mnuExport,
this.toolStripSeparator3,
this.exotToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20);
this.fileToolStripMenuItem.Text = "&File";
//
// newToolStripMenuItem
//
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);
//
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(122, 6);
//
// openToolStripMenuItem
//
this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image")));
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
this.openToolStripMenuItem.Size = new System.Drawing.Size(125, 22);
this.openToolStripMenuItem.Text = "&Open...";
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenClicked);
//
// saveToolStripMenuItem
//
this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image")));
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
this.saveToolStripMenuItem.Size = new System.Drawing.Size(125, 22);
this.saveToolStripMenuItem.Text = "&Save";
this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveClicked);
//
// saveAsToolStripMenuItem
//
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(125, 22);
this.saveAsToolStripMenuItem.Text = "Save &As...";
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsClicked);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(122, 6);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.exitToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 23);
this.fileToolStripMenuItem.Text = "&File";
//
// newToolStripMenuItem
//
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(123, 22);
this.newToolStripMenuItem.Text = "&New...";
this.newToolStripMenuItem.Click += new System.EventHandler(this.NewClicked);
//
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(120, 6);
//
// openToolStripMenuItem
//
this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image")));
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
this.openToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.openToolStripMenuItem.Text = "&Open...";
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenClicked);
//
// saveToolStripMenuItem
//
this.saveToolStripMenuItem.Enabled = false;
this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image")));
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
this.saveToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.saveToolStripMenuItem.Text = "&Save";
this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveClicked);
//
// saveAsToolStripMenuItem
//
this.saveAsToolStripMenuItem.Enabled = false;
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.saveAsToolStripMenuItem.Text = "Save &As...";
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsClicked);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(120, 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(125, 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(185, 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(185, 22);
this.bitmapToolStripMenuItem.Text = "&Bitmap...";
this.bitmapToolStripMenuItem.Visible = false;
//
// mnuExport
//
this.mnuExport.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(123, 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...";
this.bitmapToolStripMenuItem.Visible = false;
//
// mnuExport
//
this.mnuExport.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuMinimapToPNG});
this.mnuExport.Name = "mnuExport";
this.mnuExport.Size = new System.Drawing.Size(152, 22);
this.mnuExport.Text = "&Export";
//
// mnuMinimapToPNG
//
this.mnuMinimapToPNG.Image = ((System.Drawing.Image)(resources.GetObject("mnuMinimapToPNG.Image")));
this.mnuMinimapToPNG.Name = "mnuMinimapToPNG";
this.mnuMinimapToPNG.Size = new System.Drawing.Size(152, 22);
this.mnuMinimapToPNG.Text = "Minimap to PNG";
this.mnuMinimapToPNG.Click += new System.EventHandler(this.mnuMinimapToPNG_Click);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(122, 6);
//
// exotToolStripMenuItem
//
this.exotToolStripMenuItem.Name = "exotToolStripMenuItem";
this.exotToolStripMenuItem.Size = new System.Drawing.Size(125, 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.mnuExport.Name = "mnuExport";
this.mnuExport.Size = new System.Drawing.Size(123, 22);
this.mnuExport.Text = "&Export";
//
// mnuMinimapToPNG
//
this.mnuMinimapToPNG.Enabled = false;
this.mnuMinimapToPNG.Image = ((System.Drawing.Image)(resources.GetObject("mnuMinimapToPNG.Image")));
this.mnuMinimapToPNG.Name = "mnuMinimapToPNG";
this.mnuMinimapToPNG.Size = new System.Drawing.Size(163, 22);
this.mnuMinimapToPNG.Text = "Minimap to PNG";
this.mnuMinimapToPNG.Click += new System.EventHandler(this.ExportMinimap);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(120, 6);
//
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.exitToolStripMenuItem.Text = "E&xit";
this.exitToolStripMenuItem.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(39, 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(135, 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(135, 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(132, 6);
//
// spawnpointsToolStripMenuItem
//
this.spawnpointsToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("spawnpointsToolStripMenuItem.Image")));
this.spawnpointsToolStripMenuItem.Name = "spawnpointsToolStripMenuItem";
this.spawnpointsToolStripMenuItem.Size = new System.Drawing.Size(135, 22);
this.spawnpointsToolStripMenuItem.Text = "&Spawnpoints";
this.spawnpointsToolStripMenuItem.Click += new System.EventHandler(this.SpawnPointsClicked);
//
// toolsToolStripMenuItem
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mapToolStripMenuItem.Name = "mapToolStripMenuItem";
this.mapToolStripMenuItem.Size = new System.Drawing.Size(43, 23);
this.mapToolStripMenuItem.Text = "&Map";
//
// propertiesToolStripMenuItem
//
this.propertiesToolStripMenuItem.Enabled = false;
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.Enabled = false;
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.Enabled = false;
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);
//
// toolsToolStripMenuItem
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.layersFloaterToolStripMenuItem});
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
this.toolsToolStripMenuItem.Text = "Tools";
this.toolsToolStripMenuItem.Visible = false;
//
// layersFloaterToolStripMenuItem
//
this.layersFloaterToolStripMenuItem.Name = "layersFloaterToolStripMenuItem";
this.layersFloaterToolStripMenuItem.Size = new System.Drawing.Size(141, 22);
this.layersFloaterToolStripMenuItem.Text = "Layers floater";
this.layersFloaterToolStripMenuItem.Click += new System.EventHandler(this.layersFloaterToolStripMenuItem_Click);
//
// tt
//
this.tt.ShowAlways = true;
//
// statusStrip1
//
this.statusStrip1.Location = new System.Drawing.Point(0, 751);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(985, 22);
this.statusStrip1.TabIndex = 2;
this.statusStrip1.Text = "statusStrip1";
//
// surface1
//
this.surface1.BackColor = System.Drawing.Color.Black;
this.surface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.surface1.Location = new System.Drawing.Point(0, 0);
this.surface1.Name = "surface1";
this.surface1.Size = new System.Drawing.Size(783, 727);
this.surface1.TabIndex = 5;
this.surface1.Text = "surface1";
this.surface1.Click += new System.EventHandler(this.OnSurfaceClicked);
//
// saveFileDialog
//
this.saveFileDialog.DefaultExt = "*.png";
this.saveFileDialog.Filter = "PNG Image (*.png)|";
this.saveFileDialog.Title = "Export minimap to PNG";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(985, 773);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.toolStripContainer1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "OpenRA Editor";
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.toolStripContainer1.ContentPanel.ResumeLayout(false);
this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false);
this.toolStripContainer1.TopToolStripPanel.PerformLayout();
this.toolStripContainer1.ResumeLayout(false);
this.toolStripContainer1.PerformLayout();
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.splitContainer2.Panel1.ResumeLayout(false);
this.splitContainer2.Panel2.ResumeLayout(false);
this.splitContainer2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).EndInit();
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(48, 23);
this.toolsToolStripMenuItem.Text = "Tools";
this.toolsToolStripMenuItem.Visible = false;
//
// layersFloaterToolStripMenuItem
//
this.layersFloaterToolStripMenuItem.Name = "layersFloaterToolStripMenuItem";
this.layersFloaterToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
this.layersFloaterToolStripMenuItem.Text = "Layers floater";
this.layersFloaterToolStripMenuItem.Click += new System.EventHandler(this.layersFloaterToolStripMenuItem_Click);
//
// toolStripComboBox1
//
this.toolStripComboBox1.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.toolStripComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.toolStripComboBox1.Name = "toolStripComboBox1";
this.toolStripComboBox1.Size = new System.Drawing.Size(121, 23);
//
// toolStripLabel1
//
this.toolStripLabel1.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.toolStripLabel1.Name = "toolStripLabel1";
this.toolStripLabel1.Size = new System.Drawing.Size(71, 20);
this.toolStripLabel1.Text = "Active Mod:";
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabelFiller,
this.toolStripStatusLabelMousePosition});
this.statusStrip1.Location = new System.Drawing.Point(0, 751);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(985, 22);
this.statusStrip1.TabIndex = 7;
this.statusStrip1.Text = "statusStrip1";
//
// toolStripStatusLabelFiller
//
this.toolStripStatusLabelFiller.Name = "toolStripStatusLabelFiller";
this.toolStripStatusLabelFiller.Size = new System.Drawing.Size(948, 17);
this.toolStripStatusLabelFiller.Spring = true;
//
// toolStripStatusLabelMousePosition
//
this.toolStripStatusLabelMousePosition.Name = "toolStripStatusLabelMousePosition";
this.toolStripStatusLabelMousePosition.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
this.toolStripStatusLabelMousePosition.Size = new System.Drawing.Size(22, 17);
this.toolStripStatusLabelMousePosition.Text = "0,0";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(985, 773);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.splitContainer3);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "OpenRA Editor";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.splitContainer2.Panel1.ResumeLayout(false);
this.splitContainer2.Panel2.ResumeLayout(false);
this.splitContainer2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).EndInit();
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.splitContainer3.Panel1.ResumeLayout(false);
this.splitContainer3.Panel1.PerformLayout();
this.splitContainer3.Panel2.ResumeLayout(false);
this.splitContainer3.ResumeLayout(false);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ToolStripContainer toolStripContainer1;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.ToolTip tt;
private System.Windows.Forms.TabControl tabControl1;
@@ -489,32 +531,37 @@
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
private Surface surface1;
private System.Windows.Forms.PictureBox pmMiniMap;
private System.Windows.Forms.SplitContainer splitContainer2;
private System.Windows.Forms.SaveFileDialog saveFileDialog;
private System.Windows.Forms.SplitContainer splitContainer3;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelMousePosition;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelFiller;
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 openToolStripMenuItem;
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.ToolStripMenuItem mnuExport;
private System.Windows.Forms.ToolStripMenuItem mnuMinimapToPNG;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
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;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem layersFloaterToolStripMenuItem;
private System.Windows.Forms.PictureBox pmMiniMap;
private System.Windows.Forms.SplitContainer splitContainer2;
private System.Windows.Forms.ToolStripMenuItem mnuExport;
private System.Windows.Forms.ToolStripMenuItem mnuMinimapToPNG;
private System.Windows.Forms.SaveFileDialog saveFileDialog;
private System.Windows.Forms.ToolStripMenuItem spawnpointsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem layersFloaterToolStripMenuItem;
private System.Windows.Forms.ToolStripLabel toolStripLabel1;
private System.Windows.Forms.ToolStripComboBox toolStripComboBox1;
}
}

159
OpenRA.Editor/Form1.cs Normal file → Executable file
View File

@@ -10,7 +10,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
@@ -29,16 +28,40 @@ namespace OpenRA.Editor
currentMod = mods.FirstOrDefault() ?? "ra";
Text = "OpenRA Editor (mod:{0})".F(currentMod);
Game.modData = new ModData(currentMod);
Rules.LoadRules(Game.modData.Manifest, new Map());
surface1.AfterChange += MakeDirty;
toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray());
string path = Directory.GetCurrentDirectory();
Icon = new Icon(path + Path.DirectorySeparatorChar + "OpenRA.Editor" + Path.DirectorySeparatorChar + "OpenRA.Editor.Icon.ico");
toolStripComboBox1.SelectedIndexChanged += (_, e) =>
{
tilePalette.SuspendLayout();
actorPalette.SuspendLayout();
resourcePalette.SuspendLayout();
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
tilePalette.ResumeLayout();
actorPalette.ResumeLayout();
resourcePalette.ResumeLayout();
surface1.Bind(null, null, null);
pmMiniMap.Image = null;
currentMod = toolStripComboBox1.SelectedItem as string;
Text = "OpenRA Editor (mod:{0})".F(currentMod);
Game.modData = new ModData(currentMod);
FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map());
loadedMapName = null;
};
toolStripComboBox1.SelectedItem = currentMod;
surface1.AfterChange += OnMapChanged;
surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
}
void OnMapChanged()
{
MakeDirty();
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
}
void MakeDirty() { dirty = true; }
@@ -55,10 +78,8 @@ namespace OpenRA.Editor
loadedMapName = mapname;
Game.modData = new ModData(currentMod);
// load the map
var map = new Map(new Folder(mapname));
var map = new Map(mapname);
// upgrade maps that have no player definitions. editor doesnt care,
// but this breaks the game pretty badly.
@@ -78,9 +99,6 @@ namespace OpenRA.Editor
resourcePalette.Controls.Clear();
loadedMapName = null;
Game.modData = new ModData(currentMod);
PrepareMapResources(Game.modData.Manifest, map);
MakeDirty();
@@ -90,7 +108,7 @@ namespace OpenRA.Editor
void PrepareMapResources(Manifest manifest, Map map)
{
Rules.LoadRules(manifest, map);
tileset = Rules.TileSets[map.Theater];
tileset = Rules.TileSets[map.Tileset];
tileset.LoadTiles();
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
@@ -113,7 +131,7 @@ namespace OpenRA.Editor
};
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
ibox.Click += (_, e) => surface1.SetBrush(brushTemplate);
ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
var template = t.Value;
tilePalette.Controls.Add(ibox);
@@ -146,7 +164,7 @@ namespace OpenRA.Editor
};
ibox.Click += (_, e) => surface1.SetActor(template);
ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template));
actorPalette.Controls.Add(ibox);
@@ -179,7 +197,7 @@ namespace OpenRA.Editor
ibox.Click += (_, e) => surface1.SetResource(template);
ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template));
resourcePalette.Controls.Add(ibox);
@@ -200,7 +218,15 @@ namespace OpenRA.Editor
p.Visible = true;
p.ResumeLayout();
}
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
propertiesToolStripMenuItem.Enabled = true;
resizeToolStripMenuItem.Enabled = true;
spawnpointsToolStripMenuItem.Enabled = true;
saveToolStripMenuItem.Enabled = true;
saveAsToolStripMenuItem.Enabled = true;
mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here?
}
void ResizeClicked(object sender, EventArgs e)
@@ -209,16 +235,18 @@ namespace OpenRA.Editor
{
rd.width.Value = surface1.Map.MapSize.X;
rd.height.Value = surface1.Map.MapSize.Y;
rd.cordonLeft.Value = surface1.Map.TopLeft.X;
rd.cordonTop.Value = surface1.Map.TopLeft.Y;
rd.cordonRight.Value = surface1.Map.BottomRight.X;
rd.cordonBottom.Value = surface1.Map.BottomRight.Y;
rd.cordonLeft.Value = surface1.Map.Bounds.Left;
rd.cordonTop.Value = surface1.Map.Bounds.Top;
rd.cordonRight.Value = surface1.Map.Bounds.Right;
rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
if (DialogResult.OK != rd.ShowDialog())
return;
surface1.Map.TopLeft = new int2((int)rd.cordonLeft.Value, (int)rd.cordonTop.Value);
surface1.Map.BottomRight = new int2((int)rd.cordonRight.Value, (int)rd.cordonBottom.Value);
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
(int)rd.cordonTop.Value,
(int)rd.cordonRight.Value,
(int)rd.cordonBottom.Value);
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
{
@@ -237,7 +265,6 @@ namespace OpenRA.Editor
else
{
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
surface1.Map.Package = new Folder(loadedMapName);
surface1.Map.Save(loadedMapName);
dirty = false;
}
@@ -246,11 +273,8 @@ namespace OpenRA.Editor
void SaveAsClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect())
using (var nms = new MapSelect(currentMod))
{
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
nms.txtNew.ReadOnly = false;
nms.btnOk.Text = "Save";
nms.txtNew.Text = "unnamed";
@@ -261,18 +285,8 @@ namespace OpenRA.Editor
if (nms.txtNew.Text == "")
nms.txtNew.Text = "unnamed";
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
loadedMapName = mapfoldername;
try
{
Directory.CreateDirectory(mapfoldername);
}
catch (Exception ed)
{
MessageBox.Show("Directory creation failed: {0}", ed.ToString());
}
// TODO: Allow the user to choose map format (directory vs oramap)
loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap");
SaveClicked(sender, e);
}
}
@@ -280,20 +294,14 @@ namespace OpenRA.Editor
void OpenClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect())
using (var nms = new MapSelect(currentMod))
{
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
nms.txtNew.ReadOnly = true;
nms.txtPathOut.ReadOnly = true;
nms.btnOk.Text = "Open";
if (DialogResult.OK == nms.ShowDialog())
{
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
LoadMap(mapfoldername);
}
LoadMap(nms.txtNew.Tag as string);
}
}
@@ -307,12 +315,11 @@ namespace OpenRA.Editor
if (DialogResult.OK == nmd.ShowDialog())
{
var map = new Map(nmd.theater.SelectedItem as string);
var map = Map.FromTileset(nmd.theater.SelectedItem as string);
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
map.TopLeft = new int2((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value);
map.BottomRight = new int2((int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value,
(int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
NewMap(map);
}
@@ -327,6 +334,7 @@ namespace OpenRA.Editor
pd.desc.Text = surface1.Map.Description;
pd.author.Text = surface1.Map.Author;
pd.selectable.Checked = surface1.Map.Selectable;
pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap;
if (DialogResult.OK != pd.ShowDialog())
return;
@@ -335,10 +343,11 @@ namespace OpenRA.Editor
surface1.Map.Description = pd.desc.Text;
surface1.Map.Author = pd.author.Text;
surface1.Map.Selectable = pd.selectable.Checked;
surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked;
}
}
void SpawnPointsClicked(object sender, EventArgs e) { surface1.SetWaypoint(new WaypointTemplate()); }
void SpawnPointsClicked(object sender, EventArgs e) { surface1.SetTool(new WaypointTool(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; }
@@ -349,9 +358,11 @@ namespace OpenRA.Editor
void ImportLegacyMapClicked(object sender, EventArgs e)
{
var currentDirectory = Directory.GetCurrentDirectory();
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
if (DialogResult.OK == ofd.ShowDialog())
{
Directory.SetCurrentDirectory(currentDirectory);
/* massive hack: we should be able to call NewMap() with the imported Map object,
* but something's not right internally in it, unless loaded via the real maploader */
@@ -359,7 +370,6 @@ namespace OpenRA.Editor
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));
@@ -391,36 +401,13 @@ namespace OpenRA.Editor
pb.Show();
}
private void OnSurfaceClicked(object sender, EventArgs e)
void ExportMinimap(object sender, EventArgs e)
{
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
saveFileDialog.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps");
saveFileDialog.FileName = Path.ChangeExtension(loadedMapName, ".png");
if (DialogResult.OK == saveFileDialog.ShowDialog())
pmMiniMap.Image.Save(saveFileDialog.FileName);
}
private void mnuMinimapToPNG_Click(object sender, EventArgs e)
{
try
{
saveFileDialog.InitialDirectory = new string[] { Environment.CurrentDirectory, "maps" }
.Aggregate(Path.Combine);
FileInfo file = new FileInfo(loadedMapName + ".png");
string name = file.Name;
saveFileDialog.FileName = name;
saveFileDialog.ShowDialog();
if (saveFileDialog.FileName == "")
{
saveFileDialog.FileName = name;
}
else
{
Bitmap png = new Bitmap(pmMiniMap.Image);
png.Save(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch { }
}
}
}

14
OpenRA.Editor/Form1.resx Normal file → Executable file
View File

@@ -117,6 +117,12 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>76, 17</value>
</metadata>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>198, 17</value>
</metadata>
@@ -305,14 +311,8 @@
vP+uv56/AehVvkSccelEAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>307, 17</value>
</metadata>
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>76, 17</value>
<value>313, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>45</value>

View File

@@ -8,13 +8,13 @@
*/
#endregion
namespace OpenRA.Traits.Activities
{
class Idle : IActivity
{
public IActivity NextActivity { get; set; }
using SGraphics = System.Drawing.Graphics;
public IActivity Tick(Actor self) { return NextActivity; }
public void Cancel(Actor self) {}
namespace OpenRA.Editor
{
interface ITool
{
void Apply(Surface surface);
void Preview(Surface surface, SGraphics g);
}
}

View File

@@ -10,13 +10,13 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using OpenRA;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.Drawing;
namespace OpenRA.Editor
{
@@ -82,6 +82,7 @@ namespace OpenRA.Editor
// {"scrate","crate"},
};
// todo: fix this -- will have bitrotted pretty badly.
static Dictionary<string,Pair<Color,Color>> namedColorMapping = new Dictionary<string, Pair<Color, Color>>()
{
{"gold",Pair.New(Color.FromArgb(246,214,121),Color.FromArgb(40,32,8))},
@@ -401,13 +402,13 @@ namespace OpenRA.Editor
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit(parts[0]),
new HealthInit(float.Parse(parts[2])/256),
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
new ActorStanceInit(stance),
};
if (section == "INFANTRY")
actor.Add(new SubcellInit(int.Parse(parts[4])));
actor.Add(new SubCellInit(int.Parse(parts[4])));
Map.Actors.Add("Actor" + ActorCount++,actor);

View File

@@ -52,11 +52,13 @@
this.txtTitle = new System.Windows.Forms.TextBox();
this.lblMapName = new System.Windows.Forms.Label();
this.lblMinimap = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).BeginInit();
this.pnlBottom.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// MapList
@@ -85,9 +87,9 @@
//
// MapIconsList
//
this.MapIconsList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("MapIconsList.ImageStream")));
this.MapIconsList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
this.MapIconsList.ImageSize = new System.Drawing.Size(24, 24);
this.MapIconsList.TransparentColor = System.Drawing.Color.Transparent;
this.MapIconsList.Images.SetKeyName(0, "mapicon");
//
// btnCancel
//
@@ -141,6 +143,7 @@
//
// pnlBottom
//
this.pnlBottom.Controls.Add(this.pictureBox1);
this.pnlBottom.Controls.Add(this.txtPathOut);
this.pnlBottom.Controls.Add(this.lblPathOut);
this.pnlBottom.Controls.Add(this.lblPath);
@@ -253,7 +256,7 @@
this.lblTheater.Name = "lblTheater";
this.lblTheater.Size = new System.Drawing.Size(47, 13);
this.lblTheater.TabIndex = 11;
this.lblTheater.Text = "Theater:";
this.lblTheater.Text = "Tileset:";
//
// txtAuthor
//
@@ -301,6 +304,16 @@
this.lblMinimap.TabIndex = 6;
this.lblMinimap.Text = "Map preview:";
//
// pictureBox1
//
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(336, -9);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(54, 35);
this.pictureBox1.TabIndex = 7;
this.pictureBox1.TabStop = false;
this.pictureBox1.Visible = false;
//
// MapSelect
//
this.AcceptButton = this.btnOk;
@@ -327,6 +340,7 @@
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
this.splitContainer1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
@@ -356,5 +370,6 @@
public System.Windows.Forms.Label lblPathOut;
public System.Windows.Forms.Label lblPath;
public System.Windows.Forms.TextBox txtPathOut;
private System.Windows.Forms.PictureBox pictureBox1;
}
}

View File

@@ -1,14 +1,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using OpenRA.FileFormats;
using System.Windows.Forms;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using System.Linq;
namespace OpenRA.Editor
{
@@ -16,47 +11,48 @@ namespace OpenRA.Editor
{
public string MapFolderPath;
public MapSelect()
public MapSelect(string currentMod)
{
InitializeComponent();
MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
InitializeComponent();
MapIconsList.Images.Add(pictureBox1.Image);
}
private void MapSelect_Load(object sender, EventArgs e)
void MapSelect_Load(object sender, EventArgs e)
{
DirectoryInfo directory = new DirectoryInfo(MapFolderPath);
DirectoryInfo[] directories = directory.GetDirectories();
MapList.Items.Clear();
txtPathOut.Text = MapFolderPath;
foreach (DirectoryInfo subDirectory in directories)
foreach (var map in ModData.FindMapsIn(MapFolderPath))
{
ListViewItem map1 = new ListViewItem(subDirectory.Name);
ListViewItem map1 = new ListViewItem();
map1.Tag = map;
map1.Text = Path.GetFileNameWithoutExtension(map);
map1.ImageIndex = 0;
MapList.Items.Add(map1);
}
if (txtNew.Text == "unnamed")
{
//dumb indian code
}
else
{
// hack
if (txtNew.Text != "unnamed")
MapList.Items[0].Selected = true;
}
}
private void MapList_SelectedIndexChanged(object sender, EventArgs e)
void MapList_SelectedIndexChanged(object sender, EventArgs e)
{
if (MapList.SelectedItems.Count == 1)
{
txtNew.Text = MapList.SelectedItems[0].Text;
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text)));
txtNew.Tag = MapList.SelectedItems[0].Tag;
var map = new Map(txtNew.Tag as string);
txtTitle.Text = map.Title;
txtAuthor.Text = map.Author;
txtTheater.Text = map.Theater;
txtTheater.Text = map.Tileset;
txtDesc.Text = map.Description;
pbMinimap.Image = null;
try
{
pbMinimap.Image = Minimap.AddStaticResources(map, Minimap.TerrainBitmap(map, true));
@@ -69,7 +65,7 @@ namespace OpenRA.Editor
}
}
private void txtPathOut_TextChanged(object sender, EventArgs e)
void txtPathOut_TextChanged(object sender, EventArgs e)
{
MapFolderPath = txtPathOut.Text;
}

View File

@@ -120,73 +120,58 @@
<metadata name="MapIconsList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="MapIconsList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABW
DgAAAk1TRnQBSQFMAwEBAAEoAQABKAEAARgBAAEYAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABYAMA
ARgDAAEBAQABIAYAASQhAAEBAx8BLAM/AW8DSQGJAzYBWQMYASIDAQECDAADHQEqA0gBhQNCAXYDDwEU
AwEBAgMNARIDMwFSA0MBdwNRAacDDwEU/wAwAAEBAwMBBAM0BFQBwgFlAVMBUgH0AV4CWAHYA0oBjQMW
AR4DAgEDAwABAQMCAQMDGgElA00BlAEIAQkBJgH9A1ABpAM1AVcDQQFzA1MBugJDAVMB4wJTAVQBsgMA
AQH/ADAAAQEDDAEQA0IBdAFVAVQBUQHYAZkBiAGBAf8BoAGMAYUB/wF8AXABZQH4AzoBYQMKAQ4DCgEN
Ax0BKgM/AW0DVAG7ARkCGgH5AQABBQG/Af8BFwEbAUcB+QE5AUYBSwHrAQABBQFEAf8CCAFOAf0DDQER
/wAxAAMDAQQDHQEpA1ABpAFdAVMBUQHtAZsBiwGDAf8BnAGMAYQB/wGWAYQBdwH/AVsBWgFYAdgDMwFT
AzQBVANPAZ0CUwFSAdMCTAFOAfMBMAGeAbsB/wEUAXMBqwH/ARQBdQG/Af8BEAFmAbYB/wEXAY0BwgH/
AUgBYQFpAeEDAQEC/wAwAAEBAwkBDAMwAUwBVgJVAcMBewFqAWAB+gGoAZkBjwH/AZMBhAF3Af8BjAF3
AXAB/wGHAXEBbAH/A1YBvgNTAbwBTAFIAUYB5QF2AVsBUgH6AYMBbQFlAf8BUQFIAUcB/wEOAUsBpAH/
AQMBGgG4Af8BDQFRAZUB/wEZAZUBwAH/AUABagGBAesDMwFSAw0BEgMCAQP/ACUAAwEBAgMYASEDSwGP
A1EB3AGbAY4BhQH9AaEBkQGJAf8BhwFzAWsB/wGBAW4BZQH/AXUBZwFgAf8BUwFKAUMB/QFHAT4BOwH8
AZYBhgF5Af8BowGSAYoB/wFTAUoBUwH/AQMBGAHzAf8BEgFgAaYB/wEVAXYBlQH/AS8B/QH+Af8BBwEy
AZQB/wEVAXoByAH/AgABVAH/A00BlAMZASP/ACUAAwYBCAMtAUYDUwG8AWoBZQFiAfQBqgGbAZEB/wGJ
AXQBbQH/AYwBdwFuAf8BmgGJAYEB/wGLAXcBbwH/AXUBZQFeAf8BhgFxAWkB/wGVAYYBegH/AUEBPAFK
Af8BEwEfAYgB/wEKAREBrgH/ARwBegGVAf8BKgHfAeIB/wEOAVMBdwH/AQkBOQG8Af8BGQGBAaoB/wEK
ARIBqQH/ASABJQFSAfcDUQGg/wAlAAMQARUDQQFyA08B1gGTAYQBcgH9AZoBiQGDAf8BjwGAAXMB/wGW
AYYBeAH/AZ8BjQGEAf8BlgGFAXkB/wGUAYQBdwH/AZQBgwF3Af8BlwGHAYAB/wFqAV8BXAH/AWMBVwFW
Af8BYAFVAVMB/wFTAVcBWAH/ASIBYwGaAf8BDQFLAZ0B/wEgAY4BsAH/AUwBnAGvAf8BaAGaAa4B/wE7
AUsBWgH+A1ABn/8AJQADGAEiA00BlQF8AXUBbwH8AagBmAGOAf8BkQGBAXUB/wGNAXcBcAH/AZoBiQGB
Af8BkwGDAXYB/wGZAYgBgQH/AZwBiwGDAf8BlQGGAXgB/wGWAYYBeQH/AaABjwGHAf8BlgGFAXgB/wF2
AW8BbAH/AUwBbQGBAf8BHgE7AV0B/wEdAZ4BhAH/AVMBlwGpAf8BhgHFAd8B/wGIAb4B1wH/AUUBXwFi
AfsDQQFz/wAlAAMYASIDTQGVAZ0BjwGGAf8BmwGLAYMB/wGGAXEBagH/AYUBbwFoAf8BiAFzAWwB/wGJ
AXQBbAH/AZABdwFvAf8BlQGEAXcB/wGWAYUBeAH/AZ8BjwGGAf8BmQGLAYQB/wFtAYABhgH/AVYBkwGw
Af8BWgGmAccB/wFMAYMBpAH/AQUBFgGgAf8BYwGaAbAB/wGCAb8B2QH/AXEBrQHIAf8BXQFpAXIB3gMq
AUD/ACEAAwMBBAMmATgDUAGjAZoBjAGEAf8BpwGWAY4B/wGXAYYBegH/AZQBggF2Af8BlAGDAXcB/wGW
AYUBeAH/AZIBeQFyAf8BjwF5AXIB/wGVAYQBeAH/AY8BdgFrAf8BcAGAAYcB/wFaAZcBswH/AU8BmgHC
Af8BZQG1AdQB/wFlAaQBvgH/AR4BKgE1Af8BeAG6AdMB/wGAAbsB1QH/AYEBvwHaAf8BVQFWAVkBtQMP
ART/ACEAAwoBDQNBAXMDUgHPAasBmgGRAf8BmgGJAYIB/wGOAXgBcQH/AZEBgQF1Af8BlQGEAXcB/wGY
AYgBgAH/AYsBdQFuAf8BkQF6AXMB/wF4AW4BagH/AW8BrwHIAf8BWQGoAc0B/wFZAasBzAH/AVUBpgHJ
Af8BdQHDAeAB/wF6AcIB3wH/AYMBwAHbAf8BggHBAd0B/wFvAa4ByAH/AYsBvwHbAf8DSAGGAwUBB/8A
IQADHgErA1EBoAFSAVABTQHtAYMBbwFoAf8BgwFuAWcB/wGBAWwBZQH/AYEBbQFmAf8BiAFzAWsB/wGH
AXIBawH/AZQBhAF4Af8BhQF2AXMB/wFUAWwBgwH/AU0BhAGmAf8BZgGwAdAB/wFdAaoBywH/AWEBsQHR
Af8BdgG/Ad0B/wGFAcgB4wH/AYEBxAHfAf8BiAHHAeIB/wF3AbYB0QH/AW0BngG2Af8DPgFrAwIBA/8A
IQADOAFcA1UByAFrAlwB+AGRAYABdAH/AZgBiAGAAf8BlQGEAXgB/wGNAXcBcAH/AZUBhAF4Af8BmAGH
AYAB/wGTAYMBdwH/AWgBgAGLAf8BVgGQAbEB/wE3AUoBagH/AWMBqQHKAf8BYAGuAc8B/wFhAawBzAH/
AXYBvwHcAf8BiQHMAecB/wGDAcYB4gH/AYUBxQHgAf8BhwHDAd4B/wFIAYMBmwH/AzwBaAMEAQX/ACEA
A0kBiQFXAVYBVQHiAaQBkwGKAf8BrAGcAZMB/wGlAZUBjAH/AZYBhgF5Af8BkAF5AXQB/wGZAYgBgQH/
AaIBkQGJAf8BbgFdAVUB/wFkAZUBqwH/AWgBtQHVAf8BcgHBAd0B/wF0AbsB2wH/AV4BrAHOAf8BXwGt
AcwB/wF4AcMB4AH/AYgBywHmAf8BhQHGAeQB/wGDAcYB4gH/AYcBvwHdAf8BQwFVAWkB7gMbASb/ACUA
A08BpQFiAlgB7wGjAZMBigH/AZgBhwGAAf8BnwGOAYYB/wGdAYwBhAH/AZABeQFzAf8BiAFyAWsB/wGI
AXYBbwH/AWoBhQGPAf8BaAGwAdAB/wFvAbwB2gH/AWYBtgHWAf8BXwGxAdAB/wFdAa8B0AH/AXEBvQHa
Af8BcAG7AdoB/wGAAcQB3wH/AY8BzQHpAf8BigHJAeUB/wFbAZcBrAH9A0QBeQMAAQH/ACUAA1MBsQFs
Al8B8wGjAZIBigH/AZUBgwF4Af8BlAGCAXcB/wGUAYUBdwH/AYQBiwGNAf8BWwFzAYYB/wFcAYcBnQH/
AWEBrwHSAf8BbwG7AdoB/wF3AcEB3gH/AWwBuQHXAf8BYQGzAdIB/wFpAbkB1gH/AYABxQHhAf8BeAHC
Ad8B/wGAAcUB4QH/AYUBxAHhAf8BiQHGAeIB/wFSAXMBhAHzAzEBTv8AKQADUQHHAXsBcQFnAfgBqwGb
AZIB/wGQAYABdQH/AYQBbwFmAf8BcgGaAasB/wFiAasBzwH/AWQBsgHTAf8BbQG8AdoB/wFrAbgB1QH/
AXEBvgHbAf8BdgG/Ad0B/wFwAb4B2wH/AWgBuQHWAf8BgAHHAeEB/wGJAcsB5AH/AYoBzAHnAf8BjQHR
AewB/wGFAckB5gH/AW0BswHUAf8DTgGYAzABTAMAAQEDAAEB/wAhAAM+AWwBYgFfAV4ByQGJAYIBfAH1
AaQBkwGLAf8BhgGeAakB/wFnAa8B0gH/AXgBxAHgAf8BdgHCAd4B/wF2AcIB3gH/AXEBvwHbAf8BcwG8
AdoB/wFyAbsB2AH/AXQBuwHZAf8BdAG/Ad0B/wFhAZ0BwwH/AUEBYwGUAf8BbQGnAcgB/wGHAcQB4AH/
AYgBzQHpAf8BXwFxAXkB4AMsAUQDBwEJAwQBBgMAAQH/ACEAAwQBBQMZASMDNAFUA0oBiQFYAlsBwQFh
AXIBeQHiAW4BlwGoAfUBfQG0Ac8B/gGAAcUB4gH/AXIBvAHaAf8BcQG8AdoB/wFwAbsB2AH/AXUBvAHZ
Af8BjgHPAesB/wFtAa8B0gH/AU8BdQGkAf8BbAGrAc0B/wFuAa8BzwH/AY8BygHnAf8BWAFjAWYB0QMi
ATH/AD0AAwEBAgMJAQwDGgElA0IBdgFSAVwBZQHqAYEBxAHgAf4BigHHAeQB/wF5AcAB3QH/AYoBxgHi
Af8BlgHUAe4B/wF5AbgB1wH/AWEBoQHIAf8BaQGmAcwB/wFZAZIBvwH/AX8BwwHdAf4CRgFHAYEDAwEE
/wBJAAMCAQMDEAEWAzIBUANKAY0DUAGdA1IBoQFmAXUBewHgAXIBrwHFAf0BYAGXAb4B/wFgAZQBwAH/
AW8BqAHOAf8BQAF5AaoB/wM1AVYDAAEB/wBVAAMCAQMDBgEIAwoBDQMoAT0DQAFxAU8CUQGcAVsBYgFo
AdYBZQF/AZMB8gFKAX0BoQH8AyABL/8AcAABAQMIAQsDJAE2A0YBgQMDAQT/ADEAAUIBTQE+BwABPgMA
ASgDAAFgAwABGAMAAQEBAAEBBQABIAEBFgAD/wEAAeABOAEBCQABwAEAAQEJAAHAAQABAwkAAcABAAED
CQABgAsAAYALAAGACwABgAsAAYALAAGAPQABAQsAAQELAAEDIwABBwkAAfABAAEHCQAB/gEAAQcJAAH/
AcABDwkAAf8B/gEPCQAL
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAArjSURBVFhHrVcJUFRXFmVpkE0Wg0ZEMoIBl8RodGSMmVES
R0NiChVxCyIIAmFfhe6maeh9AZodZHFpUFQWcQmKisiuLKLEKFFEcIuljtZMYmI5Uc/c14EZYyapmpq8
qlP/9/+/373v3HPu+19P7/cf+jSlEWHCOEuzZfNn2Yvo3Pj3D/PTjCwYAwtgyeFwFk163Tos2tvtWJZw
zeUjmYFP6vL9fhw31vRPI8/9LnmMrtCWZhtPcJ7hbC/W8DwfnS0LR0t5NKoFazHcqsaprE3YGbMQLrYW
W/7fBAxogjGEd5wcXuPK4jxa60qD75VrfIbKMrYMD7VlPX/Ul49rp8RoyPbFIaEnhpuU6NRGoVa2HKuX
zEj/X8vAVmlIsDY2Nna2sjBd+ee5b7Yq4tfgfm8a7pxNw60OFa6e4uFmhxr/uFSIexfz0VsZh7PaIJzb
F42u8hAcV2/ANz3KF8Hub52kucb+Fv+jAccbm5quWOfxYX5y6Mcnq/IDh1oreX/vOcx9drdbjTudUgye
Tsb1piT0H4/DACUw0JiEh33ZePhlFi7UxOCLtI1o2x6IW2cUqM/egLtdediV9MnjSTYm60bE+Ys8rMzN
zd1c3/vLgVRV3lN1XjkqyzNoNaEUjIvrLXwMtQsw1JqEy/UxuHg0DJcp+KXj8bh0IobOucSGDA8vpqE6
+VNINixBU0kQbp5JJ8jxDSXdeyAE5arlAxTZ/BfRra2tS8Tqwh9L9tQhq6gSabm7odLkoP8oF90V/rjR
LsRgExc32oS40ZFCiQgw2Mgj+gW42pBI4OPSsUh6Jgn1mX4ojXJH865IXDzCx50uDe6fV+P8oQQ4Tx6r
pOATmVteKgdjXu/Mhk1h328rO4TMwn3gp2YhmquEX7gAfYfjcb4qGH0HQ3D5WAiunU7ApfpofH0ymhIS
UwkSqQRb6VoYvm6IZvXG7W4VBVbjwQU1/tanIQZkGDqtwOmSjzHXxXaLsZnZpy85QpdAnfunax/mllRD
ma2FQJyHxORMJAqzwBVpUJgtRLF8E7bxlqKjzA991QEYaIijgFwMt6VggJK60hCFr46F4sqprbjbLaf6
S0icIh1rwy1i3OvNQff+GEgj3r87/c1JLIGfjX1LP/F6KJDlIy1vN4SyQohVRdAU7IVIXQxuSiZ8/OOw
JYyP8EiqfV04Lh2JoHIwMSbiwoFgtO1ah97aTSTMKGIjDl/WhONWl5jKlYrbZ9OJGRWVIg/+axf8SK5a
8WoC5fPm//l2qqIIOaVVECm3QZG5C7L0HZCklYJLTCQKNUiWFYAnykJYRDRaywNxrTGRyhKNKyciiIEY
dFd743z1ZioT6eJkHK41kXDbRFSKbHzTpcJwsxoHc71fTLGzyBix+L/zUFlaWX+VTcFZ4NzSamQXV1Lw
EggkeeBRAsnSfKgyy6DKKcNnxEahIgRfHg5B/7EoDDYn4ma7FD0VAThfG4Cemi3EDI90IKWVq3GbHHKz
nUpCbrh6QokEr5mPTEw4773MQij9aPZY5fNYrC6hEhRAnrkTjJEkcS5ieWokS/IhUZdCrtlJbGQiIjQQ
/YeD0VMVhoTVbmgs8iVBctG11xtdlUHkDGpQpIN7velUAhmG2+W43spclI6K9JWY6TyxlGKOGxWjG53s
5HBMBpZ7+iI6UY44vhoiVTH4ohxCLoTyArqu1OlBll6CZHE20mI9EOjuis3L5uFCbTh6D4Wgu8offYeC
qSRccgcPD/qyMEiBb55VYahFgSuNckhjlr2YaGMqH2ntOiKmEAQGBgbnNviGPg2LFSM4UoiAUD78ghLo
yEVojBhRiQqEx0nAI5sKiBH/z+OgVfuic7c/Lh+NwZndfughDfQdCtL1hKFmEW51ymn1EjpSAh1ytFCL
Pl+nhKebY8XLTYn16DWEgzY2ttdzyI6yjB06+uP4acRANokvhzRRjBR5oe4aN4WupeYgNCIWZ2vj0b17
I/UKf3Tt34jOis9otTyyILmkORUDTRKyqxj9DSI07Y0k26Yhes38Roo3YVQH7OVhGiGR0K7O0epEqCRB
shKwRIQkQrZqMelAIM6ncihII9uQSCXZEi2HSMjDXvVqXKSGdTLbg6z6OVkwGcfLQvHB4jkYbJMS/UL0
1aeSM6So1Hg/oljTR93AupEVYSXhGE+soZa8X+cIlgALzFhg5/HJ6YhIzACXVs9EKiHRMmckSfMQGx0G
rXIldU4/dJSvJx3EoSDZC7OszHByTxTOfZGEq00y9B3lo70iElamhp4Ujy1eN8wIrEOd0BRW6DpiWEwq
giKSdYiIl5IOUskRKh39AmKECZNP7Mg0O6Ci59Pzd4O/NQK7FBvQULyGOmMUpBsX4KqjGTL5qzHQIqJy
iNG6Px5dtYlY7jqhmeKxvUE32C7FGKiP58uf5W6v0ekgPkmNrYIMor4YqcoinQBFdGQrl2ZsB4/cwBJR
Zml/+k0sxcQnQZzgDWHIIni9NQHSHU5IS15EPSEN11ok6G9UQs1dh/lvv/GdkZHR3NEETOhkIUE7zvb1
wRRFwYv0vD3UBTORJCEdSHMhydgFCXVHVnuWEGvZrDewjqmzKbHDNjHmFl5KBlasWokiFwtop5nhyL6p
2JO/CN2HBdSgMpHJ88GH82c8s7b4T1vmUPA3CFxCp19QzBPdtpxdRqon2kkDKRSYXeOJcyBUFMI7IJ70
kYsEgRLTXGbgrzNnwmWqC2Y4OsLZZjx43El4ggXI1zohy24MAFd4u9tj8YLpmD71DTiMtwGHY1A7ygB7
52N29CLULV7qeT+HnFCoPairu87/RC9rTjE8JYJoY/p4lR8lVQAp7Rc+/pHY7OKE61NN8a21MbQpfwC+
m4fbQ7MQNdcCfWMMsTPWDi2yyRgyNkDhOGPYGhpeo97jP5oAcwJjYQ4hk3DOyzvwn9v3HtUJjHXAzSFc
RHHlCAznIyAsCZa2k56u3xT2gtHPmGHCdXtnHh47mKBqjS1K5Q7ITrCjlf8RqXPM0bDUCr3bp2C9nj70
DDinKMYSwmujCbAjY4G9ZrN3tyMLP/D4IT1vP/J21CBeoKaa55MTUhAeK8J7i91v0DMdxqZmgw7Oc74N
iFQ8T5YX6ZzisWI9Uiebo8rKCOcsjLAv1Z72BydUxE5ElcTuKf2P9RunEeGzmD8bTIzsI0I7wc7xdgyf
NiayWVoueZ1qz7zPT8l5McnBqZieYZsYO/a4zF7yaKWP4HlASMKLj9xX4WrXWzhdMxUFlkaI1tPDAZE9
Htc4wWuhOas5Y/oXgUezYDdZdmK2N6zzCfuB1V1GFkulNswT5cFllms73f+QMIWwjCDjGJnUW1rbfu2z
wvXJk85pUH5gieNJdugvd8QV7RSc0TjgiMwevkvH3np1xa/+ZplZE9jecNh14UcPmO8VmnLyfzGr/feU
mB/dY7VjybItdSZhrb6+fvEYY6PuMWOMn7ZbGeILfQNYmnN+mO1o/OBdCw74HAMsMjR8NjL/r+Yx+p3H
XhjKZs93uxMZr4Z/uOb54qWf3bGf4pw3EpC1UPYsS3g0EU9K4uBsI86zYHPOY3MOp4zuRRLyDfT1O941
Mrzvb86Bob4h+0r6zcEmdiFICA2vvT55kLFBYOJhnYt9or06TOmCJ7HTbGxgADpndmaJMU29QxAQKvTo
vhnHkN1nX12/OlgCNoT3CZsIvgRWc9ao2IT/bTD3+BID7N1/zisBWCKOBB/CagKf8PboJP8CoUmu3yhA
ga8AAAAASUVORK5CYII=
</value>
</data>
</root>

View File

@@ -221,7 +221,7 @@
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(44, 13);
this.label4.TabIndex = 14;
this.label4.Text = "Theater";
this.label4.Text = "Tileset";
//
// theater
//

View File

@@ -13,8 +13,6 @@
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ApplicationIcon>OpenRA.Editor.Icon.ico</ApplicationIcon>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -56,12 +54,15 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ActorTemplate.cs" />
<Compile Include="ActorTool.cs" />
<Compile Include="BrushTool.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="ITool.cs" />
<Compile Include="LegacyMapImporter.cs" />
<Compile Include="MapSelect.cs">
<SubType>Form</SubType>
@@ -132,9 +133,11 @@
<Compile Include="ResizeDialog.Designer.cs">
<DependentUpon>ResizeDialog.cs</DependentUpon>
</Compile>
<Compile Include="ResourceTool.cs" />
<Compile Include="Surface.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="WaypointTool.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -11,6 +11,8 @@
using System;
using System.Globalization;
using System.Windows.Forms;
using System.Linq;
using System.IO;
namespace OpenRA.Editor
{
@@ -19,11 +21,32 @@ namespace OpenRA.Editor
[STAThread]
static void Main( string[] args )
{
if (args.Length >= 2 && args[0] == "--convert")
{
Game.modData = new ModData(args[1]);
Rules.LoadRules(Game.modData.Manifest, new Map());
UpgradeMaps(args[1]);
return;
}
Application.CurrentCulture = CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
static void UpgradeMaps(string mod)
{
var MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" }
.Aggregate(Path.Combine);
foreach (var path in ModData.FindMapsIn(MapFolderPath))
{
var map = new Map(path);
map.Save(path+".oramap");
}
}
}
}

View File

@@ -28,119 +28,131 @@
/// </summary>
private void InitializeComponent()
{
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.title = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.desc = new System.Windows.Forms.TextBox();
this.selectable = new System.Windows.Forms.CheckBox();
this.label3 = new System.Windows.Forms.Label();
this.author = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button2
//
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button2.DialogResult = System.Windows.Forms.DialogResult.OK;
this.button2.Location = new System.Drawing.Point(196, 193);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 14;
this.button2.Text = "OK";
this.button2.UseVisualStyleBackColor = true;
//
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button1.Location = new System.Drawing.Point(277, 193);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 15;
this.button1.Text = "Cancel";
this.button1.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 50);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(27, 13);
this.label1.TabIndex = 16;
this.label1.Text = "Title";
//
// title
//
this.title.Location = new System.Drawing.Point(66, 47);
this.title.Name = "title";
this.title.Size = new System.Drawing.Size(286, 20);
this.title.TabIndex = 17;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 76);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(32, 13);
this.label2.TabIndex = 16;
this.label2.Text = "Desc";
//
// desc
//
this.desc.Location = new System.Drawing.Point(66, 73);
this.desc.Name = "desc";
this.desc.Size = new System.Drawing.Size(286, 20);
this.desc.TabIndex = 17;
//
// selectable
//
this.selectable.AutoSize = true;
this.selectable.Location = new System.Drawing.Point(118, 138);
this.selectable.Name = "selectable";
this.selectable.Size = new System.Drawing.Size(130, 17);
this.selectable.TabIndex = 18;
this.selectable.Text = "Show in Map Chooser";
this.selectable.UseVisualStyleBackColor = true;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(12, 102);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(38, 13);
this.label3.TabIndex = 16;
this.label3.Text = "Author";
//
// author
//
this.author.Location = new System.Drawing.Point(66, 99);
this.author.Name = "author";
this.author.Size = new System.Drawing.Size(286, 20);
this.author.TabIndex = 17;
//
// PropertiesDialog
//
this.AcceptButton = this.button2;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.button1;
this.ClientSize = new System.Drawing.Size(370, 228);
this.Controls.Add(this.selectable);
this.Controls.Add(this.author);
this.Controls.Add(this.label3);
this.Controls.Add(this.desc);
this.Controls.Add(this.label2);
this.Controls.Add(this.title);
this.Controls.Add(this.label1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "PropertiesDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "PropertiesDialog";
this.ResumeLayout(false);
this.PerformLayout();
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.title = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.desc = new System.Windows.Forms.TextBox();
this.selectable = new System.Windows.Forms.CheckBox();
this.label3 = new System.Windows.Forms.Label();
this.author = new System.Windows.Forms.TextBox();
this.useAsShellmap = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// button2
//
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button2.DialogResult = System.Windows.Forms.DialogResult.OK;
this.button2.Location = new System.Drawing.Point(196, 193);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 14;
this.button2.Text = "OK";
this.button2.UseVisualStyleBackColor = true;
//
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button1.Location = new System.Drawing.Point(277, 193);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 15;
this.button1.Text = "Cancel";
this.button1.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 50);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(27, 13);
this.label1.TabIndex = 16;
this.label1.Text = "Title";
//
// title
//
this.title.Location = new System.Drawing.Point(66, 47);
this.title.Name = "title";
this.title.Size = new System.Drawing.Size(286, 20);
this.title.TabIndex = 17;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 76);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(32, 13);
this.label2.TabIndex = 16;
this.label2.Text = "Desc";
//
// desc
//
this.desc.Location = new System.Drawing.Point(66, 73);
this.desc.Name = "desc";
this.desc.Size = new System.Drawing.Size(286, 20);
this.desc.TabIndex = 17;
//
// selectable
//
this.selectable.AutoSize = true;
this.selectable.Location = new System.Drawing.Point(118, 138);
this.selectable.Name = "selectable";
this.selectable.Size = new System.Drawing.Size(130, 17);
this.selectable.TabIndex = 18;
this.selectable.Text = "Show in Map Chooser";
this.selectable.UseVisualStyleBackColor = true;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(12, 102);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(38, 13);
this.label3.TabIndex = 16;
this.label3.Text = "Author";
//
// author
//
this.author.Location = new System.Drawing.Point(66, 99);
this.author.Name = "author";
this.author.Size = new System.Drawing.Size(286, 20);
this.author.TabIndex = 17;
//
// checkBox1
//
this.useAsShellmap.AutoSize = true;
this.useAsShellmap.Location = new System.Drawing.Point(118, 161);
this.useAsShellmap.Name = "checkBox1";
this.useAsShellmap.Size = new System.Drawing.Size(105, 17);
this.useAsShellmap.TabIndex = 18;
this.useAsShellmap.Text = "Use as Shellmap";
this.useAsShellmap.UseVisualStyleBackColor = true;
//
// PropertiesDialog
//
this.AcceptButton = this.button2;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.button1;
this.ClientSize = new System.Drawing.Size(370, 228);
this.Controls.Add(this.useAsShellmap);
this.Controls.Add(this.selectable);
this.Controls.Add(this.author);
this.Controls.Add(this.label3);
this.Controls.Add(this.desc);
this.Controls.Add(this.label2);
this.Controls.Add(this.title);
this.Controls.Add(this.label1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "PropertiesDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "PropertiesDialog";
this.ResumeLayout(false);
this.PerformLayout();
}
@@ -155,5 +167,6 @@
public System.Windows.Forms.CheckBox selectable;
private System.Windows.Forms.Label label3;
public System.Windows.Forms.TextBox author;
public System.Windows.Forms.CheckBox useAsShellmap;
}
}

View File

@@ -8,6 +8,7 @@
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using OpenRA.FileFormats;
@@ -17,19 +18,34 @@ namespace OpenRA.Editor
{
static class RenderUtils
{
public static ColorPalette MakeSystemPalette(Palette p)
{
ColorPalette pal;
using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
pal = b.Palette;
for (var i = 0; i < 256; i++)
pal.Entries[i] = p.GetColor(i);
return pal;
}
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y);
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y,
PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
@@ -38,13 +54,13 @@ namespace OpenRA.Editor
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = p.GetColor(rawImage[i + ts.TileSize * j]).ToArgb();
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j];
}
else
{
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = Color.Transparent.ToArgb();
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0;
}
}
@@ -56,18 +72,21 @@ namespace OpenRA.Editor
{
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height);
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride2 = data.Stride >> 2;
byte* q = (byte*)data.Scan0.ToPointer();
var stride2 = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride2 + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);
@@ -77,14 +96,9 @@ namespace OpenRA.Editor
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
string image = null;
if (ri.OverrideTheater != null)
for (int i = 0; i < ri.OverrideTheater.Length; i++)
if (ri.OverrideTheater[i] == tileset.Id)
image = ri.OverrideImage[i];
image = image ?? ri.Image ?? info.Name;
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
var image = RenderSimple.GetImage(info, tileset.Id);
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var bitmap = RenderShp(shp, p);
@@ -102,7 +116,12 @@ namespace OpenRA.Editor
}
catch { }
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
return new ActorTemplate
{
Bitmap = bitmap,
Info = info,
Appearance = info.Traits.GetOrDefault<EditorAppearanceInfo>()
};
}
}
@@ -114,18 +133,19 @@ namespace OpenRA.Editor
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height);
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
q[j * stride + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);

View File

@@ -0,0 +1,51 @@
#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 SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ResourceTool : ITool
{
ResourceTemplate Resource;
public ResourceTool(ResourceTemplate resource) { Resource = resource; }
public void Apply(Surface surface)
{
surface.Map.MapResources[surface.GetBrushLocation().X, surface.GetBrushLocation().Y]
= new TileReference<byte, byte>
{
type = (byte)Resource.Info.ResourceType,
index = (byte)random.Next(Resource.Info.SpriteNames.Length),
image = (byte)Resource.Value
};
var ch = new int2((surface.GetBrushLocation().X) / Surface.ChunkSize,
(surface.GetBrushLocation().Y) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
public void Preview(Surface surface, SGraphics g)
{
surface.DrawImage(g, Resource.Bitmap, surface.GetBrushLocation(), false, null);
}
Random random = new Random();
}
}

View File

@@ -15,6 +15,9 @@ using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Traits;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
@@ -23,34 +26,34 @@ namespace OpenRA.Editor
public Map Map { get; private set; }
public TileSet TileSet { get; private set; }
public Palette Palette { get; private set; }
int2 Offset;
public int2 Offset;
float Zoom = 1.0f;
public int2 GetOffset() { return Offset; }
BrushTemplate Brush;
ActorTemplate Actor;
ResourceTemplate Resource;
WaypointTemplate Waypoint;
public float Zoom = 1.0f;
ITool Tool;
public bool IsPanning;
public event Action AfterChange = () => { };
public event Action<string> MousePositionChanged = _ => { };
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
public Keys GetModifiers() { return ModifierKeys; }
public void Bind(Map m, TileSet ts, Palette p)
{
Map = m;
TileSet = ts;
Palette = p;
Brush = null;
PlayerPalettes = null;
Chunks.Clear();
Tool = null;
}
public void SetBrush(BrushTemplate brush) { Actor = null; Brush = brush; Resource = null; Waypoint = null; }
public void SetActor(ActorTemplate actor) { Brush = null; Actor = actor; Resource = null; Waypoint = null; }
public void SetResource(ResourceTemplate resource) { Brush = null; Actor = null; Resource = resource; Waypoint = null; }
public void SetWaypoint(WaypointTemplate waypoint) { Brush = null; Actor = null; Resource = null; Waypoint = waypoint; }
public void SetTool(ITool tool) { Tool = tool; }
public void BindActorTemplates(IEnumerable<ActorTemplate> templates)
{
@@ -62,7 +65,7 @@ namespace OpenRA.Editor
ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType);
}
Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
public Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
public Surface()
: base()
@@ -87,6 +90,8 @@ namespace OpenRA.Editor
{
base.OnMouseWheel(e);
if (Map == null) return;
Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
Invalidate();
@@ -114,8 +119,11 @@ namespace OpenRA.Editor
{
base.OnMouseMove(e);
if (Map == null) return;
var oldMousePos = MousePos;
MousePos = new int2(e.Location);
MousePositionChanged(GetBrushLocation().ToString());
if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
Scroll(oldMousePos - MousePos);
@@ -131,110 +139,6 @@ namespace OpenRA.Editor
}
}
void FloodFillWithBrush(int2 pos)
{
var queue = new Queue<int2>();
var replace = Map.MapTiles[pos.X, pos.Y];
queue.Enqueue(pos);
while (queue.Count > 0)
{
var p = queue.Dequeue();
if (!Map.MapTiles[p.X, p.Y].Equals(replace))
continue;
var a = FindEdge(p, new int2(-1, 0), replace);
var b = FindEdge(p, new int2(1, 0), replace);
for (var x = a.X; x <= b.X; x++)
{
Map.MapTiles[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, image = (byte)0, index = (byte)0 };
if (Map.MapTiles[x, p.Y - 1].Equals(replace) && Map.IsInMap(x, p.Y - 1))
queue.Enqueue(new int2(x, p.Y - 1));
if (Map.MapTiles[x, p.Y + 1].Equals(replace) && Map.IsInMap(x, p.Y + 1))
queue.Enqueue(new int2(x, p.Y + 1));
}
}
/* todo: optimize */
foreach (var ch in Chunks.Values) ch.Dispose();
Chunks.Clear();
AfterChange();
}
int2 FindEdge(int2 p, int2 d, TileReference<ushort, byte> replace)
{
for (; ; )
{
var q = p+d;
if (!Map.IsInMap(q)) return p;
if (!Map.MapTiles[q.X, q.Y].Equals(replace)) return p;
p = q;
}
}
void DrawWithBrush()
{
// change the bits in the map
var tile = TileSet.Tiles[Brush.N];
var template = TileSet.Templates[Brush.N];
var pos = GetBrushLocation();
if (ModifierKeys == Keys.Shift)
{
FloodFillWithBrush(pos);
return;
}
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
{
if (Map.IsInMap(new int2(u, v) + pos))
{
var z = u + v * template.Size.X;
if (tile.TileBitmapBytes[z] != null)
Map.MapTiles[u + pos.X, v + pos.Y] =
new TileReference<ushort, byte>
{
type = Brush.N,
index = template.PickAny ? byte.MaxValue : (byte)z,
image = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4)*4) : (byte)z,
};
var ch = new int2((pos.X + u) / ChunkSize, (pos.Y + v) / ChunkSize);
if (Chunks.ContainsKey(ch))
{
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
}
}
AfterChange();
}
int wpid;
string NextWpid()
{
for (; ; )
{
var a = "wp{0}".F(wpid++);
if (!Map.Waypoints.ContainsKey(a))
return a;
}
}
void DrawWithWaypoint()
{
var k = Map.Waypoints.FirstOrDefault(a => a.Value == GetBrushLocation());
if (k.Key != null) Map.Waypoints.Remove(k.Key);
Map.Waypoints.Add(NextWpid(), GetBrushLocation());
AfterChange();
}
void Erase()
{
// Crash preventing
@@ -246,11 +150,8 @@ namespace OpenRA.Editor
BrushLocation.Y < 0)
return;
Actor = null;
Brush = null;
Resource = null;
Waypoint = null;
Tool = null;
var key = Map.Actors.FirstOrDefault(a => a.Value.Location() == BrushLocation);
if (key.Key != null) Map.Actors.Remove(key.Key);
@@ -273,58 +174,7 @@ namespace OpenRA.Editor
void Draw()
{
if (Brush != null) DrawWithBrush();
if (Actor != null) DrawWithActor();
if (Resource != null) DrawWithResource();
if (Waypoint != null) DrawWithWaypoint();
AfterChange();
}
int id;
string NextActorName()
{
for (; ; )
{
var possible = "Actor{0}".F(id++);
if (!Map.Actors.ContainsKey(possible)) return possible;
}
}
void DrawWithActor()
{
if (Map.Actors.Any(a => a.Value.Location() == GetBrushLocation()))
return;
var owner = "Neutral";
var id = NextActorName();
Map.Actors[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant())
{
new LocationInit( GetBrushLocation() ),
new OwnerInit( owner)
};
AfterChange();
}
System.Random r = new System.Random();
void DrawWithResource()
{
Map.MapResources[GetBrushLocation().X, GetBrushLocation().Y]
= new TileReference<byte, byte>
{
type = (byte)Resource.Info.ResourceType,
index = (byte)r.Next(Resource.Info.SpriteNames.Length),
image = (byte)Resource.Value
};
var ch = new int2((GetBrushLocation().X) / ChunkSize, (GetBrushLocation().Y) / ChunkSize);
if (Chunks.ContainsKey(ch))
{
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
if (Tool != null) Tool.Apply(this);
AfterChange();
}
@@ -332,6 +182,8 @@ namespace OpenRA.Editor
{
base.OnMouseDown(e);
if (Map == null) return;
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
@@ -341,7 +193,7 @@ namespace OpenRA.Editor
Invalidate();
}
const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
Bitmap RenderChunk(int u, int v)
{
@@ -394,88 +246,104 @@ namespace OpenRA.Editor
return bitmap;
}
int2 GetBrushLocation()
public int2 GetBrushLocation()
{
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
}
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t)
public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp)
{
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize/2 : 0;
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize/2 : 0;
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
float width = t.Bitmap.Width * Zoom;
float height = t.Bitmap.Height * Zoom;
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
g.DrawImage(t.Bitmap, destRect, sourceRect, GraphicsUnit.Pixel);
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
DrawImage(g, t.Bitmap, p, centered, cp);
}
void DrawImage(System.Drawing.Graphics g, Bitmap bmp, int2 location)
float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered)
{
float OffsetX = bmp.Width / 2 - TileSet.TileSize / 2;
float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
float OffsetY = bmp.Height / 2 - TileSet.TileSize / 2;
float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
float width = bmp.Width * Zoom;
float height = bmp.Height * Zoom;
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
return new float2(DrawX, DrawY);
}
public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp)
{
var drawPos = GetDrawPosition(location, bmp, centered);
var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom);
var restorePalette = bmp.Palette;
if (cp != null) bmp.Palette = cp;
g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
if (cp != null) bmp.Palette = restorePalette;
}
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
float width = t.Bitmap.Width * Zoom;
float height = t.Bitmap.Height * Zoom;
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
var drawPos = GetDrawPosition(p, t.Bitmap, centered);
g.DrawRectangle(CordonPen,
DrawX, DrawY,
drawPos.X, drawPos.Y,
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
}
ColorPalette GetPaletteForPlayer(string name)
{
var pr = Map.Players[name];
var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat);
return RenderUtils.MakeSystemPalette(new Palette(Palette, remap));
}
Cache<string, ColorPalette> PlayerPalettes;
ColorPalette GetPaletteForActor(ActorReference ar)
{
if (PlayerPalettes == null)
PlayerPalettes = new Cache<string, ColorPalette>(GetPaletteForPlayer);
var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>();
if (ownerInit == null)
return null;
return PlayerPalettes[ownerInit.PlayerName];
}
protected override void OnPaint(PaintEventArgs e)
{
if (Map == null) return;
if (TileSet == null) return;
for( var u = 0; u < Map.MapSize.X; u += ChunkSize )
for (var u = 0; u < Map.MapSize.X; u += ChunkSize)
for (var v = 0; v < Map.MapSize.Y; v += ChunkSize)
{
var x = new int2(u/ChunkSize,v/ChunkSize);
var x = new int2(u / ChunkSize, v / ChunkSize);
if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
Bitmap bmp = Chunks[x];
float DrawX = TileSet.TileSize* 1f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = TileSet.TileSize * 1f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
}
e.Graphics.DrawRectangle(CordonPen,
Map.XOffset * TileSet.TileSize * Zoom + Offset.X,
Map.YOffset * TileSet.TileSize * Zoom + Offset.Y,
Map.Width * TileSet.TileSize * Zoom,
Map.Height * TileSet.TileSize * Zoom);
Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
Map.Bounds.Width * TileSet.TileSize * Zoom,
Map.Bounds.Height * TileSet.TileSize * Zoom);
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],
GetPaletteForActor(ar.Value));
foreach (var wp in Map.Waypoints)
e.Graphics.DrawRectangle(Pens.LimeGreen,
@@ -483,26 +351,10 @@ namespace OpenRA.Editor
TileSet.TileSize * wp.Value.Y * Zoom + Offset.Y + 4,
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
if (Brush != null)
e.Graphics.DrawImage(Brush.Bitmap,
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X,
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y,
Brush.Bitmap.Width * Zoom,
Brush.Bitmap.Height * Zoom);
if (Actor != null)
DrawActor(e.Graphics, GetBrushLocation(), Actor);
if (Resource != null)
DrawImage(e.Graphics, Resource.Bitmap, GetBrushLocation());
if (Waypoint != null)
e.Graphics.DrawRectangle(Pens.LimeGreen,
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X + 4,
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y + 4,
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
if (Brush == null && Actor == null && Resource == null)
if (Tool != null)
Tool.Preview(this, e.Graphics);
if (Tool == null)
{
var x = Map.Actors.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (x.Key != null)

View File

@@ -0,0 +1,51 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using System.Linq;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class WaypointTool : ITool
{
WaypointTemplate Waypoint;
public WaypointTool(WaypointTemplate waypoint) { Waypoint = waypoint; }
public void Apply(Surface surface)
{
var k = surface.Map.Waypoints.FirstOrDefault(a => a.Value == surface.GetBrushLocation());
if (k.Key != null) surface.Map.Waypoints.Remove(k.Key);
surface.Map.Waypoints.Add(NextWpid(surface), surface.GetBrushLocation());
}
public void Preview(Surface surface, SGraphics g)
{
g.DrawRectangle(Pens.LimeGreen,
surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X + 4,
surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y + 4,
(surface.TileSet.TileSize - 8) * surface.Zoom, (surface.TileSet.TileSize - 8) * surface.Zoom);
}
public string NextWpid(Surface surface)
{
int wpid = 0;
for (; ; )
{
var a = "wp{0}".F(wpid++);
if (!surface.Map.Waypoints.ContainsKey(a))
return a;
}
}
}
}

View File

@@ -0,0 +1,64 @@
#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;
namespace OpenRA.FileFormats
{
public struct ColorRamp
{
public byte H,S,L,R;
public ColorRamp(byte h, byte s, byte l, byte r)
{
H = h; S = s; L = l; R = r;
}
/* returns a color along the Lum ramp */
public Color GetColor( float t )
{
return ColorFromHSL( H / 255f, S / 255f, float2.Lerp( L / 255f, L*R / (255f * 255f), t ) );
}
public override string ToString()
{
return "{0},{1},{2},{3}".F(H, S, L, R);
}
// hk is hue in the range [0,1] instead of [0,360]
public static Color ColorFromHSL(float hk, float s, float l)
{
// Convert from HSL to RGB
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
var p = 2 * l - q;
float[] trgb = { hk + 1 / 3.0f,
hk,
hk - 1/3.0f };
float[] rgb = { 0, 0, 0 };
for (int k = 0; k < 3; k++)
{
while (trgb[k] < 0) trgb[k] += 1.0f;
while (trgb[k] > 1) trgb[k] -= 1.0f;
}
for (int k = 0; k < 3; k++)
{
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
else { rgb[k] = p; }
}
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
}
}
}

View File

@@ -1,45 +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.IO;
using System.IO.Packaging;
using System.Linq;
namespace OpenRA.FileFormats
{
public class CompressedPackage : IFolder
{
readonly uint[] hashes;
readonly Stream s;
readonly ZipPackage pkg;
public CompressedPackage(string filename)
{
s = FileSystem.Open(filename);
pkg = (ZipPackage)ZipPackage.Open(s, FileMode.Open);
hashes = pkg.GetParts()
.Select(p => PackageEntry.HashFilename(p.Uri.LocalPath)).ToArray();
}
public Stream GetContent(string filename)
{
return pkg.GetPart(new Uri(filename)).GetStream(FileMode.Open);
}
public IEnumerable<uint> AllFileHashes() { return hashes; }
public bool Exists(string filename)
{
return hashes.Contains(PackageEntry.HashFilename(filename));
}
}
}

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

@@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -73,5 +74,37 @@ namespace OpenRA
{
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
}
public static T[] GetCustomAttributes<T>( this MemberInfo mi, bool inherit )
where T : class
{
return (T[])mi.GetCustomAttributes( typeof( T ), inherit );
}
public static T[] GetCustomAttributes<T>( this ParameterInfo mi )
where T : class
{
return (T[])mi.GetCustomAttributes( typeof( T ), true );
}
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0)
return min;
else if (val.CompareTo(max) > 0)
return max;
else
return val;
}
public static bool Contains(this Rectangle r, int2 p)
{
return r.Contains(p.ToPoint());
}
public static bool Contains(this RectangleF r, int2 p)
{
return r.Contains(p.ToPointF());
}
}
}

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

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace OpenRA.FileFormats
{
@@ -99,11 +100,19 @@ namespace OpenRA.FileFormats
else if (fieldType == typeof(float))
{
float res;
if (float.TryParse(x.Replace("%",""), out res))
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01f : 1f);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(decimal))
{
decimal res;
if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01m : 1m);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(string))
return x;
@@ -111,51 +120,64 @@ namespace OpenRA.FileFormats
{
var parts = x.Split(',');
if (parts.Length == 3)
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
if (parts.Length == 4)
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType.IsEnum)
{
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower()))
return InvalidValueAction(x,fieldType, field);
return Enum.Parse(fieldType, x, true);
}
else if (fieldType == typeof(ColorRamp))
{
var parts = x.Split(',');
if (parts.Length == 4)
return new ColorRamp(
(byte)int.Parse(parts[0]).Clamp(0, 255),
(byte)int.Parse(parts[1]).Clamp(0, 255),
(byte)int.Parse(parts[2]).Clamp(0, 255),
(byte)int.Parse(parts[3]).Clamp(0, 255));
else if (fieldType == typeof(bool))
return ParseYesNo(x, fieldType, field);
return InvalidValueAction(x, fieldType, field);
}
else if (fieldType.IsArray)
{
if (x == null)
return Array.CreateInstance(fieldType.GetElementType(), 0);
else if (fieldType.IsEnum)
{
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower()))
return InvalidValueAction(x, fieldType, field);
return Enum.Parse(fieldType, x, true);
}
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
else if (fieldType == typeof(bool))
return ParseYesNo(x, fieldType, field);
var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for (int i = 0; i < parts.Length; i++)
ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i);
return ret;
}
else if (fieldType == typeof(int2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
}
else if (fieldType == typeof(float2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float xx = 0;
float yy = 0;
float res;
if (float.TryParse(parts[0].Replace("%",""), out res))
xx = res * (parts[0].Contains( '%' ) ? 0.01f : 1f);
if (float.TryParse(parts[1].Replace("%",""), out res))
yy = res * (parts[1].Contains( '%' ) ? 0.01f : 1f);
return new float2(xx,yy);
}
else if (fieldType.IsArray)
{
if (x == null)
return Array.CreateInstance(fieldType.GetElementType(), 0);
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for (int i = 0; i < parts.Length; i++)
ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i);
return ret;
}
else if (fieldType == typeof(int2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
}
else if (fieldType == typeof(float2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float xx = 0;
float yy = 0;
float res;
if (float.TryParse(parts[0].Replace("%", ""), out res))
xx = res * (parts[0].Contains('%') ? 0.01f : 1f);
if (float.TryParse(parts[1].Replace("%", ""), out res))
yy = res * (parts[1].Contains('%') ? 0.01f : 1f);
return new float2(xx, yy);
}
UnknownFieldAction("[Type] {0}".F(x),fieldType);
return null;
@@ -177,11 +199,12 @@ namespace OpenRA.FileFormats
{
var ret = new Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>();
foreach( var field in type.GetFields() )
foreach( var ff in type.GetFields() )
{
var load = (LoadAttribute[])field.GetCustomAttributes( typeof( LoadAttribute ), false );
var loadUsing = (LoadUsingAttribute[])field.GetCustomAttributes( typeof( LoadUsingAttribute ), false );
var fromYamlKey = (FieldFromYamlKeyAttribute[])field.GetCustomAttributes( typeof( FieldFromYamlKeyAttribute ), false );
var field = ff;
var load = field.GetCustomAttributes<LoadAttribute>( false );
var loadUsing = field.GetCustomAttributes<LoadUsingAttribute>( false );
var fromYamlKey = field.GetCustomAttributes<FieldFromYamlKeyAttribute>( false );
if( loadUsing.Length != 0 )
ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml );
else if( fromYamlKey.Length != 0 )
@@ -252,6 +275,11 @@ namespace OpenRA.FileFormats
FormatValue( o, f ) ) ).ToList() );
}
public static MiniYamlNode SaveField(object o, string field)
{
return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) ));
}
public static string FormatValue(object o, FieldInfo f)
{
var v = f.GetValue(o);
@@ -262,7 +290,10 @@ namespace OpenRA.FileFormats
if (f.FieldType == typeof(Color))
{
var c = (Color)v;
return "{0},{1},{2},{3}".F(c.A,c.R,c.G,c.B);
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
((int)c.R).Clamp(0, 255),
((int)c.G).Clamp(0, 255),
((int)c.B).Clamp(0, 255));
}
return f.FieldType.IsArray

View File

@@ -0,0 +1,274 @@
#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.
*
* This file is based on the blast routines (version 1.1 by Mark Adler)
* included in zlib/contrib
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
public static class Blast
{
public static readonly int MAXBITS = 13; // maximum code length
public static readonly int MAXWIN = 4096; // maximum window size
static byte[] litlen = new byte[] {
11, 124, 8, 7, 28, 7, 188, 13, 76, 4,
10, 8, 12, 10, 12, 10, 8, 23, 8, 9,
7, 6, 7, 8, 7, 6, 55, 8, 23, 24,
12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
7, 24, 6, 11, 9, 6, 7, 22, 7, 11,
38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
8, 12, 5, 38, 5, 38, 5, 11, 7, 5,
6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
44, 253, 253, 253, 252, 252, 252, 13, 12, 45,
12, 45, 12, 61, 12, 45, 44, 173
};
// bit lengths of length codes 0..15
static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 };
// bit lengths of distance codes 0..63
static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 };
// base for length codes
static short[] lengthbase = new short[] {
3, 2, 4, 5, 6, 7, 8, 9, 10, 12,
16, 24, 40, 72, 136, 264
};
// extra bits for length codes
static byte[] extra = new byte[] {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
3, 4, 5, 6, 7, 8
};
static Huffman litcode = new Huffman(litlen, litlen.Length, 256);
static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16);
static Huffman distcode = new Huffman(distlen, distlen.Length, 64);
// Decode PKWare Compression Library stream.
public static byte[] Decompress(byte[] src)
{
BitReader br = new BitReader(src);
// Are literals coded?
int coded = br.ReadBits(8);
if (coded < 0 || coded > 1)
throw new NotImplementedException("Invalid datastream");
bool EncodedLiterals = (coded == 1);
// log2(dictionary size) - 6
int dict = br.ReadBits(8);
if (dict < 4 || dict > 6)
throw new InvalidDataException("Invalid dictionary size");
// output state
ushort next = 0; // index of next write location in out[]
bool first = true; // true to check distances (for first 4K)
byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window
var ms = new MemoryStream();
// decode literals and length/distance pairs
do
{
// length/distance pair
if (br.ReadBits(1) == 1)
{
// Length
int symbol = Decode(lencode, br);
int len = lengthbase[symbol] + br.ReadBits(extra[symbol]);
if (len == 519) // Magic number for "done"
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
break;
}
// Distance
symbol = len == 2 ? 2 : dict;
int dist = Decode(distcode, br) << symbol;
dist += br.ReadBits(symbol);
dist++;
if (first && dist > next)
throw new InvalidDataException("Attempt to jump before data");
// copy length bytes from distance bytes back
do
{
int dest = next;
int source = dest - dist;
int copy = MAXWIN;
if (next < dist)
{
source += copy;
copy = dist;
}
copy -= next;
if (copy > len)
copy = len;
len -= copy;
next += (ushort)copy;
Array.Copy(outBuffer, source, outBuffer, dest, copy);
// Flush window to outstream
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
} while (len != 0);
}
else // literal value
{
int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8);
outBuffer[next++] = (byte)symbol;
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
}
} while (true);
return ms.ToArray();
}
// Decode a code using huffman table h.
private static int Decode(Huffman h, BitReader br)
{
int code = 0; // len bits being decoded
int first = 0; // first code of length len
int index = 0; // index of first code of length len in symbol table
short next = 1;
while (true)
{
code |= br.ReadBits(1) ^ 1; // invert code
int count = h.Count[next++];
if (code < first + count)
return h.Symbol[index + (code - first)];
index += count;
first += count;
first <<= 1;
code <<= 1;
}
}
}
class BitReader
{
readonly byte[] src;
int offset = 0;
int bitBuffer = 0;
int bitCount = 0;
public BitReader(byte[] src)
{
this.src = src;
}
public int ReadBits(int count)
{
int ret = 0;
int filled = 0;
while (filled < count)
{
if (bitCount == 0)
{
bitBuffer = src[offset++];
bitCount = 8;
}
ret |= (bitBuffer & 1) << filled;
bitBuffer >>= 1;
bitCount--;
filled++;
}
return ret;
}
}
/*
* Given a list of repeated code lengths rep[0..n-1], where each byte is a
* count (high four bits + 1) and a code length (low four bits), generate the
* list of code lengths. This compaction reduces the size of the object code.
* Then given the list of code lengths length[0..n-1] representing a canonical
* Huffman code for n symbols, construct the tables required to decode those
* codes. Those tables are the number of codes of each length, and the symbols
* sorted by length, retaining their original order within each length.
*/
class Huffman
{
public short[] Count; // number of symbols of each length
public short[] Symbol; // canonically ordered symbols
public Huffman(byte[] rep, int n, short SymbolCount)
{
short[] length = new short[256]; // code lengths
int s = 0; // current symbol
// convert compact repeat counts into symbol bit length list
foreach (byte code in rep)
{
int num = (code >> 4) + 1; // Number of codes (top four bits plus 1)
byte len = (byte)(code & 15); // Code length (low four bits)
do
{
length[s++] = len;
} while (--num > 0);
}
n = s;
// count number of codes of each length
Count = new short[Blast.MAXBITS + 1];
for (int i = 0; i < n; i++)
Count[length[i]]++;
// no codes!
if (Count[0] == n)
return;
// check for an over-subscribed or incomplete set of lengths
int left = 1; // one possible code of zero length
for (int len = 1; len <= Blast.MAXBITS; len++)
{
left <<= 1;
// one more bit, double codes left
left -= Count[len];
// deduct count from possible codes
if (left < 0)
throw new InvalidDataException ("over subscribed code set");
}
// generate offsets into symbol table for each length for sorting
short[] offs = new short[Blast.MAXBITS + 1];
for (int len = 1; len < Blast.MAXBITS; len++)
offs[len + 1] = (short)(offs[len] + Count[len]);
// put symbols in table sorted by length, by symbol order within each length
Symbol = new short[SymbolCount];
for (short i = 0; i < n; i++)
if (length[i] != 0)
Symbol[offs[length[i]]++] = i;
}
}
}

View File

@@ -9,6 +9,7 @@
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
@@ -35,6 +36,8 @@ namespace OpenRA.FileFormats
Array.Copy(src, this.offset, dest, offset, count);
this.offset += count;
}
public int Remaining() { return src.Length - offset; }
}
public static class Format80
@@ -121,5 +124,27 @@ namespace OpenRA.FileFormats
}
}
}
public static byte[] Encode(byte[] src)
{
/* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */
/* this does not produce good compression, but it's valid format80 */
var ctx = new FastByteReader(src);
var ms = new MemoryStream();
do
{
var len = Math.Min(ctx.Remaining(), 0x3F);
ms.WriteByte((byte)(0x80 | len));
while (len-- > 0)
ms.WriteByte(ctx.ReadByte());
}
while (!ctx.Done());
ms.WriteByte(0x80); // terminator -- 0-length run.
return ms.ToArray();
}
}
}

View File

@@ -12,12 +12,14 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Linq;
namespace OpenRA.FileFormats
{
public static class FileSystem
{
static List<IFolder> mountedFolders = new List<IFolder>();
public static string SpecialPackageRoot = "";
static Cache<uint, List<IFolder>> allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
@@ -33,22 +35,50 @@ namespace OpenRA.FileFormats
}
}
static int order = 0;
static IFolder OpenPackage(string filename)
{
if (filename.EndsWith(".mix"))
return new Package(filename);
else if (filename.EndsWith(".zip"))
return new CompressedPackage(filename);
else
return new Folder(filename);
return OpenPackage(filename, order++);
}
public static IFolder CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order, content);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("Creating .Z archives is unsupported");
else
return new Folder(filename, order, content);
}
public static IFolder OpenPackage(string filename, int order)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
return new InstallShieldPackage(filename, order);
else
return new Folder(filename, order);
}
public static void Mount(string name)
{
name = name.ToLowerInvariant();
var optional = name.StartsWith("~");
if (optional) name = name.Substring(1);
// paths starting with $ are relative to SpecialPackageRoot
if (name.StartsWith("$"))
name = SpecialPackageRoot+name.Substring(1);
var a = (Action)(() => FileSystem.MountInner(OpenPackage(name)));
if (optional)
@@ -64,6 +94,16 @@ namespace OpenRA.FileFormats
allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
}
public static bool Unmount(IFolder mount)
{
return (mountedFolders.RemoveAll(f => f == mount) > 0);
}
public static void Mount(IFolder mount)
{
if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount);
}
public static void LoadFromManifest( Manifest manifest )
{
UnmountAll();
@@ -73,9 +113,14 @@ namespace OpenRA.FileFormats
static Stream GetFromCache( Cache<uint, List<IFolder>> index, string filename )
{
foreach( var folder in index[ PackageEntry.HashFilename( filename ) ] )
if (folder.Exists(filename))
return folder.GetContent(filename);
var folder = index[PackageEntry.HashFilename(filename)]
.Where(x => x.Exists(filename))
.OrderBy(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
return null;
}
@@ -88,11 +133,13 @@ namespace OpenRA.FileFormats
return ret;
}
foreach( IFolder folder in mountedFolders )
{
if (folder.Exists(filename))
return folder.GetContent(filename);
}
var folder = mountedFolders
.Where(x => x.Exists(filename))
.OrderByDescending(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}

View File

@@ -0,0 +1,73 @@
#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.IO;
using System;
namespace OpenRA.FileFormats
{
public class Folder : IFolder
{
readonly string path;
int priority;
// Create a new folder package
public Folder(string path, int priority, Dictionary<string, byte[]> contents)
{
this.path = path;
this.priority = priority;
if (Directory.Exists(path))
Directory.Delete(path);
Write(contents);
}
public Folder(string path, int priority)
{
this.path = path;
this.priority = priority;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
public Stream GetContent(string filename)
{
try { return File.OpenRead( Path.Combine( path, filename ) ); }
catch { return null; }
}
public IEnumerable<uint> AllFileHashes()
{
foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) )
yield return PackageEntry.HashFilename( Path.GetFileName(filename) );
}
public bool Exists(string filename)
{
return File.Exists(Path.Combine(path,filename));
}
public int Priority
{
get { return priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
foreach (var file in contents)
using (var dataStream = File.Create(Path.Combine(path, file.Key)))
using (var writer = new BinaryWriter(dataStream))
writer.Write(file.Value);
}
}
}

View File

@@ -0,0 +1,126 @@
#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.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
public class InstallShieldPackage : IFolder
{
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly Stream s;
readonly long dataStart = 255;
int priority;
public InstallShieldPackage(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
// Parse package header
BinaryReader reader = new BinaryReader(s);
uint signature = reader.ReadUInt32();
if (signature != 0x8C655D13)
throw new InvalidDataException("Not an Installshield package");
reader.ReadBytes(8);
/*var FileCount = */reader.ReadUInt16();
reader.ReadBytes(4);
/*var ArchiveSize = */reader.ReadUInt32();
reader.ReadBytes(19);
var TOCAddress = reader.ReadInt32();
reader.ReadBytes(4);
var DirCount = reader.ReadUInt16();
// Parse the directory list
s.Seek(TOCAddress, SeekOrigin.Begin);
BinaryReader TOCreader = new BinaryReader(s);
for (var i = 0; i < DirCount; i++)
ParseDirectory(TOCreader);
}
void ParseDirectory(BinaryReader reader)
{
// Parse directory header
var FileCount = reader.ReadUInt16();
var ChunkSize = reader.ReadUInt16();
var NameLength = reader.ReadUInt16();
reader.ReadChars(NameLength); //var DirName = new String(reader.ReadChars(NameLength));
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 6);
// Parse files
for (var i = 0; i < FileCount; i++)
ParseFile(reader);
}
uint AccumulatedData = 0;
void ParseFile(BinaryReader reader)
{
reader.ReadBytes(7);
var CompressedSize = reader.ReadUInt32();
reader.ReadBytes(12);
var ChunkSize = reader.ReadUInt16();
reader.ReadBytes(4);
var NameLength = reader.ReadByte();
var FileName = new String(reader.ReadChars(NameLength));
var hash = PackageEntry.HashFilename(FileName);
index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize));
AccumulatedData += CompressedSize;
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 30);
}
public Stream GetContent(uint hash)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
return null;
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
byte[] data = new byte[ e.Length ];
s.Read( data, 0, (int)e.Length );
return new MemoryStream(Blast.Decompress(data));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename));
}
public IEnumerable<uint> AllFileHashes()
{
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 2000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save InstallShieldPackages.");
}
}
}

View File

@@ -20,17 +20,32 @@ namespace OpenRA.FileFormats
Stream GetContent(string filename);
bool Exists(string filename);
IEnumerable<uint> AllFileHashes();
void Write(Dictionary<string, byte[]> contents);
int Priority { get; }
}
public class Package : IFolder
public class MixFile : IFolder
{
readonly Dictionary<uint, PackageEntry> index;
readonly bool isRmix, isEncrypted;
readonly long dataStart;
readonly Stream s;
public Package(string filename)
int priority;
// Create a new MixFile
public MixFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
if (File.Exists(filename))
File.Delete(filename);
s = File.Create(filename);
Write(contents);
}
public MixFile(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
BinaryReader reader = new BinaryReader(s);
@@ -149,6 +164,51 @@ namespace OpenRA.FileFormats
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 1000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
// Cannot modify existing mixfile - rename existing file and
// create a new one with original content plus modifications
FileSystem.Unmount(this);
// TODO: Add existing data to the contents list
if (index.Count > 0)
throw new NotImplementedException("Updating mix files unfinished");
// Construct a list of entries for the file header
uint dataSize = 0;
var items = new List<PackageEntry>();
foreach (var kv in contents)
{
uint length = (uint)kv.Value.Length;
uint hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key));
items.Add(new PackageEntry(hash, dataSize, length));
dataSize += length;
}
// Write the new file
s.Seek(0,SeekOrigin.Begin);
using (var writer = new BinaryWriter(s))
{
// Write file header
writer.Write((ushort)items.Count);
writer.Write(dataSize);
foreach (var item in items)
item.Write(writer);
writer.Flush();
// Copy file data
foreach (var file in contents)
s.Write(file.Value);
}
}
}
[Flags]

View File

@@ -0,0 +1,117 @@
#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.IO;
using ICSharpCode.SharpZipLib.Zip;
using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
namespace OpenRA.FileFormats
{
public class ZipFile : IFolder
{
string filename;
SZipFile pkg;
int priority;
public ZipFile(string filename, int priority)
{
this.filename = filename;
this.priority = priority;
try
{
// pull the file into memory, dont keep it open.
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
catch (ZipException e)
{
Log.Write("debug", "Couldn't load zip file: {0}", e.Message);
}
}
// Create a new zip with the specified contents
public ZipFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
this.filename = filename;
if (File.Exists(filename))
File.Delete(filename);
pkg = SZipFile.Create(filename);
Write(contents);
}
public Stream GetContent(string filename)
{
using (var z = pkg.GetInputStream(pkg.GetEntry(filename)))
{
var ms = new MemoryStream();
int bufSize = 2048;
byte[] buf = new byte[bufSize];
while ((bufSize = z.Read(buf, 0, buf.Length)) > 0)
ms.Write(buf, 0, bufSize);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
public IEnumerable<uint> AllFileHashes()
{
foreach(ZipEntry entry in pkg)
yield return PackageEntry.HashFilename(entry.Name);
}
public bool Exists(string filename)
{
return pkg.GetEntry(filename) != null;
}
public int Priority
{
get { return 500 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
pkg.Close();
pkg = SZipFile.Create(filename);
pkg.BeginUpdate();
// TODO: Clear existing content?
foreach (var kvp in contents)
pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key);
pkg.CommitUpdate();
pkg.Close();
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
}
class StaticMemoryDataSource : IStaticDataSource
{
byte[] data;
public StaticMemoryDataSource (byte[] data)
{
this.data = data;
}
public Stream GetSource()
{
return new MemoryStream(data);
}
}
}

View File

@@ -1,39 +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.IO;
namespace OpenRA.FileFormats
{
public class Folder : IFolder
{
readonly string path;
public Folder(string path) { this.path = path; }
public Stream GetContent(string filename)
{
try { return File.OpenRead( Path.Combine( path, filename ) ); }
catch { return null; }
}
public IEnumerable<uint> AllFileHashes()
{
foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) )
yield return PackageEntry.HashFilename( filename );
}
public bool Exists(string filename)
{
return File.Exists(Path.Combine(path,filename));
}
}
}

View File

@@ -33,14 +33,12 @@ namespace OpenRA.FileFormats.Graphics
IIndexBuffer CreateIndexBuffer( int length );
ITexture CreateTexture( Bitmap bitmap );
ITexture CreateTexture();
IShader CreateShader( Stream stream );
IShader CreateShader( string name );
Size WindowSize { get; }
void Begin();
void End();
void Clear( Color color );
void Present();
void Present( IInputHandler inputHandler );
void DrawIndexedPrimitives( PrimitiveType type, Range<int> vertexRange, Range<int> indexRange );
void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives );
@@ -52,13 +50,13 @@ namespace OpenRA.FileFormats.Graphics
public interface IVertexBuffer<T>
{
void Bind();
void SetData( T[] vertices );
void SetData( T[] vertices, int length );
}
public interface IIndexBuffer
{
void Bind();
void SetData( ushort[] indices );
void SetData( ushort[] indices, int length );
}
public interface IShader

View File

@@ -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
@@ -9,16 +9,32 @@
#endregion
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA
{
public interface IInputHandler
{
void ModifierKeys( Modifiers mods );
void OnKeyInput( KeyInput input );
void OnMouseInput( MouseInput input );
}
public struct MouseInput
{
public MouseInputEvent Event;
public int2 Location;
public MouseButton Button;
public int2 Location;
public Modifiers Modifiers;
public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods )
{
this.Event = ev;
this.Button = button;
this.Location = location;
this.Modifiers = mods;
}
}
public enum MouseInputEvent { Down, Move, Up };
@@ -26,19 +42,21 @@ namespace OpenRA
[Flags]
public enum MouseButton
{
None = (int)MouseButtons.None,
Left = (int)MouseButtons.Left,
Right = (int)MouseButtons.Right,
Middle = (int)MouseButtons.Middle,
None = 0,
Left = 1,
Right = 2,
Middle = 4,
WheelDown = 8,
WheelUp = 16
}
[Flags]
public enum Modifiers
{
None = (int)Keys.None,
Shift = (int)Keys.Shift,
Alt = (int)Keys.Alt,
Ctrl = (int)Keys.Control,
None = 0,
Shift = 1,
Alt = 2,
Ctrl = 4,
}
public enum KeyInputEvent { Down, Up };

View File

@@ -26,6 +26,8 @@ namespace OpenRA.FileFormats
public byte[] Image;
public ImageHeader() { }
public ImageHeader( BinaryReader reader )
{
Offset = reader.ReadUInt32();
@@ -35,6 +37,15 @@ namespace OpenRA.FileFormats
RefOffset = reader.ReadUInt16();
RefFormat = (Format)reader.ReadUInt16();
}
public static readonly int SizeOnDisk = 8;
public void WriteTo(BinaryWriter writer)
{
writer.Write(Offset | ((uint)Format << 24));
writer.Write((ushort)RefOffset);
writer.Write((ushort)RefFormat);
}
}
public enum Format

View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats.Graphics
{
// format80-only SHP writer
public static class ShpWriter
{
public static void Write(Stream s, int width, int height, IEnumerable<byte[]> frames)
{
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
// note: end-of-file and all-zeroes headers
var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk;
using (var bw = new BinaryWriter(s))
{
bw.Write((ushort)compressedFrames.Length);
bw.Write((ushort)0); // unused
bw.Write((ushort)0); // unused
bw.Write((ushort)width);
bw.Write((ushort)height);
bw.Write((uint)0); // unused
foreach (var f in compressedFrames)
{
var ih = new ImageHeader { Format = Format.Format80, Offset = (uint)dataOffset };
dataOffset += f.Length;
ih.WriteTo(bw);
}
var eof = new ImageHeader { Offset = (uint)dataOffset };
eof.WriteTo(bw);
var allZeroes = new ImageHeader { };
allZeroes.WriteTo(bw);
foreach (var f in compressedFrames)
bw.Write(f);
}
}
}
}

View File

@@ -0,0 +1,97 @@
#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;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace OpenRA.FileFormats
{
public static class HttpUtil
{
public static byte[] DownloadData(string url, Action<int, int> f, int chunkSize)
{
var uri = new Uri(url);
var ip = Dns.GetHostEntry(uri.DnsSafeHost).AddressList[0];
using (var s = new TcpClient())
{
s.Connect(new IPEndPoint(ip, uri.Port));
var ns = s.GetStream();
var sw = new StreamWriter(ns);
sw.Write("GET {0} HTTP/1.0\r\nHost:{1}\r\n\r\n", uri.PathAndQuery, uri.Host);
sw.Flush();
var br = new BinaryReader(ns);
var contentLength = 0;
var offset = 0;
for (; ; )
{
var result = br.ReadLine();
var kv = result.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
if (result == "")
{
/* data follows the blank line */
if (contentLength > 0)
{
if (f != null)
f(offset, contentLength);
var data = new byte[contentLength];
while (offset < contentLength)
{
var thisChunk = Math.Min(contentLength - offset, chunkSize);
br.Read(data, offset, thisChunk);
offset += thisChunk;
if (f != null)
f(offset, contentLength);
}
s.Close();
return data;
}
else
{
s.Close();
return new byte[] { };
}
}
else if (kv[0] == "Content-Length")
contentLength = int.Parse(kv[1]);
}
}
}
public static byte[] DownloadData(string url, Action<int, int> f)
{
return DownloadData(url, f, 4096);
}
public static byte[] DownloadData(string url)
{
return DownloadData(url, null);
}
static string ReadLine(this BinaryReader br)
{
var sb = new StringBuilder();
char c;
while ((c = br.ReadChar()) != '\n')
if (c != '\r' && c != '\n')
sb.Append(c);
return sb.ToString();
}
}
}

View File

@@ -18,15 +18,15 @@ namespace OpenRA.FileFormats
public class Manifest
{
public readonly string[]
Folders, Packages, Rules,
Mods, Folders, Packages, Rules, ServerTraits,
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, Movies, TileSets;
public readonly string ShellmapUid, LoadScreen;
public readonly string LoadScreen;
public readonly int TileSize = 24;
public Manifest(string[] mods)
{
Mods = mods;
var yaml = mods
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
.Aggregate(MiniYaml.Merge);
@@ -35,6 +35,7 @@ namespace OpenRA.FileFormats
Folders = YamlList(yaml, "Folders");
Packages = YamlList(yaml, "Packages");
Rules = YamlList(yaml, "Rules");
ServerTraits = YamlList(yaml, "ServerTraits");
Sequences = YamlList(yaml, "Sequences");
Cursors = YamlList(yaml, "Cursors");
Chrome = YamlList(yaml, "Chrome");
@@ -46,7 +47,6 @@ namespace OpenRA.FileFormats
Movies = YamlList(yaml, "Movies");
TileSets = YamlList(yaml, "TileSets");
ShellmapUid = yaml.First( x => x.Key == "ShellmapUid" ).Value.Value;
LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value;
if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null)

View File

@@ -12,18 +12,22 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography;
namespace OpenRA.FileFormats
{
public class MapStub
{
public readonly IFolder Package;
protected IFolder Container;
public string Path {get; protected set;}
// Yaml map data
public readonly string Uid;
[FieldLoader.Load] public bool Selectable;
public string Uid { get; protected set; }
[FieldLoader.Load] public bool Selectable;
[FieldLoader.Load] public bool UseAsShellmap;
[FieldLoader.Load] public string Title;
[FieldLoader.Load] public string Type = "Conquest";
[FieldLoader.Load] public string Description;
[FieldLoader.Load] public string Author;
[FieldLoader.Load] public int PlayerCount;
@@ -35,18 +39,33 @@ namespace OpenRA.FileFormats
[FieldLoader.Load] public int2 TopLeft;
[FieldLoader.Load] public int2 BottomRight;
public int Width { get { return BottomRight.X - TopLeft.X; } }
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
public MapStub(IFolder package)
public Rectangle Bounds;
public MapStub() {} // Hack for the editor - not used for anything important
public MapStub(string path)
{
Package = package;
var yaml = MiniYaml.FromStream(Package.GetContent("map.yaml"));
Path = path;
Container = FileSystem.OpenPackage(path, int.MaxValue);
var yaml = MiniYaml.FromStream(Container.GetContent("map.yaml"));
FieldLoader.Load( this, new MiniYaml( null, yaml ) );
Uid = Package.GetContent("map.uid").ReadAllText();
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
Uid = ComputeHash();
}
string ComputeHash()
{
// UID is calculated by taking an SHA1 of the yaml and binary data
// Read the relevant data into a buffer
var data = Container.GetContent("map.yaml").ReadAllBytes()
.Concat(Container.GetContent("map.bin").ReadAllBytes()).ToArray();
// Take the SHA1
using (var csp = SHA1.Create())
return new string(csp.ComputeHash(data).SelectMany(a => a.ToString("x2")).ToArray());
}
static object LoadWaypoints( MiniYaml y )
{
var ret = new Dictionary<string, int2>();

View File

@@ -8,7 +8,8 @@
*/
#endregion
using System.Drawing;
using System.Drawing;
using System;
namespace OpenRA.FileFormats
{
@@ -16,13 +17,19 @@ namespace OpenRA.FileFormats
{
public string Name;
public string Palette;
public string Race;
public bool OwnsWorld = false;
public bool NonCombatant = false;
public bool Playable = false;
public bool DefaultStartingUnits = false;
public bool AllowBots = true;
public bool LockRace = false;
public string Race;
public bool LockColor = false;
public Color Color = Color.FromArgb(238,238,238);
public Color Color2 = Color.FromArgb(44,28,24);
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public int InitialCash = 0;
public string[] Allies = {};

View File

@@ -225,7 +225,7 @@ namespace OpenRA.FileFormats
{
return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray());
}
public static IEnumerable<string> ToLines(this MiniYamlNodes y, bool lowest)
{
foreach (var kv in y)

37
OpenRA.FileFormats/Mod.cs Normal file
View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace OpenRA.FileFormats
{
public class Mod
{
public string Title;
public string Description;
public string Version;
public string Author;
public string Requires;
public bool Standalone = false;
public static readonly Dictionary<string, Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
public static Dictionary<string, Mod> ValidateMods(string[] mods)
{
var ret = new Dictionary<string, Mod>();
foreach (var m in mods)
{
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
continue;
var yaml = new MiniYaml(null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
if (!yaml.NodesDict.ContainsKey("Metadata"))
continue;
ret.Add(m, FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
}
return ret;
}
}
}

View File

@@ -45,6 +45,7 @@
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Tao.Sdl, Version=1.2.13.0, Culture=neutral, PublicKeyToken=9c7a200e36c0094e">
<SpecificVersion>False</SpecificVersion>
@@ -53,22 +54,28 @@
<Reference Include="WindowsBase">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\thirdparty\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ColorHSLR.cs" />
<Compile Include="Evaluator.cs" />
<Compile Include="Exts.cs" />
<Compile Include="FieldLoader.cs" />
<Compile Include="FileSystem.cs" />
<Compile Include="Folder.cs" />
<Compile Include="Graphics\IGraphicsDevice.cs" />
<Compile Include="Graphics\IInputHandler.cs" />
<Compile Include="Graphics\ShpWriter.cs" />
<Compile Include="Graphics\Vertex.cs" />
<Compile Include="HttpUtil.cs" />
<Compile Include="Manifest.cs" />
<Compile Include="MiniYaml.cs" />
<Compile Include="Mod.cs" />
<Compile Include="PackageEntry.cs" />
<Compile Include="Package.cs" />
<Compile Include="PackageWriter.cs" />
<Compile Include="Palette.cs" />
<Compile Include="PlayerColorRemap.cs" />
<Compile Include="Primitives\ActionQueue.cs" />
<Compile Include="Primitives\DisposableAction.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Thirdparty\Random.cs" />
@@ -98,8 +105,13 @@
<Compile Include="Map\MapStub.cs" />
<Compile Include="Map\SmudgeReference.cs" />
<Compile Include="Map\PlayerReference.cs" />
<Compile Include="CompressedPackage.cs" />
<Compile Include="Graphics\VqaReader.cs" />
<Compile Include="Filesystem\MixFile.cs" />
<Compile Include="Filesystem\FileSystem.cs" />
<Compile Include="Filesystem\Folder.cs" />
<Compile Include="Filesystem\InstallShieldPackage.cs" />
<Compile Include="FileFormats\Blast.cs" />
<Compile Include="Filesystem\ZipFile.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

@@ -1,48 +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.IO;
namespace OpenRA.FileFormats
{
public static class PackageWriter
{
public static void CreateMix(string filename, List<string> contents)
{
// Construct a list of entries for the file header
uint dataSize = 0;
var items = new List<PackageEntry>();
foreach (var file in contents)
{
uint length = (uint)new FileInfo(file).Length;
uint hash = PackageEntry.HashFilename(Path.GetFileName(file));
items.Add(new PackageEntry(hash, dataSize, length));
dataSize += length;
}
using (var s = File.Create(filename))
using (var writer = new BinaryWriter(s))
{
// Write file header
writer.Write((ushort)items.Count);
writer.Write(dataSize);
foreach (var item in items)
item.Write(writer);
writer.Flush();
// Copy file data
foreach (var file in contents)
s.Write(File.ReadAllBytes(file));
}
}
}
}

View File

@@ -8,11 +8,8 @@
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System;
namespace OpenRA.FileFormats
{

7
OpenRA.FileFormats/PlayerColorRemap.cs Normal file → Executable file
View File

@@ -21,8 +21,11 @@ namespace OpenRA.FileFormats
{
Dictionary<int, Color> remapColors;
public PlayerColorRemap(Color c1, Color c2, PaletteFormat fmt)
public PlayerColorRemap(ColorRamp c, PaletteFormat fmt)
{
var c1 = c.GetColor(0);
var c2 = c.GetColor(1); /* temptemp: this can be expressed better */
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
var ramp = (fmt == PaletteFormat.cnc)
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
@@ -32,7 +35,7 @@ namespace OpenRA.FileFormats
.ToDictionary(u => u.First, u => u.Second);
}
static Color ColorLerp(float t, Color c1, Color c2)
public static Color ColorLerp(float t, Color c1, Color c2)
{
return Color.FromArgb(255,
(int)(t * c2.R + (1 - t) * c1.R),

View File

@@ -0,0 +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 System;
namespace OpenRA.FileFormats
{
/// <summary>
/// A thread-safe action queue, suitable for passing units of work between threads.
/// </summary>
public class ActionQueue
{
object syncRoot = new object();
Action actions = () => { };
public void Add(Action a)
{
lock (syncRoot)
actions += a;
}
public void PerformActions()
{
Action a;
lock (syncRoot)
{
a = actions;
actions = () => { };
}
a();
}
}
}

View File

@@ -62,7 +62,8 @@ namespace OpenRA
Constrain(Y, min.Y, max.Y));
}
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); }
public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); }

View File

@@ -25,6 +25,9 @@ namespace OpenRA
public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); }
public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); }
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); }
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
@@ -59,5 +62,24 @@ namespace OpenRA
{
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
}
public static int Lerp( int a, int b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public static int2 Lerp( int2 a, int2 b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public int2 Clamp(Rectangle r)
{
return new int2(Math.Min(r.Right, Math.Max(X, r.Left)),
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
}
public static int Dot(int2 a, int2 b) { return a.X * b.X + a.Y * b.Y; }
}
}

View File

@@ -26,11 +26,12 @@ namespace OpenRA
public readonly World World;
public readonly uint ActorID;
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public int2 CenterLocation { get { return Trait<IHasLocation>().PxPosition; } }
[Sync]
public Player Owner;
IActivity currentActivity;
private IActivity currentActivity;
public Group Group;
internal Actor(World world, string name, TypeDictionary initDict )
@@ -52,9 +53,6 @@ namespace OpenRA
AddTrait(trait.Create(init));
}
if( CenterLocation == float2.Zero && HasTrait<IOccupySpace>() )
CenterLocation = Traits.Util.CenterOfCell(Location);
Size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
@@ -63,44 +61,25 @@ namespace OpenRA
// auto size from render
var firstSprite = TraitsImplementing<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size;
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size * firstSprite.Scale;
});
}
public void Tick()
{
var wasIdle = currentActivity is Idle;
while (currentActivity != null)
{
var a = currentActivity;
var sw = new Stopwatch();
currentActivity = a.Tick(this) ?? new Idle();
var dt = sw.ElapsedTime();
if(dt > Game.Settings.Debug.LongTickThreshold)
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", a, dt * 1000, Game.LocalTick);
if (a == currentActivity) break;
if (currentActivity == null)
foreach (var ni in TraitsImplementing<INotifyIdle>())
ni.TickIdle(this);
if (currentActivity is Idle)
{
if (!wasIdle)
foreach (var ni in TraitsImplementing<INotifyIdle>())
ni.Idle(this);
break;
}
}
currentActivity = Util.RunActivity( this, currentActivity );
}
public bool IsIdle
{
get { return currentActivity == null || currentActivity is Idle; }
get { return currentActivity == null; }
}
public float2 CenterLocation;
OpenRA.FileFormats.Lazy<float2> Size;
public IEnumerable<Renderable> Render()
@@ -109,58 +88,46 @@ namespace OpenRA
var sprites = TraitsImplementing<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
public Order Order( int2 xy, MouseInput mi, Actor underCursor )
{
if (Owner != World.LocalPlayer)
return null;
if (!World.Map.IsInMap(xy.X, xy.Y))
return null;
if (Destroyed)
return null;
return TraitsImplementing<IIssueOrder>()
.OrderByDescending( x => x.OrderPriority( this, xy, mi, underCursor ) )
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
// When useAltitude = true, the bounding box is extended
// vertically to altitude = 0 to support FindUnitsInCircle queries
// When false, the bounding box is given for the actor
// at its current altitude
public RectangleF GetBounds(bool useAltitude)
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
var size = Size.Value;
var loc = CenterLocation - 0.5f * size;
var loc = CenterLocation - 0.5f * size;
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
loc += new float2(si.Bounds[2], si.Bounds[3]);
if (useAltitude)
{
var move = TraitOrDefault<IMove>();
if (move != null) loc -= new float2(0, move.Altitude);
var move = TraitOrDefault<IMove>();
if (move != null)
{
loc -= new float2(0, move.Altitude);
if (useAltitude)
size = new float2(size.X, size.Y + move.Altitude);
}
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
}
public bool IsInWorld { get; internal set; }
public bool IsInWorld { get; internal set; }
public void QueueActivity( bool queued, IActivity nextActivity )
{
if( !queued )
CancelActivity();
QueueActivity( nextActivity );
}
public void QueueActivity( IActivity nextActivity )
{
if( currentActivity == null )
{
currentActivity = nextActivity;
return;
}
var act = currentActivity;
while( act.NextActivity != null )
{
act = act.NextActivity;
}
act.NextActivity = nextActivity;
else
currentActivity.Queue( nextActivity );
}
public void CancelActivity()
@@ -169,7 +136,6 @@ namespace OpenRA
currentActivity.Cancel( this );
}
// For pathdebug, et al
public IActivity GetCurrentActivity()
{
return currentActivity;
@@ -222,10 +188,24 @@ namespace OpenRA
{
World.AddFrameEndTask( w =>
{
if (Destroyed) return;
World.Remove( this );
World.traitDict.RemoveActor( this );
Destroyed = true;
} );
}
// todo: move elsewhere.
public void ChangeOwner(Player newOwner)
{
World.AddFrameEndTask(w =>
{
// momentarily remove from world so the ownership queries don't get confused
w.Remove(this);
Owner = newOwner;
w.Add(this);
});
}
}
}

View File

@@ -23,9 +23,6 @@ namespace OpenRA.FileFormats
public ActorReference( string type, Dictionary<string, MiniYaml> inits )
{
if (Rules.Info != null && !Rules.Info.ContainsKey(type))
throw new InvalidDataException("Unknown actor: `{0}'".F(type));
Type = type;
InitDict = new TypeDictionary();
foreach( var i in inits )

View File

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

View File

@@ -1,46 +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 OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class MoveFlash : IEffect
{
Animation anim = new Animation("moveflsh");
float2 pos;
public MoveFlash( World world, int2 cell )
{
this.pos = Game.CellSize * (cell + new float2(0.5f, 0.5f));
anim.PlayThen( "idle",
() => world.AddFrameEndTask(
w => w.Remove( this ) ) );
}
public MoveFlash( World world, float2 pos )
{
this.pos = pos;
anim.PlayThen( "idle",
() => world.AddFrameEndTask(
w => w.Remove( this ) ) );
}
public void Tick( World world ) { anim.Tick(); }
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y);
}
}
}

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

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

440
OpenRA.Game/Game.cs Normal file → Executable file
View File

@@ -6,18 +6,20 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
#endregion
using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Net;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
@@ -27,315 +29,341 @@ namespace OpenRA
{
public static class Game
{
public static Utilities Utilities;
public static int CellSize { get { return modData.Manifest.TileSize; } }
public static ModData modData;
public static World world;
private static WorldRenderer worldRenderer;
public static Viewport viewport;
public static Settings Settings;
internal static OrderManager orderManager;
static Server.Server server;
public static XRandom CosmeticRandom = new XRandom(); // not synced
public static Renderer Renderer;
public static Session LobbyInfo = new Session();
public static bool HasInputFocus = false;
static void LoadMap(string uid)
{
var map = modData.PrepareMap(uid);
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
world = new World(modData.Manifest, map);
}
public static void MoveViewport(int2 loc)
public static void MoveViewport(float2 loc)
{
viewport.Center(loc);
}
internal static string CurrentHost = "";
internal static int CurrentPort = 0;
internal static void JoinServer(string host, int port)
public static void JoinServer(string host, int port)
{
if (orderManager != null) orderManager.Dispose();
var replayFilename = ChooseReplayFilename();
string path = Path.Combine( Game.SupportDir, "Replays" );
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
CurrentHost = host;
CurrentPort = port;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
}
JoinInner(new OrderManager(host, port,
new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile)));
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep");
}
static void JoinInner(OrderManager om)
{
if (orderManager != null) orderManager.Dispose();
orderManager = om;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged(orderManager);
}
public static void JoinReplay(string replayFile)
{
JoinInner(new OrderManager("<no server>", -1, new ReplayConnection(replayFile)));
}
static void JoinLocal()
{
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
JoinInner(new OrderManager("<no server>", -1, new EchoConnection()));
}
static int lastTime = Environment.TickCount;
static void ResetTimer()
{
lastTime = Environment.TickCount;
}
internal static int RenderFrame = 0;
internal static int LocalTick = 0;
public static int RenderFrame = 0;
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public static event Action ConnectionStateChanged = () => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
static void Tick()
// Hacky workaround for orderManager visibility
public static Widget OpenWindow(World world, string widget)
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged();
}
return Widget.OpenWindow(widget, new Dictionary<string,object>{{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }});
}
int t = Environment.TickCount;
int dt = t - lastTime;
if (dt >= Settings.Game.Timestep)
static ActionQueue afterTickActions = new ActionQueue();
public static void RunAfterTick(Action a) { afterTickActions.Add(a); }
static void Tick( OrderManager orderManager, Viewport viewPort )
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
using (new PerfSample("tick_time"))
{
lastTime += Settings.Game.Timestep;
Widget.DoTick(world);
Sound.Tick();
orderManager.TickImmediate(world);
var isNetTick = LocalTick % NetTickScale == 0;
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++LocalTick;
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
if (isNetTick) orderManager.Tick(world);
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.FrameNumber == 0)
lastTime = Environment.TickCount;
}
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged( orderManager );
}
Tick( orderManager );
if( worldRenderer != null && orderManager.world != worldRenderer.world )
Tick( worldRenderer.world.orderManager );
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions(world);
viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world ));
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
}
PerfHistory.items["render"].Tick();
PerfHistory.items["batches"].Tick();
PerfHistory.items["text"].Tick();
PerfHistory.items["cursor"].Tick();
MasterServerQuery.Tick();
afterTickActions.PerformActions();
}
internal static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo(string data)
private static void Tick( OrderManager orderManager )
{
LobbyInfo = Session.Deserialize(data);
int t = Environment.TickCount;
int dt = t - orderManager.LastTickTime;
if (dt >= Settings.Game.Timestep)
using( new PerfSample( "tick_time" ) )
{
orderManager.LastTickTime += Settings.Game.Timestep;
Widget.DoTick();
var world = orderManager.world;
if( orderManager.GameStarted && world.LocalPlayer != null )
++Viewport.TicksSinceLastMove;
Sound.Tick();
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
if( !world.GameHasStarted )
world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
if (world != null)
{
var isNetTick = LocalTick % NetTickScale == 0;
if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
world.SetLocalPlayer(orderManager.Connection.LocalClientId);
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++orderManager.LocalFrameNumber;
if (orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
&& !orderManager.GameStarted)
{
orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
Debug("Order lag is now {0} frames.".F(LobbyInfo.GlobalSettings.OrderLatency));
}
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
if (isNetTick) orderManager.Tick();
Sync.CheckSyncUnchanged(world, () =>
{
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
});
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.NetFrameNumber == 0)
orderManager.LastTickTime = Environment.TickCount;
}
}
}
public static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo()
{
LobbyInfoChanged();
}
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
public static event Action AfterGameStart = () => {};
public static event Action<World> AfterGameStart = _ => {};
public static event Action BeforeGameStart = () => {};
internal static void StartGame(string map)
internal static void StartGame(string mapUID)
{
BeforeGameStart();
LoadMap(map);
var map = modData.PrepareMap(mapUID);
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer);
orderManager.world = new World(modData.Manifest, map, orderManager);
worldRenderer = new WorldRenderer(orderManager.world);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
LocalTick = 0;
orderManager.StartGame();
viewport.RefreshPalette();
AfterGameStart();
}
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
if (world == null)
return;
int sync = world.SyncHash();
var initialWorld = world;
var mi = new MouseInput
{
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");
orderManager.LocalFrameNumber = 0;
orderManager.StartGame();
worldRenderer.RefreshPalette();
AfterGameStart( orderManager.world );
}
public static bool IsHost
{
get { return orderManager.Connection.LocalClientId == 0; }
}
internal static Session.Client LocalClient
public static Dictionary<String, Mod> CurrentMods
{
get { return LobbyInfo.Clients.FirstOrDefault(c => c.Index == orderManager.Connection.LocalClientId); }
}
public static void HandleKeyEvent(KeyInput e)
{
if (world == null)
return;
int sync = world.SyncHash();
if (Widget.HandleKeyPress(e))
return;
if (sync != Game.world.SyncHash())
throw new InvalidOperationException("Desync in OnKeyPress");
get { return Mod.AllMods.Where( k => orderManager.LobbyInfo.GlobalSettings.Mods.Contains( k.Key )).ToDictionary( k => k.Key, k => k.Value ); }
}
static Modifiers modifiers;
public static Modifiers GetModifierKeys() { return modifiers; }
public static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
internal static void Initialize(Arguments args)
{
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
Settings = new Settings(SupportDir + "settings.yaml", args);
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
FileSystem.SpecialPackageRoot = args.GetValue("SpecialPackageRoot", "");
Utilities = new Utilities(args.GetValue("UtilityPath", "OpenRA.Utility.exe"));
Settings = new Settings(SupportDir + "settings.yaml", args);
Settings.Save();
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
FileSystem.Mount("."); // Needed to access shaders
Renderer.Initialize( Game.Settings.Graphics.Mode );
Renderer.SheetSize = Settings.Game.SheetSize;
Renderer = new Renderer();
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods;
modData = new ModData( LobbyInfo.GlobalSettings.Mods );
Console.WriteLine("Available mods:");
foreach(var mod in Mod.AllMods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
Sound.Create();
InitializeWithMods(Settings.Game.Mods);
}
public static void InitializeWithMods(string[] mods)
{
// Clear static state if we have switched mods
LobbyInfoChanged = () => {};
AddChatLine = (a,b,c) => {};
worldRenderer = null;
if (server != null)
server.Shutdown();
if (orderManager != null)
orderManager.Dispose();
// Discard any invalid mods
var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
Console.WriteLine("Loading mods: {0}",string.Join(",",mm));
Settings.Game.Mods = mm;
Settings.Save();
Sound.Initialize();
modData = new ModData( mm );
modData.LoadInitialAssets();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false;
JoinLocal();
JoinLocal();
viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer);
Widget.RootWidget.RemoveChildren();
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "INIT_SETUP" );
}
public static void LoadShellMap()
{
StartGame(ChooseShellmap());
Game.orderManager.LastTickTime = Environment.TickCount;
}
static string ChooseShellmap()
{
var shellmaps = modData.AvailableMaps
.Where(m => m.Value.UseAsShellmap);
if (shellmaps.Count() == 0)
throw new InvalidDataException("No valid shellmaps available");
return shellmaps.Random(CosmeticRandom).Key;
}
static bool quit;
public static event Action OnQuit = () => {};
internal static void Run()
{
while (!quit)
{
{
Tick( orderManager, viewport );
Application.DoEvents();
}
OnQuit();
}
public static void Exit() { quit = true; }
public static void Exit() { quit = true; }
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
public static void Debug(string s, params object[] args)
{
public static void Debug(string s, params object[] args)
{
AddChatLine(Color.White, "Debug", String.Format(s,args));
}
public static void Disconnect()
{
if (IsHost && server != null)
server.Shutdown();
orderManager.Dispose();
orderManager.Dispose();
var shellmap = modData.Manifest.ShellmapUid;
LobbyInfo = new Session();
var shellmap = ChooseShellmap();
JoinLocal();
StartGame(shellmap);
Widget.RootWidget.CloseWindow();
Widget.RootWidget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
baseSupportDir = dir + Path.DirectorySeparatorChar;
}
}
get { return baseSupportDir; }
}
public static T CreateObject<T>( string name )
{
return modData.ObjectCreator.CreateObject<T>( name );
}
public static void CreateAndJoinServer(Settings settings, string map)
{
server = new Server.Server(modData, settings, map);
JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort);
}
}
}
}

View File

@@ -66,21 +66,21 @@ namespace OpenRA
var ret = new List<ITraitInfo>();
var t = Traits.WithInterface<ITraitInfo>().ToList();
int index = 0;
while( t.Count != 0 )
while (t.Count != 0)
{
if( index >= t.Count )
throw new InvalidOperationException( "Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1}".F(
Name, string.Join( ",", t.Select( x => x.GetType().Name ).ToArray())));
var prereqs = PrerequisitesOf( t[ index ] );
if( prereqs.Count == 0 || prereqs.All( n => ret.Any( x => x.GetType() == n || x.GetType().IsSubclassOf( n ) ) ) )
var prereqs = PrerequisitesOf(t[index]);
var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n)));
if (!unsatisfied.Any())
{
ret.Add( t[ index ] );
t.RemoveAt( index );
ret.Add(t[index]);
t.RemoveAt(index);
index = 0;
}
else
++index;
else if (++index >= t.Count)
throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F(
Name,
string.Join(",", t.Select(x => x.GetType().Name).ToArray()),
string.Join(",", unsatisfied.Select(x => x.Name).ToArray())));
}
return ret;

View File

@@ -27,9 +27,10 @@ namespace OpenRA
public static void LoadRules(Manifest m, Map map)
{
// Added support to extend the list of rules (add it to m.LocalRules)
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, new List<MiniYamlNode>(), (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, new List<MiniYamlNode>(), (k, _) => new VoiceInfo(k.Value));
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, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);

View File

@@ -8,13 +8,14 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using System;
using OpenRA.Server;
namespace OpenRA.GameRules
{
@@ -24,23 +25,24 @@ namespace OpenRA.GameRules
public int ListenPort = 1234;
public int ExternalPort = 1234;
public bool AdvertiseOnline = true;
public string MasterServer = "http://open-ra.org/master/";
public string MasterServer = "http://master.open-ra.org/";
public bool AllowCheats = false;
}
public class DebugSettings
{
public bool BotDebug = false;
public bool PerfGraph = false;
public bool RecordSyncReports = true;
public bool ShowCollisions = false;
public float LongTickThreshold = 0.001f;
public bool SanityCheckUnsyncedCode = false;
}
public class GraphicSettings
{
public string Renderer = "Gl";
public WindowMode Mode = WindowMode.PseudoFullscreen;
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height);
public int2 WindowedSize = new int2(1024,768);
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
public int2 WindowedSize = new int2(1024, 768);
public readonly int2 MinResolution = new int2(800, 600);
}
@@ -56,8 +58,9 @@ namespace OpenRA.GameRules
public class PlayerSettings
{
public string Name = "Newbie";
public Color Color1 = Color.FromArgb(255,160,238);
public Color Color2 = Color.FromArgb(68,0,56);
[Obsolete] public Color Color1 = Color.FromArgb(255,160,238);
[Obsolete] public Color Color2 = Color.FromArgb(68,0,56);
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public string LastServer = "localhost:1234";
}
@@ -66,9 +69,13 @@ namespace OpenRA.GameRules
public string[] Mods = { "ra" };
public bool MatchTimer = true;
// Chat settings
public bool TeamChatToggle = false;
// Behaviour settings
public bool ViewportEdgeScroll = true;
public bool InverseDragScroll = false;
public float ViewportEdgeScrollStep = 10f;
// Internal game settings
public int Timestep = 40;
@@ -86,7 +93,7 @@ namespace OpenRA.GameRules
public ServerSettings Server = new ServerSettings();
public DebugSettings Debug = new DebugSettings();
Dictionary<string, object> Sections;
public Dictionary<string, object> Sections;
public Settings(string file, Arguments args)
{
SettingsFile = file;
@@ -100,18 +107,19 @@ namespace OpenRA.GameRules
{"Debug", Debug}
};
// Override fieldloader to ignore invalid entries
var err1 = FieldLoader.UnknownFieldAction;
var err2 = FieldLoader.InvalidValueAction;
FieldLoader.UnknownFieldAction = (s,f) =>
{
System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
};
if (File.Exists(SettingsFile))
{
System.Console.WriteLine("Loading settings file {0}",SettingsFile);
//Console.WriteLine("Loading settings file {0}",SettingsFile);
var yaml = MiniYaml.DictFromFile(SettingsFile);
foreach (var kv in Sections)
@@ -123,7 +131,7 @@ namespace OpenRA.GameRules
foreach (var kv in Sections)
foreach (var f in kv.Value.GetType().GetFields())
if (args.Contains(kv.Key+"."+f.Name))
OpenRA.FileFormats.FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.UnknownFieldAction = err1;
FieldLoader.InvalidValueAction = err2;
@@ -133,16 +141,11 @@ namespace OpenRA.GameRules
{
var root = new List<MiniYamlNode>();
foreach( var kv in Sections )
root.Add( new MiniYamlNode( kv.Key, SectionYaml( kv.Value ) ) );
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
root.WriteToFile(SettingsFile);
}
MiniYaml SectionYaml(object section)
{
return FieldSaver.SaveDifferences(section, Activator.CreateInstance(section.GetType()));
}
void LoadSectionYaml(MiniYaml yaml, object section)
{
object defaults = Activator.CreateInstance(section.GetType());

View File

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

View File

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

View File

@@ -56,13 +56,14 @@ namespace OpenRA.Graphics
PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) );
}
public void ReplaceAnim(string sequenceName)
public bool ReplaceAnim(string sequenceName)
{
if (!HasSequence(sequenceName))
return;
return false;
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
return true;
}
public void PlayThen( string sequenceName, Action after )
@@ -124,14 +125,15 @@ namespace OpenRA.Graphics
}
}
public void ChangeImage(string newImage)
public void ChangeImage(string newImage, string newAnimIfMissing)
{
newImage = newImage.ToLowerInvariant();
if (name != newImage)
{
name = newImage.ToLowerInvariant();
ReplaceAnim(CurrentSequence.Name);
if (!ReplaceAnim(CurrentSequence.Name))
ReplaceAnim(newAnimIfMissing);
}
}

View File

@@ -20,33 +20,25 @@ namespace OpenRA.Graphics
public static class CursorProvider
{
static Dictionary<string, CursorSequence> cursors;
public static void Initialize(string[] sequenceFiles)
{
cursors = new Dictionary<string, CursorSequence>();
foreach (var f in sequenceFiles)
LoadSequenceSource(f);
}
static void LoadSequenceSource(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(FileSystem.Open(filename));
foreach (XmlElement eCursor in document.SelectNodes("/sequences/cursor"))
LoadSequencesForCursor(eCursor);
public static void Initialize(string[] sequenceFiles)
{
cursors = new Dictionary<string, CursorSequence>();
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.Merge));
foreach (var s in sequences.NodesDict["Palettes"].Nodes)
Game.modData.Palette.AddPalette(s.Key, new Palette(FileSystem.Open(s.Value.Value), false));
foreach (var s in sequences.NodesDict["Cursors"].Nodes)
LoadSequencesForCursor(s.Key, s.Value);
}
static void LoadSequencesForCursor(XmlElement eCursor)
static void LoadSequencesForCursor(string cursorSrc, MiniYaml cursor)
{
Game.modData.LoadScreen.Display();
string cursorSrc = eCursor.GetAttribute("src");
string palette = eCursor.GetAttribute("palette");
foreach (XmlElement eSequence in eCursor.SelectNodes("./sequence"))
cursors.Add(eSequence.GetAttribute("name"), new CursorSequence(cursorSrc, palette, eSequence));
foreach (var sequence in cursor.Nodes)
cursors.Add(sequence.Key, new CursorSequence(cursorSrc, cursor.Value, sequence.Value));
}
public static bool HasCursorSequence(string cursor)

View File

@@ -9,6 +9,7 @@
#endregion
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
@@ -25,24 +26,27 @@ namespace OpenRA.Graphics
Sprite[] sprites;
public CursorSequence(string cursorSrc, string palette, XmlElement e)
public CursorSequence(string cursorSrc, string palette, MiniYaml info)
{
sprites = Game.modData.CursorSheetBuilder.LoadAllSprites(cursorSrc);
var d = info.NodesDict;
start = int.Parse(e.GetAttribute("start"));
start = int.Parse(d["start"].Value);
this.palette = palette;
if (e.GetAttribute("length") == "*" || e.GetAttribute("end") == "*")
if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*"))
length = sprites.Length - start;
else if (e.HasAttribute("length"))
length = int.Parse(e.GetAttribute("length"));
else if (e.HasAttribute("end"))
length = int.Parse(e.GetAttribute("end")) - start;
else if (d.ContainsKey("length"))
length = int.Parse(d["length"].Value);
else if (d.ContainsKey("end"))
length = int.Parse(d["end"].Value) - start;
else
length = 1;
int.TryParse( e.GetAttribute("x"), out Hotspot.X );
int.TryParse( e.GetAttribute("y"), out Hotspot.Y );
if (d.ContainsKey("x"))
int.TryParse(d["x"].Value, out Hotspot.X );
if (d.ContainsKey("y"))
int.TryParse(d["y"].Value, out Hotspot.Y );
}
public Sprite GetSprite(int frame)

View File

@@ -27,7 +27,7 @@ namespace OpenRA.Graphics
}
Sprite[] LoadCursors(string filename)
{
{
try
{
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Graphics
{
class HardwarePalette
public class HardwarePalette
{
public const int MaxPalettes = 64;
int allocated = 0;
@@ -26,7 +26,7 @@ namespace OpenRA.Graphics
Dictionary<string, Palette> palettes;
Dictionary<string, int> indices;
public HardwarePalette(Map map)
public HardwarePalette()
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
@@ -51,6 +51,9 @@ namespace OpenRA.Graphics
public void AddPalette(string name, Palette p)
{
if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name));
palettes.Add(name, p);
indices.Add(name, allocated++);
}

View File

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

View File

@@ -28,12 +28,12 @@ namespace OpenRA.Graphics
public static Bitmap TerrainBitmap(Map map, bool actualSize)
{
var tileset = Rules.TileSets[map.Tileset];
var width = map.Width;
var height = map.Height;
var width = map.Bounds.Width;
var height = map.Bounds.Height;
if (!actualSize)
{
width = height = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
}
Bitmap terrain = new Bitmap(width, height);
@@ -45,11 +45,11 @@ namespace OpenRA.Graphics
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Width; x++)
for (var y = 0; y < map.Height; y++)
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.TopLeft.X;
var mapY = y + map.TopLeft.Y;
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]);
if (!tileset.Terrain.ContainsKey(type))
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
@@ -75,11 +75,11 @@ namespace OpenRA.Graphics
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Width; x++)
for (var y = 0; y < map.Height; y++)
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.TopLeft.X;
var mapY = y + map.TopLeft.Y;
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (map.MapResources[mapX, mapY].type == 0)
continue;
@@ -100,7 +100,7 @@ namespace OpenRA.Graphics
public static Bitmap CustomTerrainBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
@@ -109,11 +109,11 @@ namespace OpenRA.Graphics
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Width; x++)
for (var y = 0; y < map.Height; y++)
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.TopLeft.X;
var mapY = y + map.TopLeft.Y;
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var custom = map.CustomTerrain[mapX,mapY];
if (custom == null)
continue;
@@ -127,7 +127,7 @@ namespace OpenRA.Graphics
public static Bitmap ActorsBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
@@ -135,16 +135,16 @@ namespace OpenRA.Graphics
unsafe
{
int* c = (int*)bitmapData.Scan0;
foreach (var t in world.Queries.WithTraitMultiple<IRadarSignature>())
foreach (var t in world.Queries.WithTrait<IRadarSignature>())
{
if (!t.Actor.IsVisible(world.LocalPlayer))
if (!world.LocalShroud.IsVisible(t.Actor))
continue;
var color = t.Trait.RadarSignatureColor(t.Actor);
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();
*(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb();
}
}
@@ -155,26 +155,29 @@ namespace OpenRA.Graphics
public static Bitmap ShroudBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
if (world.LocalShroud.Disabled)
return bitmap;
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
var shroud = Color.Black.ToArgb();
var fog = Color.FromArgb(128, Color.Black).ToArgb();
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Width; x++)
for (var y = 0; y < map.Height; y++)
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.TopLeft.X;
var mapY = y + map.TopLeft.Y;
if (!world.LocalPlayer.Shroud.IsExplored(mapX, mapY))
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (!world.LocalShroud.IsExplored(mapX, mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
else if (!world.LocalPlayer.Shroud.IsVisible(mapX,mapY))
else if (!world.LocalShroud.IsVisible(mapX,mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
}
}

View File

@@ -9,13 +9,13 @@
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using OpenRA.FileFormats;
using System.Windows.Forms;
using OpenRA.FileFormats.Graphics;
using OpenRA.Support;
using System.Windows.Forms;
namespace OpenRA.Graphics
{
@@ -23,10 +23,10 @@ namespace OpenRA.Graphics
{
internal static int SheetSize;
public IShader SpriteShader { get; private set; } /* note: shared shader params */
public IShader LineShader { get; private set; }
public IShader RgbaSpriteShader { get; private set; }
public IShader WorldSpriteShader { get; private set; }
internal IShader SpriteShader { get; private set; } /* note: shared shader params */
internal IShader LineShader { get; private set; }
internal IShader RgbaSpriteShader { get; private set; }
internal IShader WorldSpriteShader { get; private set; }
public SpriteRenderer SpriteRenderer { get; private set; }
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
@@ -35,14 +35,20 @@ namespace OpenRA.Graphics
public ITexture PaletteTexture;
public readonly SpriteFont RegularFont, BoldFont, TitleFont;
public readonly SpriteFont RegularFont, BoldFont, TitleFont, TinyFont;
internal const int TempBufferSize = 8192;
const int TempBufferCount = 8;
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
public Renderer()
{
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
LineShader = device.CreateShader(FileSystem.Open("shaders/line.fx"));
RgbaSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-rgba.fx"));
WorldSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-shp.fx"));
SpriteShader = device.CreateShader("world-shp");
LineShader = device.CreateShader("world-line");
RgbaSpriteShader = device.CreateShader("chrome-rgba");
WorldSpriteShader = device.CreateShader("chrome-shp");
SpriteRenderer = new SpriteRenderer( this, SpriteShader );
RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader );
@@ -52,13 +58,19 @@ namespace OpenRA.Graphics
RegularFont = new SpriteFont("FreeSans.ttf", 14);
BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
TitleFont = new SpriteFont("titles.ttf", 48);
TinyFont = new SpriteFont("FreeSans.ttf", 10);
for( int i = 0 ; i < TempBufferCount ; i++ )
{
tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) );
tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) );
}
}
public IGraphicsDevice Device { get { return device; } }
internal IGraphicsDevice Device { get { return device; } }
public void BeginFrame(float2 scroll)
{
device.Begin();
device.Clear(Color.Black);
float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height);
@@ -73,16 +85,16 @@ namespace OpenRA.Graphics
private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll )
{
s.SetValue( "Palette", PaletteTexture );
s.SetValue( "Scroll", scroll.X, scroll.Y );
s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y );
s.SetValue( "r1", r1.X, r1.Y );
s.SetValue( "r2", r2.X, r2.Y );
s.Commit();
}
public void EndFrame()
public void EndFrame( IInputHandler inputHandler )
{
device.End();
device.Present();
Flush();
device.Present( inputHandler );
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
@@ -111,15 +123,9 @@ namespace OpenRA.Graphics
public void Flush()
{
WorldSpriteRenderer.Flush();
RgbaSpriteRenderer.Flush();
LineRenderer.Flush();
CurrentBatchRenderer = null;
}
static IGraphicsDevice device;
public static Size Resolution { get { return device.WindowSize; } }
@@ -127,14 +133,14 @@ namespace OpenRA.Graphics
internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode )
{
var resolution = GetResolution( windowMode );
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Gl.dll" ) ), resolution.Width, resolution.Height, windowMode, false );
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false );
}
static Size GetResolution(WindowMode windowmode)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize;
if (customSize.X > 0 && customSize.Y > 0)
{
desktopResolution.Width = customSize.X;
@@ -154,5 +160,49 @@ namespace OpenRA.Graphics
}
throw new NotImplementedException();
}
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{
var ret = tempBuffersV.Dequeue();
tempBuffersV.Enqueue( ret );
return ret;
}
internal IIndexBuffer GetTempIndexBuffer()
{
var ret = tempBuffersI.Dequeue();
tempBuffersI.Enqueue( ret );
return ret;
}
public interface IBatchRenderer
{
void Flush();
}
static IBatchRenderer currentBatchRenderer;
public static IBatchRenderer CurrentBatchRenderer
{
get { return currentBatchRenderer; }
set
{
if( currentBatchRenderer == value ) return;
if( currentBatchRenderer != null )
currentBatchRenderer.Flush();
currentBatchRenderer = value;
}
}
public void EnableScissor(int left, int top, int width, int height)
{
Flush();
Device.EnableScissor( left, top, width, height );
}
public void DisableScissor()
{
Flush();
Device.DisableScissor();
}
}
}

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Graphics
Name = name;
var d = info.NodesDict;
sprites = SpriteSheetBuilder.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
start = int.Parse(d["Start"].Value);
if (!d.ContainsKey("Length"))

View File

@@ -12,7 +12,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
@@ -21,15 +20,13 @@ namespace OpenRA.Graphics
{
static Dictionary<string, Dictionary<string, Sequence>> units;
public static void Initialize(string[] sequenceFiles)
public static void Initialize(string[] sequenceFiles, List<MiniYamlNode> sequenceNodes)
{
units = new Dictionary<string, Dictionary<string, Sequence>>();
if (sequenceFiles.Length == 0)
return;
var sequences = sequenceFiles
.Select(s => MiniYaml.FromFile(s))
.Aggregate(MiniYaml.Merge);
var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge);
foreach (var s in sequences)
LoadSequencesForUnit(s.Key, s.Value);
@@ -58,8 +55,12 @@ namespace OpenRA.Graphics
try { return units[unitName][sequenceName]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
if (units.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
else
throw new InvalidOperationException(
"Unit `{0}` does not have any sequences defined.".F(unitName));
}
}

View File

@@ -0,0 +1,161 @@
#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;
namespace OpenRA.Graphics
{
public class ShroudRenderer
{
Traits.Shroud shroud;
Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow");
Sprite[,] sprites, fogSprites;
bool dirty = true;
Map map;
public ShroudRenderer(World world)
{
this.shroud = world.LocalShroud;
this.map = world.Map;
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
shroud.Dirty += () => dirty = true;
}
static readonly byte[][] SpecialShroudTiles =
{
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
new byte[] { 44 },
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
new byte[] { 40 },
new byte[] { 35, 24, 17, 18 },
new byte[] { 39, 39, 29, 29 },
new byte[] { 45 },
new byte[] { 43 },
new byte[] { 38, 28 },
new byte[] { 42 },
new byte[] { 41 },
new byte[] { 46 },
};
Sprite ChooseShroud(int i, int j)
{
if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
var uSides = u;
if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1;
if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2;
if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4;
if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8;
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
}
Sprite ChooseFog(int i, int j)
{
if (!shroud.IsVisible(i,j)) return shadowBits[0xf];
if (!shroud.IsExplored(i, j)) return shadowBits[0xf];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
var uSides = u;
if (!shroud.IsVisible(i - 1, j - 1)) u |= 1;
if (!shroud.IsVisible(i + 1, j - 1)) u |= 2;
if (!shroud.IsVisible(i + 1, j + 1)) u |= 4;
if (!shroud.IsVisible(i - 1, j + 1)) u |= 8;
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
}
internal void Draw( WorldRenderer wr )
{
if (dirty)
{
dirty = false;
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
sprites[i, j] = ChooseShroud(i, j);
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
fogSprites[i, j] = ChooseFog(i, j);
}
var clipRect = Game.viewport.WorldBounds(wr.world);
DrawShroud( wr, clipRect, fogSprites, "fog" );
DrawShroud( wr, clipRect, sprites, "shroud" );
}
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal )
{
var shroudPalette = wr.GetPaletteIndex(pal);
for (var j = clip.Top; j < clip.Bottom; j++)
{
var starti = clip.Left;
var last = shadowBits[0x0f];
for (var i = clip.Left; i < clip.Right; i++)
{
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
continue;
if (starti != i)
{
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i + 1;
}
s[i, j].DrawAt(
Game.CellSize * new float2(i, j),
shroudPalette);
starti = i + 1;
last = s[i, j];
}
if (starti < clip.Right)
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
}
}
}
}

View File

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

View File

@@ -69,6 +69,19 @@ namespace OpenRA.Graphics
}
}
public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset > 0)
{
DrawText(text, location + new float2(-offset, 0), bg);
DrawText(text, location + new float2(offset, 0), bg);
DrawText(text, location + new float2(0, -offset), bg);
DrawText(text, location + new float2(0, offset), bg);
}
DrawText(text, location, fg);
}
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size);
@@ -80,17 +93,20 @@ namespace OpenRA.Graphics
GlyphInfo CreateGlyph(Pair<char,Color> c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
throw new InvalidOperationException( "FT_Load_Glyph failed." );
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
var s = builder.Allocate(
new Size(_glyph.metrics.width.ToInt32() >> 6,
_glyph.metrics.height.ToInt32() >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance / 64f,
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
};

View File

@@ -13,23 +13,25 @@ using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public static class SpriteSheetBuilder
public class SpriteLoader
{
public static void Initialize( TileSet tileset )
public SpriteLoader( string[] exts, SheetBuilder sheetBuilder )
{
exts = tileset.Extensions;
SheetBuilder = sheetBuilder;
this.exts = exts;
sprites = new Cache<string, Sprite[]>( LoadSprites );
}
static Cache<string, Sprite[]> sprites;
static string[] exts;
readonly SheetBuilder SheetBuilder;
readonly Cache<string, Sprite[]> sprites;
readonly string[] exts;
static Sprite[] LoadSprites(string filename)
Sprite[] LoadSprites(string filename)
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => Game.modData.SheetBuilder.Add(a.Image, shp.Size)).ToArray();
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
public static Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
}
}

View File

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

View File

@@ -34,20 +34,21 @@ namespace OpenRA.Graphics
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
Vertex[] vertices = new Vertex[4 * map.Height * map.Width];
ushort[] indices = new ushort[6 * map.Height * map.Width];
Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width];
terrainSheet = tileMapping[map.MapTiles[map.TopLeft.X, map.TopLeft.Y]].sheet;
terrainSheet = tileMapping[map.MapTiles[map.Bounds.Left, map.Bounds.Top]].sheet;
int nv = 0;
int ni = 0;
for( int j = map.TopLeft.Y ; j < map.BottomRight.Y; j++ )
for( int i = map.TopLeft.X ; i < map.BottomRight.X; i++ )
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )
{
Sprite tile = tileMapping[map.MapTiles[i, j]];
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
// before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni, tile.size);
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size);
nv += 4;
ni += 6;
@@ -56,36 +57,36 @@ namespace OpenRA.Graphics
}
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices );
vertexBuffer.SetData( vertices, nv );
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices );
indexBuffer.SetData( indices, ni );
}
public void Draw( Viewport viewport )
public void Draw( WorldRenderer wr, Viewport viewport )
{
int indicesPerRow = map.Width * 6;
int verticesPerRow = map.Width * 4;
int indicesPerRow = map.Bounds.Width * 6;
int verticesPerRow = map.Bounds.Width * 4;
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.YOffset);
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top);
int lastRow = firstRow + visibleRows;
if (lastRow < 0 || firstRow > map.Height)
if (lastRow < 0 || firstRow > map.Bounds.Height)
return;
if (firstRow < 0) firstRow = 0;
if (lastRow > map.Height) lastRow = map.Height;
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
{
var r = world.LocalPlayer.Shroud.Bounds.Value;
if (firstRow < r.Top - map.YOffset)
firstRow = r.Top - map.YOffset;
var r = world.LocalShroud.Bounds.Value;
if (firstRow < r.Top - map.Bounds.Top)
firstRow = r.Top - map.Bounds.Top;
if (firstRow > r.Bottom - map.YOffset)
firstRow = r.Bottom - map.YOffset;
if (firstRow > r.Bottom - map.Bounds.Top)
firstRow = r.Bottom - map.Bounds.Top;
}
if( lastRow < firstRow ) lastRow = firstRow;
@@ -98,7 +99,7 @@ namespace OpenRA.Graphics
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
r.Render();
r.Render( wr );
}
}
}

135
OpenRA.Game/Graphics/Viewport.cs Normal file → Executable file
View File

@@ -11,24 +11,21 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA.Graphics
{
public class Viewport
{
readonly float2 screenSize;
float2 scrollPosition;
readonly int2 screenSize;
int2 scrollPosition;
readonly Renderer renderer;
readonly int2 mapStart;
readonly int2 mapEnd;
readonly Rectangle adjustedMapBounds;
public float2 Location { get { return scrollPosition; } }
public int Width { get { return (int)screenSize.X; } }
public int Height { get { return (int)screenSize.Y; } }
public int Width { get { return screenSize.X; } }
public int Height { get { return screenSize.Y; } }
float cursorFrame = 0f;
@@ -42,7 +39,8 @@ namespace OpenRA.Graphics
public void Scroll(float2 delta, bool ignoreBorders)
{
float2 newScrollPosition = scrollPosition + delta;
var d = delta.ToInt2();
var newScrollPosition = scrollPosition + d;
if(!ignoreBorders)
newScrollPosition = this.NormalizeScrollPosition(newScrollPosition);
@@ -50,80 +48,53 @@ namespace OpenRA.Graphics
scrollPosition = newScrollPosition;
}
private float2 NormalizeScrollPosition(float2 newScrollPosition)
private int2 NormalizeScrollPosition(int2 newScrollPosition)
{
float2 topLeftBorder = (Game.CellSize* mapStart).ToFloat2();
float2 bottomRightBorder = (Game.CellSize* mapEnd).ToFloat2();
if(newScrollPosition.Y < topLeftBorder.Y - screenSize.Y/2)
newScrollPosition.Y = topLeftBorder.Y - screenSize.Y/2;
if(newScrollPosition.X < topLeftBorder.X - screenSize.X/2)
newScrollPosition.X = topLeftBorder.X - screenSize.X/2;
if(newScrollPosition.Y > bottomRightBorder.Y - screenSize.Y/2)
newScrollPosition.Y = bottomRightBorder.Y - screenSize.Y/2;
if(newScrollPosition.X > bottomRightBorder.X - screenSize.X/2)
newScrollPosition.X = bottomRightBorder.X - screenSize.X/2;
return newScrollPosition;
return newScrollPosition.Clamp(adjustedMapBounds);
}
public ScrollDirection GetBlockedDirections()
{
int2 topLeftBorder = (Game.CellSize* mapStart);
int2 bottomRightBorder = (Game.CellSize* mapEnd);
ScrollDirection blockedDirections = ScrollDirection.None;
if(scrollPosition.Y <= topLeftBorder.Y - screenSize.Y/2)
if(scrollPosition.Y <= adjustedMapBounds.Top)
blockedDirections = blockedDirections.Set(ScrollDirection.Up, true);
if(scrollPosition.X <= topLeftBorder.X - screenSize.X/2)
if(scrollPosition.X <= adjustedMapBounds.Left)
blockedDirections = blockedDirections.Set(ScrollDirection.Left, true);
if(scrollPosition.Y >= bottomRightBorder.Y - screenSize.Y/2)
if(scrollPosition.Y >= adjustedMapBounds.Bottom)
blockedDirections = blockedDirections.Set(ScrollDirection.Down, true);
if(scrollPosition.X >= bottomRightBorder.X - screenSize.X/2)
if(scrollPosition.X >= adjustedMapBounds.Right)
blockedDirections = blockedDirections.Set(ScrollDirection.Right, true);
return blockedDirections;
}
public Viewport(float2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer)
{
this.screenSize = screenSize;
this.renderer = renderer;
this.mapStart = mapStart;
this.mapEnd = mapEnd;
this.scrollPosition = Game.CellSize* mapStart;
this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2,
Game.CellSize*mapBounds.Y - screenSize.Y/2,
Game.CellSize*mapBounds.Width,
Game.CellSize*mapBounds.Height);
this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2;
}
public void DrawRegions( World world )
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
{
renderer.BeginFrame(scrollPosition);
world.WorldRenderer.Draw();
Widget.DoDraw(world);
if (wr != null)
wr.Draw();
Widget.DoDraw();
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
var c = new Cursor(cursorName);
c.Draw((int)cursorFrame, Viewport.LastMousePos + Location);
new Cursor(cursorName).Draw((int)cursorFrame, Viewport.LastMousePos + Location);
renderer.RgbaSpriteRenderer.Flush();
renderer.SpriteRenderer.Flush();
renderer.WorldSpriteRenderer.Flush();
renderer.EndFrame();
}
public void RefreshPalette()
{
Game.world.WorldRenderer.palette.Update(
Game.world.WorldActor.TraitsImplementing<IPaletteModifier>());
renderer.EndFrame( inputHandler );
}
public void Tick()
{
cursorFrame += 0.5f;
RefreshPalette();
}
public float2 ViewToWorld(int2 loc)
@@ -135,36 +106,52 @@ namespace OpenRA.Graphics
return ViewToWorld(mi.Location);
}
public void Center(int2 loc)
public void Center(float2 loc)
{
scrollPosition = this.NormalizeScrollPosition(Game.CellSize*loc - .5f * new float2(Width, Height));
scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2());
}
public void Center(IEnumerable<Actor> actors)
{
if (!actors.Any()) return;
var avgPos = (1f / actors.Count()) * actors
var avgPos = actors
.Select(a => a.CenterLocation)
.Aggregate((a, b) => a + b);
scrollPosition = this.NormalizeScrollPosition((avgPos - .5f * new float2(Width, Height)));
}
public Rectangle? ShroudBounds()
{
var localPlayer = Game.world.LocalPlayer;
if (localPlayer == null) return null;
if (localPlayer.Shroud.Disabled) return null;
return localPlayer.Shroud.Bounds;
.Aggregate((a, b) => a + b) / actors.Count();
scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2));
}
public Rectangle ViewBounds()
public Rectangle ViewBounds(World world)
{
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
var r = WorldBounds(world);
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
var right = left + (int)(Game.CellSize * r.Width);
var bottom = top + (int)(Game.CellSize * r.Height);
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > Game.viewport.Width) right = Game.viewport.Width;
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
return new Rectangle(left, top, right - left, bottom - top);
}
int2 cachedScroll = new int2(int.MaxValue, int.MaxValue);
Rectangle cachedRect;
public Rectangle WorldBounds(World world)
{
if (cachedScroll != scrollPosition)
{
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds);
cachedScroll = scrollPosition;
}
var b = world.LocalShroud.Bounds;
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
}
}
}

View File

@@ -19,18 +19,23 @@ namespace OpenRA.Graphics
{
public class WorldRenderer
{
readonly World world;
public readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly ShroudRenderer shroudRenderer;
public readonly UiOverlay uiOverlay;
internal readonly HardwarePalette palette;
internal WorldRenderer(World world)
{
this.world = world;
this.palette = Game.modData.Palette;
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) )
pal.Trait.InitPalette( this );
terrainRenderer = new TerrainRenderer(world, this);
shroudRenderer = new ShroudRenderer(world);
uiOverlay = new UiOverlay();
palette = new HardwarePalette(world.Map);
}
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
@@ -45,32 +50,9 @@ namespace OpenRA.Graphics
}
}
Rectangle GetBoundsRect()
IEnumerable<Renderable> SpritesToRender()
{
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
{
var r = world.LocalPlayer.Shroud.Bounds.Value;
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
var right = left + (int)(Game.CellSize * r.Width);
var bottom = top + (int)(Game.CellSize * r.Height);
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > Game.viewport.Width) right = Game.viewport.Width;
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
return new Rectangle(left, top, right - left, bottom - top);
}
else
return new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
}
Renderable[] worldSprites = { };
public void Tick()
{
var bounds = GetBoundsRect();
var bounds = Game.viewport.ViewBounds(world);
var comparer = new SpriteComparer();
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
@@ -84,38 +66,52 @@ namespace OpenRA.Graphics
var effects = world.Effects.SelectMany(e => e.Render());
worldSprites = renderables.Concat(effects).ToArray();
return renderables.Concat(effects);
}
public void Draw()
{
var bounds = GetBoundsRect();
Game.Renderer.Device.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
RefreshPalette();
var bounds = Game.viewport.ViewBounds(world);
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
terrainRenderer.Draw(Game.viewport);
terrainRenderer.Draw(this, Game.viewport);
foreach (var a in world.traitDict.ActorsWithTraitMultiple<IRenderAsTerrain>(world))
foreach (var r in a.Trait.RenderAsTerrain(a.Actor))
r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale);
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(this, a);
Game.Renderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(this, world);
foreach (var image in SpritesToRender() )
image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale);
uiOverlay.Draw(this, world);
// added for contrails
foreach (var a in world.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRender>())
t.RenderAfterWorld(this, a);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(world);
world.OrderGenerator.RenderAfterWorld(this, world);
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.LineRenderer.Flush();
shroudRenderer.Draw( this );
Game.Renderer.DisableScissor();
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(this, a);
foreach (var image in worldSprites)
Game.Renderer.SpriteRenderer.DrawSprite(image.Sprite, image.Pos, image.Palette);
uiOverlay.Draw(world);
Game.Renderer.SpriteRenderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(world);
if (world.LocalPlayer != null)
world.LocalPlayer.Shroud.Draw();
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
Game.Renderer.LineRenderer.Flush();
Game.Renderer.Flush();
}
void DrawBox(RectangleF r, Color color)
@@ -129,23 +125,9 @@ namespace OpenRA.Graphics
Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color);
}
void DrawBins(RectangleF bounds)
{
DrawBox(bounds, Color.Red);
if (world.LocalPlayer != null)
DrawBox(world.LocalPlayer.Shroud.Bounds.Value, Color.Blue);
for (var j = 0; j < world.Map.MapSize.Y;
j += world.WorldActor.Info.Traits.Get<SpatialBinsInfo>().BinSize)
{
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * Game.CellSize), new float2(world.Map.MapSize.X * Game.CellSize, j * Game.CellSize), Color.Black, Color.Black);
Game.Renderer.LineRenderer.DrawLine(new float2(j * Game.CellSize, 0), new float2(j * Game.CellSize, world.Map.MapSize.Y * Game.CellSize), Color.Black, Color.Black);
}
}
public void DrawSelectionBox(Actor selectedUnit, Color c)
{
var bounds = selectedUnit.GetBounds(true);
var bounds = selectedUnit.GetBounds(false);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
@@ -183,7 +165,7 @@ namespace OpenRA.Graphics
}
}
public void DrawRangeCircle(Color c, float2 location, int range)
public void DrawRangeCircle(Color c, float2 location, float range)
{
var prev = location + Game.CellSize * range * float2.FromAngle(0);
for (var i = 1; i <= 32; i++)
@@ -193,5 +175,10 @@ namespace OpenRA.Graphics
prev = pos;
}
}
public void RefreshPalette()
{
palette.Update( world.WorldActor.TraitsImplementing<IPaletteModifier>() );
}
}
}

52
OpenRA.Game/InputHandler.cs Executable file
View File

@@ -0,0 +1,52 @@
#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.Widgets;
namespace OpenRA
{
public class NullInputHandler : IInputHandler
{
// ignore all input
public void ModifierKeys( Modifiers mods ) { }
public void OnKeyInput( KeyInput input ) { }
public void OnMouseInput( MouseInput input ) { }
}
public class DefaultInputHandler : IInputHandler
{
readonly World world;
public DefaultInputHandler( World world )
{
this.world = world;
}
public void ModifierKeys( Modifiers mods )
{
Game.HandleModifierKeys( mods );
}
public void OnKeyInput( KeyInput input )
{
Sync.CheckSyncUnchanged( world, () =>
{
Widget.HandleKeyPress( input );
} );
}
public void OnMouseInput( MouseInput input )
{
Sync.CheckSyncUnchanged( world, () =>
{
Widget.HandleInput( input );
} );
}
}
}

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

@@ -16,76 +16,65 @@ using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using OpenRA.FileFormats;
using System.Text;
namespace OpenRA
{
public class Map
public class Map : MapStub
{
public IFolder Package;
public string Uid;
// Yaml map data
[FieldLoader.Load] public bool Selectable = true;
[FieldLoader.Load] public int MapFormat;
[FieldLoader.Load] public string Title;
[FieldLoader.Load] public string Description;
[FieldLoader.Load] public string Author;
[FieldLoader.Load] public int PlayerCount;
[FieldLoader.Load] public string Tileset;
public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>();
public Dictionary<string, ActorReference> Actors = new Dictionary<string, ActorReference>();
public List<SmudgeReference> Smudges = new List<SmudgeReference>();
public Dictionary<string, int2> Waypoints = new Dictionary<string, int2>();
// Rules overrides
// Rules overrides
public List<MiniYamlNode> Rules = new List<MiniYamlNode>();
// Sequences overrides
public List<MiniYamlNode> Sequences = new List<MiniYamlNode>();
// Weapon overrides
public List<MiniYamlNode> Weapons = new List<MiniYamlNode>();
// Voices overrides
public List<MiniYamlNode> Voices = new List<MiniYamlNode>();
// Binary map data
public byte TileFormat = 1;
[FieldLoader.Load] public int2 MapSize;
[FieldLoader.Load] public int2 TopLeft;
[FieldLoader.Load] public int2 BottomRight;
public TileReference<ushort, byte>[,] MapTiles;
public TileReference<byte, byte>[,] MapResources;
public string [,] CustomTerrain;
// Temporary compat hacks
public int XOffset { get { return TopLeft.X; } }
public int YOffset { get { return TopLeft.Y; } }
public int Width { get { return BottomRight.X - TopLeft.X; } }
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
public string Theater { get { return Tileset; } }
public IEnumerable<int2> SpawnPoints { get { return Waypoints.Select(kv => kv.Value); } }
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
public Map()
{
// Do nothing; not a valid map (editor hack)
}
public Map(string tileset)
public static Map FromTileset(string tileset)
{
MapSize = new int2(1, 1);
Tileset = tileset;
MapResources = new TileReference<byte, byte>[1, 1];
var tile = OpenRA.Rules.TileSets[Tileset].Templates.First();
MapTiles = new TileReference<ushort, byte>[1, 1]
var tile = OpenRA.Rules.TileSets[tileset].Templates.First();
Map map = new Map()
{
Title = "Name your map here",
Description = "Describe your map here",
Author = "Your name here",
MapSize = new int2(1, 1),
PlayerCount = 0,
Tileset = tileset,
MapResources = new TileReference<byte, byte>[1, 1],
MapTiles = new TileReference<ushort, byte>[1, 1]
{ { new TileReference<ushort, byte> {
type = tile.Key,
image = (byte)(tile.Value.PickAny ? 0xffu : 0),
index = (byte)(tile.Value.PickAny ? 0xffu : 0) } } };
PlayerCount = 0;
TopLeft = new int2(0, 0);
BottomRight = new int2(0, 0);
Title = "Name your map here";
Description = "Describe your map here";
Author = "Your name here";
index = (byte)(tile.Value.PickAny ? 0xffu : 0) }
} },
};
return map;
}
class Format2ActorReference
@@ -95,21 +84,15 @@ namespace OpenRA
public int2 Location = int2.Zero;
public string Owner = null;
}
public Map(IFolder package)
public Map(string path)
: base(path)
{
Package = package;
var yaml = new MiniYaml( null, MiniYaml.FromStream( Package.GetContent( "map.yaml" ) ) );
var yaml = new MiniYaml( null, MiniYaml.FromStream( Container.GetContent( "map.yaml" ) ) );
// 'Simple' metadata
FieldLoader.Load( this, yaml );
// Waypoints
foreach (var wp in yaml.NodesDict["Waypoints"].NodesDict)
{
string[] loc = wp.Value.Value.Split(',');
Waypoints.Add(wp.Key, new int2(int.Parse(loc[0]), int.Parse(loc[1])));
}
// Players & Actors -- this has changed several times.
// - Be backwards compatible wherever possible.
@@ -156,6 +139,7 @@ namespace OpenRA
} break;
case 3:
case 4:
{
foreach (var kv in yaml.NodesDict["Players"].NodesDict)
{
@@ -185,7 +169,16 @@ namespace OpenRA
};
Players.Add(p.Name, p);
}
}
}
// Color1/Color2 -> ColorRamp
if (MapFormat == 3)
foreach (var mp in Players)
mp.Value.ColorRamp = new ColorRamp(
(byte)((mp.Value.Color.GetHue() / 360.0f) * 255),
(byte)(mp.Value.Color.GetSaturation() * 255),
(byte)(mp.Value.Color.GetBrightness() * 255),
(byte)(mp.Value.Color2.GetBrightness() * 255));
// Smudges
foreach (var kv in yaml.NodesDict["Smudges"].NodesDict)
@@ -198,19 +191,29 @@ namespace OpenRA
// Rules
Rules = yaml.NodesDict["Rules"].Nodes;
// Sequences
Sequences = (yaml.NodesDict.ContainsKey("Sequences")) ? yaml.NodesDict["Sequences"].Nodes : new List<MiniYamlNode>();
// Weapons
Weapons = (yaml.NodesDict.ContainsKey("Weapons")) ? yaml.NodesDict["Weapons"].Nodes : new List<MiniYamlNode>();
// Voices
Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List<MiniYamlNode>();
CustomTerrain = new string[MapSize.X, MapSize.Y];
LoadUid();
LoadBinaryData();
}
public void Save(string filepath)
{
MapFormat = 3;
public void Save(string toPath)
{
Console.WriteLine("Saving map to path {0}",toPath);
// Todo: save to a zip file in the support dir by default
MapFormat = 4;
var root = new List<MiniYamlNode>();
foreach (var field in new string[] {"Selectable", "MapFormat", "Title", "Description", "Author", "PlayerCount", "Tileset", "MapSize", "TopLeft", "BottomRight"})
foreach (var field in new string[] {"Selectable", "MapFormat", "Title", "Description", "Author", "PlayerCount", "Tileset", "MapSize", "TopLeft", "BottomRight", "UseAsShellmap", "Type"})
{
FieldInfo f = this.GetType().GetField(field);
var f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
@@ -225,13 +228,30 @@ namespace OpenRA
x.Key,
x.Value.Save() ) ).ToList() ) );
root.Add( new MiniYamlNode( "Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints ) ) );
root.Add( new MiniYamlNode( "Smudges", MiniYaml.FromList<SmudgeReference>( Smudges ) ) );
root.Add( new MiniYamlNode( "Rules", null, Rules ) );
SaveBinaryData(Path.Combine(filepath, "map.bin"));
root.WriteToFile(Path.Combine(filepath, "map.yaml"));
SaveUid(Path.Combine(filepath, "map.uid"));
root.Add(new MiniYamlNode("Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints )));
root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList<SmudgeReference>( Smudges )));
root.Add(new MiniYamlNode("Rules", null, Rules));
root.Add(new MiniYamlNode("Sequences", null, Sequences));
root.Add(new MiniYamlNode("Weapons", null, Weapons));
root.Add(new MiniYamlNode("Voices", null, Voices));
Dictionary<string, byte[]> entries = new Dictionary<string, byte[]>();
entries.Add("map.bin", SaveBinaryData());
var s = root.WriteToString();
entries.Add("map.yaml", Encoding.UTF8.GetBytes(s));
// Saving the map to a new location
if (toPath != Path)
{
Path = toPath;
// Create a new map package
// TODO: Add other files (resources, rules) to the entries list
Container = FileSystem.CreatePackage(Path, int.MaxValue, entries);
}
// Update existing package
Container.Write(entries);
}
static byte ReadByte(Stream s)
@@ -252,7 +272,7 @@ namespace OpenRA
public void LoadBinaryData()
{
using (var dataStream = Package.GetContent("map.bin"))
using (var dataStream = Container.GetContent("map.bin"))
{
if (ReadByte(dataStream) != 1)
throw new InvalidDataException("Unknown binary map format");
@@ -284,9 +304,9 @@ namespace OpenRA
}
}
public void SaveBinaryData(string filepath)
public byte[] SaveBinaryData()
{
using (var dataStream = File.Create(filepath + ".tmp"))
MemoryStream dataStream = new MemoryStream();
using (var writer = new BinaryWriter(dataStream))
{
// File header consists of a version byte, followed by 2 ushorts for width and height
@@ -310,27 +330,7 @@ namespace OpenRA
writer.Write(MapResources[i, j].index);
}
}
File.Delete(filepath);
File.Move(filepath + ".tmp", filepath);
}
public void LoadUid()
{
Uid = Package.GetContent("map.uid").ReadAllText();
}
public void SaveUid(string filename)
{
// UID is calculated by taking an SHA1 of the yaml and binary data
// Read the relevant data into a buffer
var data = Package.GetContent("map.yaml").ReadAllBytes()
.Concat(Package.GetContent("map.bin").ReadAllBytes()).ToArray();
// Take the SHA1
using (var csp = SHA1.Create())
Uid = new string(csp.ComputeHash(data).SelectMany(a => a.ToString("x2")).ToArray());
File.WriteAllText(filename, Uid);
return dataStream.ToArray();
}
public bool IsInMap(int2 xy)
@@ -340,7 +340,7 @@ namespace OpenRA
public bool IsInMap(int x, int y)
{
return (x >= TopLeft.X && y >= TopLeft.Y && x < BottomRight.X && y < BottomRight.Y);
return Bounds.Contains(x,y);
}
static T[,] ResizeArray<T>(T[,] ts, T t, int width, int height)
@@ -359,5 +359,12 @@ namespace OpenRA
MapResources = ResizeArray(MapResources, MapResources[0, 0], width, height);
MapSize = new int2(width, height);
}
public void ResizeCordon(int left, int top, int right, int bottom)
{
TopLeft = new int2(left, top);
BottomRight = new int2(right, bottom);
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
}
}
}

View File

@@ -1,77 +1,122 @@
#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.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Support;
namespace OpenRA
{
public class ModData
{
public readonly Manifest Manifest;
public readonly ObjectCreator ObjectCreator;
public readonly SheetBuilder SheetBuilder;
public readonly CursorSheetBuilder CursorSheetBuilder;
public readonly Dictionary<string, MapStub> AvailableMaps;
public ILoadScreen LoadScreen = null;
public ModData( params string[] mods )
{
Manifest = new Manifest( mods );
ObjectCreator = new ObjectCreator( Manifest );
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
LoadScreen.Init();
LoadScreen.Display();
FileSystem.LoadFromManifest( Manifest );
ChromeProvider.Initialize( Manifest.Chrome );
SheetBuilder = new SheetBuilder( TextureChannel.Red );
CursorSheetBuilder = new CursorSheetBuilder( this );
AvailableMaps = FindMaps( mods );
}
// TODO: Do this nicer
Dictionary<string, MapStub> FindMaps(string[] mods)
{
var paths = new[] { "maps/" }.Concat(mods.Select(m => "mods/" + m + "/maps/"))
.Where(p => Directory.Exists(p))
.SelectMany(p => Directory.GetDirectories(p)).ToList();
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
}
string cachedTheatre = null;
public Map PrepareMap(string uid)
{
LoadScreen.Display();
if (!AvailableMaps.ContainsKey(uid))
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
var map = new Map(AvailableMaps[uid].Package);
Rules.LoadRules(Manifest, map);
if (map.Theater != cachedTheatre)
{
SpriteSheetBuilder.Initialize( Rules.TileSets[map.Tileset] );
SequenceProvider.Initialize(Manifest.Sequences);
CursorProvider.Initialize(Manifest.Cursors);
cachedTheatre = map.Theater;
}
return map;
}
}
public interface ILoadScreen { void Display(); void Init(); }
}
#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.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA
{
public class ModData
{
public readonly Manifest Manifest;
public readonly ObjectCreator ObjectCreator;
public Dictionary<string, MapStub> AvailableMaps {get; private set;}
public readonly WidgetLoader WidgetLoader;
public ILoadScreen LoadScreen = null;
public SheetBuilder SheetBuilder;
public CursorSheetBuilder CursorSheetBuilder;
public SpriteLoader SpriteLoader;
public HardwarePalette Palette { get; private set; }
IFolder previousMapMount = null;
public ModData( params string[] mods )
{
Manifest = new Manifest( mods );
ObjectCreator = new ObjectCreator( Manifest );
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
LoadScreen.Init();
LoadScreen.Display();
WidgetLoader = new WidgetLoader( this );
}
public void ReloadMaps()
{
AvailableMaps = FindMaps( Manifest.Mods );
}
public void LoadInitialAssets()
{
// all this manipulation of static crap here is nasty and breaks
// horribly when you use ModData in unexpected ways.
FileSystem.UnmountAll();
foreach (var dir in Manifest.Folders)
FileSystem.Mount(dir);
ReloadMaps();
Palette = new HardwarePalette();
ChromeProvider.Initialize( Manifest.Chrome );
SheetBuilder = new SheetBuilder( TextureChannel.Red );
CursorSheetBuilder = new CursorSheetBuilder( this );
CursorProvider.Initialize(Manifest.Cursors);
Palette.Update(new IPaletteModifier[]{});
}
public Map PrepareMap(string uid)
{
LoadScreen.Display();
if (!AvailableMaps.ContainsKey(uid))
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
var map = new Map(AvailableMaps[uid].Path);
// Maps may contain custom assets
// TODO: why are they lowest priority? they should be highest.
if (previousMapMount != null) FileSystem.Unmount(previousMapMount);
previousMapMount = FileSystem.OpenPackage(map.Path, int.MaxValue);
FileSystem.Mount(previousMapMount);
// Reinit all our assets
LoadInitialAssets();
foreach (var pkg in Manifest.Packages)
FileSystem.Mount(pkg);
Rules.LoadRules(Manifest, map);
SpriteLoader = new SpriteLoader( Rules.TileSets[map.Tileset].Extensions, SheetBuilder );
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences);
return map;
}
public static IEnumerable<string> FindMapsIn(string dir)
{
string[] NoMaps = { };
if (!Directory.Exists(dir))
return NoMaps;
return Directory.GetDirectories(dir)
.Concat(Directory.GetFiles(dir, "*.zip"))
.Concat(Directory.GetFiles(dir, "*.oramap"));
}
Dictionary<string, MapStub> FindMaps(string[] mods)
{
var paths = mods.SelectMany(p => FindMapsIn("mods{0}{1}{0}maps{0}".F(Path.DirectorySeparatorChar, p)))
.Concat(mods.SelectMany(p => FindMapsIn("{1}maps{0}{2}{0}".F(Path.DirectorySeparatorChar, Game.SupportDir, p))));
Dictionary<string, MapStub> ret = new Dictionary<string, MapStub>();
foreach (var path in paths)
{
var map = new MapStub(path);
if (ret.ContainsKey(map.Uid))
System.Console.WriteLine("Ignoring duplicate map: {0}", path);
else
ret.Add(map.Uid, map);
}
return ret;
}
}
public interface ILoadScreen { void Display(); void Init(); }
}

View File

@@ -18,7 +18,7 @@ using OpenRA.Support;
namespace OpenRA.Network
{
enum ConnectionState
public enum ConnectionState
{
PreConnecting,
NotConnected,
@@ -26,11 +26,13 @@ namespace OpenRA.Network
Connected,
}
interface IConnection
public interface IConnection : IDisposable
{
int LocalClientId { get; }
ConnectionState ConnectionState { get; }
void Send( byte[] packet );
void Send( int frame, List<byte[]> orders );
void SendImmediate( List<byte[]> orders );
void SendSync( int frame, byte[] syncData );
void Receive( Action<int, byte[]> packetFn );
}
@@ -53,7 +55,33 @@ namespace OpenRA.Network
get { return ConnectionState.PreConnecting; }
}
public virtual void Send( byte[] packet )
public virtual void Send( int frame, List<byte[]> orders )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( frame ) );
foreach( var o in orders )
ms.Write( o );
Send( ms.ToArray() );
}
public virtual void SendImmediate( List<byte[]> orders )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( (int)0 ) );
foreach( var o in orders )
ms.Write( o );
Send( ms.ToArray() );
}
public virtual void SendSync( int frame, byte[] syncData )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( frame ) );
ms.Write( syncData );
Send( ms.ToArray() );
}
protected virtual void Send( byte[] packet )
{
if( packet.Length == 0 )
throw new NotImplementedException();
@@ -73,9 +101,11 @@ namespace OpenRA.Network
foreach( var p in packets )
packetFn( p.FromClient, p.Data );
}
public virtual void Dispose() { }
}
class NetworkConnection : EchoConnection, IDisposable
class NetworkConnection : EchoConnection
{
TcpClient socket;
int clientId;
@@ -112,12 +142,13 @@ namespace OpenRA.Network
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
}
}
catch( SocketException )
catch { }
finally
{
connectionState = ConnectionState.NotConnected;
if( socket != null )
socket.Close();
}
catch ( IOException ) { socket.Close(); }
catch (ThreadAbortException ) { socket.Close(); }
}
) { IsBackground = true };
t.Start();
@@ -126,26 +157,42 @@ namespace OpenRA.Network
public override int LocalClientId { get { return clientId; } }
public override ConnectionState ConnectionState { get { return connectionState; } }
public override void Send( byte[] packet )
List<byte[]> queuedSyncPackets = new List<byte[]>();
public override void SendSync( int frame, byte[] syncData )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( frame ) );
ms.Write( syncData );
queuedSyncPackets.Add( ms.ToArray() );
}
protected override void Send( byte[] packet )
{
base.Send( packet );
try
{
var ms = new MemoryStream();
ms.Write(BitConverter.GetBytes((int)packet.Length));
ms.Write(packet);
foreach( var q in queuedSyncPackets )
{
ms.Write( BitConverter.GetBytes( (int)q.Length ) );
ms.Write( q );
base.Send( q );
}
queuedSyncPackets.Clear();
ms.WriteTo(socket.GetStream());
}
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
catch (ObjectDisposedException) { /* ditto */ }
catch (InvalidOperationException) { /* ditto */ }
}
bool disposed = false;
public void Dispose ()
public override void Dispose ()
{
if (disposed) return;
disposed = true;
@@ -160,48 +207,4 @@ namespace OpenRA.Network
~NetworkConnection() { Dispose(); }
}
class ReplayConnection : IConnection
{
//uint nextFrame = 1;
FileStream replayStream;
public ReplayConnection( string replayFilename )
{
replayStream = File.OpenRead( replayFilename );
}
public int LocalClientId
{
get { return 0; }
}
public ConnectionState ConnectionState
{
get { return ConnectionState.Connected; }
}
public void Send( byte[] packet )
{
// do nothing; ignore locally generated orders
}
public void Receive( Action<int, byte[]> packetFn )
{
if( replayStream == null ) return;
var reader = new BinaryReader( replayStream );
while( replayStream.Position < replayStream.Length )
{
var client = reader.ReadInt32();
var packetLen = reader.ReadInt32();
var packet = reader.ReadBytes( packetLen );
packetFn( client, packet );
if( !Game.orderManager.GameStarted )
return;
}
replayStream = null;
}
}
}

View File

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

View File

@@ -0,0 +1,73 @@
#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.FileFormats;
namespace OpenRA.Network
{
public class HandshakeRequest
{
[FieldLoader.Load] public string[] Mods;
[FieldLoader.Load] public string Map;
public string Serialize()
{
var data = new List<MiniYamlNode>();
data.Add(new MiniYamlNode("Handshake", FieldSaver.Save(this)));
return data.WriteToString();
}
public static HandshakeRequest Deserialize(string data)
{
var handshake = new HandshakeRequest();
FieldLoader.Load(handshake, MiniYaml.FromString(data).First().Value);
return handshake;
}
}
public class HandshakeResponse
{
[FieldLoader.Load] public string[] Mods;
[FieldLoader.Load] public string Password;
public Session.Client Client;
public string Serialize()
{
var data = new List<MiniYamlNode>();
data.Add( new MiniYamlNode( "Handshake", null,
new string[]{ "Mods", "Password" }.Select( p => FieldSaver.SaveField(this, p) ).ToList() ) );
data.Add(new MiniYamlNode("Client", FieldSaver.Save(Client)));
return data.WriteToString();
}
public static HandshakeResponse Deserialize(string data)
{
var handshake = new HandshakeResponse();
handshake.Client = new Session.Client();
var ys = MiniYaml.FromString(data);
foreach (var y in ys)
switch (y.Key)
{
case "Handshake":
FieldLoader.Load(handshake, y.Value);
break;
case "Client":
FieldLoader.Load(handshake.Client, y.Value);
break;
}
return handshake;
}
}
}

View File

@@ -11,23 +11,43 @@
using System;
using System.IO;
using System.Linq;
using OpenRA.Network;
namespace OpenRA
{
[Flags]
enum OrderFields : byte
{
TargetActor = 0x01,
TargetLocation = 0x02,
TargetString = 0x04,
Queued = 0x08,
ExtraLocation = 0x10,
}
static class OrderFieldsExts
{
public static bool HasField(this OrderFields of, OrderFields f)
{
return (of & f) != 0;
}
}
public sealed class Order
{
public readonly string OrderString;
public readonly Actor Subject;
public readonly Actor TargetActor;
public readonly int2 TargetLocation;
public readonly string TargetString;
public readonly bool Queued;
public Actor TargetActor;
public int2 TargetLocation;
public string TargetString;
public int2 ExtraLocation;
public bool IsImmediate;
public Player Player { get { return Subject.Owner; } }
public Order(string orderString, Actor subject,
Actor targetActor, int2 targetLocation, string targetString, bool queued)
Order(string orderString, Actor subject,
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
{
this.OrderString = orderString;
this.Subject = subject;
@@ -35,24 +55,15 @@ namespace OpenRA
this.TargetLocation = targetLocation;
this.TargetString = targetString;
this.Queued = queued;
this.ExtraLocation = extraLocation;
}
public Order(string orderString, Actor subject)
: this(orderString, subject, null, int2.Zero, null, false) { }
public Order(string orderString, Actor subject, Actor targetActor)
: this(orderString, subject, targetActor, int2.Zero, null, false) { }
public Order(string orderString, Actor subject, int2 targetLocation)
: this(orderString, subject, null, targetLocation, null, false) { }
public Order(string orderString, Actor subject, int2 targetLocation, bool queued)
: this(orderString, subject, null, targetLocation, null, queued) { }
public Order(string orderString, Actor subject, string targetString)
: this(orderString, subject, null, int2.Zero, targetString, false) { }
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation)
: this(orderString, subject, targetActor, targetLocation, null, false) { }
public Order(string orderString, Actor subject, Actor targetActor, string targetString)
: this(orderString, subject, targetActor, int2.Zero, targetString, false) { }
public Order(string orderString, Actor subject, int2 targetLocation, string targetString)
: this(orderString, subject, null, targetLocation, targetString, false) { }
// For scripting special powers
public Order()
: this(null, null, null, int2.Zero, null, false, int2.Zero) { }
public Order(string orderString, Actor subject, bool queued)
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
public byte[] Serialize()
{
@@ -80,13 +91,25 @@ namespace OpenRA
w.Write( (byte)0xFF );
w.Write(OrderString);
w.Write(UIntFromActor(Subject));
w.Write(UIntFromActor(TargetActor));
w.Write(TargetLocation.X);
w.Write(TargetLocation.Y);
w.Write(TargetString != null);
OrderFields fields = 0;
if (TargetActor != null) fields |= OrderFields.TargetActor;
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
if (TargetString != null) fields |= OrderFields.TargetString;
if (Queued) fields |= OrderFields.Queued;
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
w.Write((byte)fields);
if (TargetActor != null)
w.Write(UIntFromActor(TargetActor));
if (TargetLocation != int2.Zero)
w.Write(TargetLocation);
if (TargetString != null)
w.Write(TargetString);
w.Write(Queued);
if (ExtraLocation != int2.Zero)
w.Write(ExtraLocation);
return ret.ToArray();
}
}
@@ -100,19 +123,19 @@ namespace OpenRA
{
var order = r.ReadString();
var subjectId = r.ReadUInt32();
var targetActorId = r.ReadUInt32();
var targetLocation = new int2(r.ReadInt32(), 0);
targetLocation.Y = r.ReadInt32();
var targetString = null as string;
if (r.ReadBoolean())
targetString = r.ReadString();
var queued = r.ReadBoolean();
var flags = (OrderFields)r.ReadByte();
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
var queued = flags.HasField(OrderFields.Queued);
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
Actor subject, targetActor;
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
return null;
return new Order( order, subject, targetActor, targetLocation, targetString, queued);
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
}
case 0xfe:
@@ -120,7 +143,7 @@ namespace OpenRA
var name = r.ReadString();
var data = r.ReadString();
return new Order( name, null, data ) { IsImmediate = true };
return new Order( name, null, false ) { IsImmediate = true, TargetString = data };
}
default:
@@ -130,9 +153,9 @@ namespace OpenRA
public override string ToString()
{
return "OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n".F(
OrderString, Subject, TargetActor.Info.Name , TargetLocation, TargetString, IsImmediate, Player.PlayerName);
return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F(
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
}
static uint UIntFromActor(Actor a)
@@ -164,32 +187,37 @@ namespace OpenRA
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
public static Order Chat(string text)
{
return new Order("Chat", null, text) { IsImmediate = true };
return new Order("Chat", null, false) { IsImmediate = true, TargetString = text};
}
public static Order TeamChat(string text)
{
return new Order("TeamChat", null, text) { IsImmediate = true };
return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text };
}
public static Order HandshakeResponse(string text)
{
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
}
public static Order Command(string text)
{
return new Order("Command", null, text) { IsImmediate = true };
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
}
public static Order StartProduction(Actor subject, string item, int count)
{
return new Order("StartProduction", subject, new int2( count, 0 ), item );
return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
}
public static Order PauseProduction(Actor subject, string item, bool pause)
{
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item);
return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
}
public static Order CancelProduction(Actor subject, string item)
public static Order CancelProduction(Actor subject, string item, int count)
{
return new Order("CancelProduction", subject, item);
return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
}
}
}

View File

@@ -8,36 +8,18 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.Network
{
static class OrderIO
public static class OrderIO
{
public static void Write(this Stream s, byte[] buf)
{
s.Write(buf, 0, buf.Length);
}
public static void WriteFrameData(this Stream s, IEnumerable<Order> orders, int frameNumber)
{
var bytes = Serialize( orders, frameNumber );
s.Write( BitConverter.GetBytes( (int)bytes.Length ) );
s.Write( bytes );
}
public static byte[] Serialize( this IEnumerable<Order> orders, int frameNumber )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( frameNumber ) );
foreach( var o in orders.Select( o => o.Serialize() ) )
ms.Write( o );
return ms.ToArray();
}
public static List<Order> ToOrderList(this byte[] bytes, World world)
{
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
@@ -52,17 +34,29 @@ namespace OpenRA.Network
return ret;
}
public static byte[] SerializeSync( this List<int> sync, int frameNumber )
public static byte[] SerializeSync( this List<int> sync )
{
var ms = new MemoryStream();
using( var writer = new BinaryWriter( ms ) )
{
writer.Write( frameNumber );
writer.Write( (byte)0x65 );
foreach( var s in sync )
writer.Write( s );
}
return ms.ToArray();
}
public static int2 ReadInt2(this BinaryReader r)
{
var x = r.ReadInt32();
var y = r.ReadInt32();
return new int2(x, y);
}
public static void Write(this BinaryWriter w, int2 p)
{
w.Write(p.X);
w.Write(p.Y);
}
}
}

View File

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

View File

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

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Network
@@ -20,17 +21,27 @@ namespace OpenRA.Network
public List<Slot> Slots = new List<Slot>();
public Global GlobalSettings = new Global();
public Client ClientWithIndex(int clientID)
{
return Clients.SingleOrDefault(c => c.Index == clientID);
}
public Client ClientInSlot(Slot slot)
{
return Clients.SingleOrDefault(c => c.Slot == slot.Index);
}
public enum ClientState
{
NotReady,
Ready
Ready,
Disconnected = 1000
}
public class Client
{
public int Index;
public Color Color1;
public Color Color2;
public ColorRamp ColorRamp;
public string Country;
public int SpawnPoint;
public string Name;
@@ -44,47 +55,52 @@ namespace OpenRA.Network
public int Index;
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
public bool Closed; // host has explicitly closed this slot.
public string MapPlayer; // playerReference to bind against.
public string MapPlayer; // playerReference to bind against.
public bool Spectator = false; // Spectating or not
// todo: more stuff?
}
public class Global
{
public string ServerName;
public string Map;
public string[] Mods = { "ra" }; // mod names
public int OrderLatency = 3;
public int RandomSeed = 0;
public bool LockTeams = false; // don't allow team changes after game start.
public bool LockTeams = true; // don't allow team changes after game start.
public bool AllowCheats = false;
}
public Session(string[] mods)
{
this.GlobalSettings.Mods = mods.ToArray();
}
public string Serialize()
{
var clientData = new List<MiniYamlNode>();
foreach( var client in Clients )
clientData.Add( new MiniYamlNode( "Client@{0}".F( client.Index ), FieldSaver.Save( client ) ) );
foreach (var client in Clients)
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
foreach( var slot in Slots )
clientData.Add( new MiniYamlNode( "Slot@{0}".F( slot.Index ), FieldSaver.Save( slot ) ) );
foreach (var slot in Slots)
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot)));
clientData.Add( new MiniYamlNode( "GlobalSettings", FieldSaver.Save( GlobalSettings ) ) );
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
return clientData.WriteToString();
}
public static Session Deserialize(string data)
{
var session = new Session();
session.GlobalSettings.Mods = Game.Settings.Game.Mods;
var session = new Session(Game.Settings.Game.Mods);
var ys = MiniYaml.FromString(data);
foreach (var y in ys)
{
var yy = y.Key.Split('@');
switch( yy[0] )
switch (yy[0])
{
case "GlobalSettings":
FieldLoader.Load(session.GlobalSettings, y.Value);
@@ -95,7 +111,7 @@ namespace OpenRA.Network
break;
case "Slot":
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value ));
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value));
break;
}
}

View File

@@ -1,39 +1,43 @@
using System;
#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 System.Text;
using OpenRA.FileFormats;
using OpenRA.Support;
namespace OpenRA.Network
{
class SyncReport
{
readonly OrderManager orderManager;
const int numSyncReports = 5;
Report[] syncReports = new Report[numSyncReports];
int curIndex = 0;
public SyncReport()
public SyncReport( OrderManager orderManager )
{
this.orderManager = orderManager;
for (var i = 0; i < numSyncReports; i++)
syncReports[i] = new SyncReport.Report();
}
internal void UpdateSyncReport()
{
if (!Game.Settings.Debug.RecordSyncReports)
return;
GenerateSyncReport(syncReports[curIndex]);
curIndex = ++curIndex % numSyncReports;
}
void GenerateSyncReport(Report report)
{
report.Frame = Game.orderManager.FrameNumber;
report.SyncedRandom = Game.world.SharedRandom.Last;
report.Frame = orderManager.NetFrameNumber;
report.SyncedRandom = orderManager.world.SharedRandom.Last;
report.Traits.Clear();
foreach (var a in Game.world.Queries.WithTraitMultiple<object>())
foreach (var a in orderManager.world.Queries.WithTrait<ISync>())
{
var sync = Sync.CalculateSyncHash(a.Trait);
if (sync != 0)
@@ -41,7 +45,7 @@ namespace OpenRA.Network
{
ActorID = a.Actor.ActorID,
Type = a.Actor.Info.Name,
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName,
Trait = a.Trait.GetType().Name,
Hash = sync
});

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
@@ -11,97 +11,184 @@
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
using System;
using OpenRA.FileFormats;
namespace OpenRA.Network
{
static class UnitOrders
{
static Session.Client FindClientById(int id)
static Player FindPlayerByClient(this World world, Session.Client c)
{
return Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == id);
/* todo: this is still a hack.
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
* bots,.. */
return world.players.Values.FirstOrDefault(
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
}
static Player FindPlayerByClientId(int id)
public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order)
{
/* todo: find the interactive player. */
return Game.world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
}
public static void ProcessOrder( World world, int clientId, Order order )
{
// Drop exploiting orders
if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId)
if (world != null)
{
Game.Debug("Detected exploit order from {0}: {1}".F(clientId, order.OrderString));
return;
if (!world.WorldActor.TraitsImplementing<IValidateOrder>().All(vo =>
vo.OrderValidation(orderManager, world, clientId, order)))
return;
}
switch( order.OrderString )
switch (order.OrderString)
{
case "Chat":
{
var client = FindClientById(clientId);
if (client != null)
case "Chat":
{
var player = FindPlayerByClientId(clientId);
if (player != null && player.WinState == WinState.Lost)
Game.AddChatLine(client.Color1, client.Name + " (Dead)", order.TargetString);
else
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
}
break;
}
case "TeamChat":
{
var client = FindClientById(clientId);
if (client != null)
{
var player = FindPlayerByClientId(clientId);
var display = (world.GameHasStarted) ?
player != null && (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|| player.WinState == WinState.Lost) :
client == Game.LocalClient || (client.Team == Game.LocalClient.Team && client.Team != 0);
if (display)
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
var player = world != null ? world.FindPlayerByClient(client) : null;
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
}
else
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
break;
}
break;
}
case "StartGame":
case "Disconnected": /* reports that the target player disconnected */
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
client.State = Session.ClientState.Disconnected;
}
break;
}
case "TeamChat":
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
if (world == null)
{
if (client.Team == orderManager.LocalClient.Team)
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)",
order.TargetString);
}
else
{
var player = world.FindPlayerByClient(client);
var display = player != null
&&
(world.LocalPlayer != null &&
player.Stances[world.LocalPlayer] == Stance.Ally
|| player.WinState == WinState.Lost);
if (display)
{
var suffix = (player != null && player.WinState == WinState.Lost)
? " (Dead)"
: " (Team)";
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
}
}
}
break;
}
case "StartGame":
{
Game.AddChatLine(Color.White, "Server", "The game has started.");
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
break;
}
case "HandshakeRequest":
{
Game.AddChatLine(Color.White, "Server", "The game has started.");
Game.StartGame(Game.LobbyInfo.GlobalSettings.Map);
break;
}
case "SyncInfo":
{
Game.SyncLobbyInfo(order.TargetString);
break;
}
case "SetStance":
{
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
var oldStance = order.Player.Stances[targetPlayer];
order.Player.Stances[targetPlayer] = (Stance)order.TargetLocation.Y;
var request = HandshakeRequest.Deserialize(order.TargetString);
// Check that the map exists on the client
if (!Game.modData.AvailableMaps.ContainsKey(request.Map))
throw new InvalidOperationException("Missing map {0}".F(request.Map));
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, order.Player.Stances[targetPlayer]));
break;
}
default:
{
if( !order.IsImmediate )
foreach (var t in order.Subject.TraitsImplementing<IResolveOrder>())
t.ResolveOrder(order.Subject, order);
var info = new Session.Client()
{
Name = Game.Settings.Player.Name,
ColorRamp = Game.Settings.Player.ColorRamp,
Country = "random",
SpawnPoint = 0,
Team = 0,
State = Session.ClientState.NotReady
};
var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray();
var response = new HandshakeResponse()
{
Client = info,
Mods = localMods,
Password = "Foo"
};
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize()));
break;
}
case "ServerError":
orderManager.ServerError = order.TargetString;
break;
case "SyncInfo":
{
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
&& !orderManager.GameStarted)
{
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
Game.Debug(
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
}
Game.SyncLobbyInfo();
break;
}
case "SetStance":
{
if (Game.orderManager.LobbyInfo.GlobalSettings.LockTeams)
return;
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
var newStance = (Stance)order.TargetLocation.Y;
SetPlayerStance(world, order.Player, targetPlayer, newStance);
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
// automatically declare war reciprocally
if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally)
{
SetPlayerStance(world, targetPlayer, order.Player, newStance);
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
}
break;
}
default:
{
if( !order.IsImmediate )
{
var self = order.Subject;
var health = self.TraitOrDefault<Health>();
if( health == null || !health.IsDead )
foreach( var t in self.TraitsImplementing<IResolveOrder>() )
t.ResolveOrder( self, order );
}
break;
}
}
}
static void SetPlayerStance(World w, Player p, Player target, Stance s)
{
var oldStance = p.Stances[target];
p.Stances[target] = s;
if (target == w.LocalPlayer)
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
}
}
}

View File

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

View File

@@ -79,22 +79,14 @@
<Compile Include="Group.cs" />
<Compile Include="Orders\GenericSelectTarget.cs" />
<Compile Include="Server\ProtocolVersion.cs" />
<Compile Include="Traits\BaseBuilding.cs" />
<Compile Include="Traits\LintAttributes.cs" />
<Compile Include="Traits\Player\PlayerResources.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\Delegates\ServerBrowserDelegate.cs" />
<Compile Include="Widgets\Delegates\SettingsMenuDelegate.cs" />
<Compile Include="Widgets\MapPreviewWidget.cs" />
<Compile Include="Widgets\WidgetUtils.cs" />
<Compile Include="Effects\DelayedAction.cs" />
<Compile Include="Effects\FlashTarget.cs" />
<Compile Include="Effects\MoveFlash.cs" />
<Compile Include="Exts.cs" />
<Compile Include="GameRules\ActorInfo.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
@@ -106,23 +98,19 @@
<Compile Include="Network\Connection.cs" />
<Compile Include="Network\OrderIO.cs" />
<Compile Include="Network\OrderManager.cs" />
<Compile Include="PathSearch.cs" />
<Compile Include="Selection.cs" />
<Compile Include="Server\Connection.cs" />
<Compile Include="Server\Exts.cs" />
<Compile Include="Server\MasterServerQuery.cs" />
<Compile Include="Server\Server.cs" />
<Compile Include="Server\ServerOrder.cs" />
<Compile Include="ShroudRenderer.cs" />
<Compile Include="Sound.cs" />
<Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" />
<Compile Include="Traits\CustomSellValue.cs" />
<Compile Include="Traits\World\SpatialBins.cs" />
<Compile Include="Traits\World\Country.cs" />
<Compile Include="Actor.cs" />
<Compile Include="Cursor.cs" />
<Compile Include="GameRules\Footprint.cs" />
<Compile Include="GameRules\Rules.cs" />
<Compile Include="Graphics\Animation.cs" />
<Compile Include="Game.cs" />
@@ -130,36 +118,25 @@
<Compile Include="Graphics\CursorSheetBuilder.cs" />
<Compile Include="Graphics\LineRenderer.cs" />
<Compile Include="Graphics\WorldRenderer.cs" />
<Compile Include="Traits\Activities\Idle.cs" />
<Compile Include="Traits\Activities\RemoveSelf.cs" />
<Compile Include="Traits\Activities\Sell.cs" />
<Compile Include="Orders\IOrderGenerator.cs" />
<Compile Include="Player.cs" />
<Compile Include="Graphics\Sheet.cs" />
<Compile Include="PathFinder.cs" />
<Compile Include="Graphics\Sequence.cs" />
<Compile Include="Network\Order.cs" />
<Compile Include="Graphics\SequenceProvider.cs" />
<Compile Include="Graphics\SheetBuilder.cs" />
<Compile Include="Graphics\HardwarePalette.cs" />
<Compile Include="MainWindow.cs">
</Compile>
<Compile Include="Support\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Graphics\Renderer.cs" />
<Compile Include="Graphics\Sprite.cs" />
<Compile Include="Graphics\SpriteRenderer.cs" />
<Compile Include="Graphics\SpriteSheetBuilder.cs" />
<Compile Include="Graphics\SpriteLoader.cs" />
<Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\World\BuildingInfluence.cs" />
<Compile Include="Traits\World\PlayerColorPalette.cs" />
<Compile Include="Traits\World\ResourceLayer.cs" />
<Compile Include="Traits\World\ResourceType.cs" />
<Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\Mobile.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\World\UnitInfluence.cs" />
@@ -169,29 +146,22 @@
<Compile Include="Graphics\Util.cs" />
<Compile Include="Graphics\Viewport.cs" />
<Compile Include="Orders\UnitOrderGenerator.cs" />
<Compile Include="Widgets\WorldTooltipWidget.cs" />
<Compile Include="World.cs" />
<Compile Include="WorldUtils.cs" />
<Compile Include="Traits\Player\EvaAlerts.cs" />
<Compile Include="Traits\World\ScreenShaker.cs" />
<Compile Include="Traits\LineBuild.cs" />
<Compile Include="Widgets\WidgetLoader.cs" />
<Compile Include="Widgets\ButtonWidget.cs" />
<Compile Include="Widgets\Widget.cs" />
<Compile Include="Widgets\BackgroundWidget.cs" />
<Compile Include="Widgets\LabelWidget.cs" />
<Compile Include="Widgets\CheckboxWidget.cs" />
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
<Compile Include="Widgets\PerfGraphWidget.cs" />
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
<Compile Include="Widgets\Delegates\LobbyDelegate.cs" />
<Compile Include="Widgets\ColorBlockWidget.cs" />
<Compile Include="GameRules\MusicInfo.cs" />
<Compile Include="Widgets\ImageWidget.cs" />
<Compile Include="Widgets\TextFieldWidget.cs" />
<Compile Include="Widgets\ChatDisplayWidget.cs" />
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
<Compile Include="Widgets\ListBoxWidget.cs" />
<Compile Include="Widgets\SliderWidget.cs" />
<Compile Include="Widgets\TimerWidget.cs" />
<Compile Include="Widgets\ShpImageWidget.cs" />
@@ -200,18 +170,19 @@
<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\Activities\Drag.cs" />
<Compile Include="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
<Compile Include="GameRules\Settings.cs" />
<Compile Include="Support\Arguments.cs" />
<Compile Include="Traits\ActorStance.cs" />
<Compile Include="Traits\Armor.cs" />
<Compile Include="Graphics\CursorProvider.cs" />
<Compile Include="Traits\Player\TechTree.cs" />
<Compile Include="Traits\Player\PowerManager.cs" />
<Compile Include="Server\TraitInterfaces.cs" />
<Compile Include="Widgets\ScrollPanelWidget.cs" />
<Compile Include="Graphics\ShroudRenderer.cs" />
<Compile Include="Network\Handshake.cs" />
<Compile Include="Widgets\ProgressBarWidget.cs" />
<Compile Include="Utilities.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -220,16 +191,22 @@
</ProjectReference>
<Compile Include="ActorInitializer.cs" />
<Compile Include="ActorReference.cs" />
<Compile Include="InputHandler.cs" />
<Compile Include="ModData.cs" />
<Compile Include="Map.cs" />
<Compile Include="Network\FrameData.cs" />
<Compile Include="Network\ReplayConnection.cs" />
<Compile Include="Network\Session.cs" />
<Compile Include="ObjectCreator.cs" />
<Compile Include="Network\SyncReport.cs" />
<Compile Include="Traits\EditorAppearance.cs" />
<Compile Include="Traits\SubcellInit.cs" />
<Compile Include="Traits\Target.cs" />
<Compile Include="Traits\ValidateOrder.cs" />
<Compile Include="TraitDictionary.cs" />
<Compile Include="Traits\SharesCell.cs" />
<Compile Include="Traits\Valued.cs" />
<Compile Include="Traits\World\BibLayer.cs" />
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
<Compile Include="Traits\Activities\CancelableActivity.cs" />
<Compile Include="Widgets\PasswordFieldWidget.cs" />
<Compile Include="Widgets\ScrollingTextWidget.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
@@ -251,6 +228,9 @@
<ItemGroup>
<Content Include="OpenRA.ico" />
</ItemGroup>
<ItemGroup>
<Folder Include="Widgets\Delegates\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -10,39 +10,64 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Orders
{
public class GenericSelectTarget : IOrderGenerator
{
readonly Actor subject;
readonly IEnumerable<Actor> subjects;
readonly string order;
readonly string cursor;
readonly MouseButton expectedButton;
public GenericSelectTarget(Actor subject, string order, string cursor)
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor, MouseButton button)
{
this.subject = subject;
this.subjects = subjects;
this.order = order;
this.cursor = cursor;
expectedButton = button;
}
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
: this(subjects, order, cursor, MouseButton.Left)
{
}
public GenericSelectTarget(Actor subject, string order, string cursor)
: this(new Actor[] { subject }, order, cursor)
{
}
public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button)
: this(new Actor[] { subject }, order, cursor, button)
{
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
if (mi.Button != expectedButton)
world.CancelInputMode();
return OrderInner(world, xy, mi);
}
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left && world.Map.IsInMap(xy))
yield return new Order(order, subject, xy);
if (mi.Button == expectedButton && world.Map.IsInMap(xy))
{
world.CancelInputMode();
foreach (var subject in subjects)
yield return new Order(order, subject, false) { TargetLocation = xy };
}
}
public virtual void Tick(World world) { }
public void RenderAfterWorld(World world) { }
public void RenderBeforeWorld(World world) { }
public virtual void Tick(World world) { }
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
public void RenderAfterWorld(WorldRenderer wr, World world) { }
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}
@@ -53,6 +78,9 @@ namespace OpenRA.Orders
public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor)
: base(subject, order, cursor) { }
public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor, MouseButton button)
: base(subject, order, cursor, button) { }
public override void Tick(World world)
{
var hasStructure = world.Queries.OwnedBy[world.LocalPlayer]
@@ -63,5 +91,4 @@ namespace OpenRA.Orders
world.CancelInputMode();
}
}
}

View File

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

View File

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

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