Compare commits

...

588 Commits

Author SHA1 Message Date
Chris Forbes
fb1d37ae53 use explosion *names*, not *numbers* like RA. 2010-07-07 19:44:14 +12:00
Paul Chote
c17a63a434 Add icons to the osx launcher 2010-07-07 19:09:52 +12:00
Paul Chote
bc84e33222 Add more resolution to version string 2010-07-07 19:09:50 +12:00
Paul Chote
2835fd66fe Show version on shellmap (via alzeih) 2010-07-07 19:09:46 +12:00
Paul Chote
1b38c4a6cb Upgrade install if newer version is run 2010-07-07 19:09:41 +12:00
Paul Chote
a74705f34d Tweaks 2010-07-07 19:09:38 +12:00
Paul Chote
2fa0ac99dd Install game in ~/Library/Application Support/OpenRA/; Download packages only when needed; Display a dialog on crash 2010-07-07 19:09:36 +12:00
Paul Chote
247576277f Select mod on game start (TODO: kill this in favor of a proper ingame mod manager) 2010-07-07 19:09:34 +12:00
Paul Chote
6359674d27 Override UserSettings from the commandline 2010-07-07 19:09:30 +12:00
Paul Chote
4671e6b261 Script to package a game build into a zip 2010-07-07 19:09:27 +12:00
Paul Chote
cfa4820379 Package Cg and SDL too 2010-07-07 19:09:25 +12:00
Paul Chote
4c8575b1f5 Custom game wrapper for osx. Point it at a standard game dir, and it will run it without needing any other dependencies installed.
Internal mono works; still uses system SDL and Cg
2010-07-07 19:09:22 +12:00
Chris Forbes
ec9bdb03c5 slower-moving but much nicer v2 projectile 2010-07-07 19:00:10 +12:00
Chris Forbes
ae671369b6 fix descriptions for 2tnk/3tnk; tweak damage types for 1tnk. 2010-07-07 18:36:08 +12:00
Chris Forbes
2ed8045736 remove DeathWeapon; IExplodeModifier implemented for resource actors (and for V2, which was the original purpose) 2010-07-07 18:32:45 +12:00
Chris Forbes
68b63dc89e ralint: verify voices, support (and still verify) @-form prerequisites. 2010-07-04 14:50:26 +12:00
Chris Forbes
8e68449af1 voices are no longer tied to having Unit; default is to have no voice; defaults.yaml set up appropriately for units that should have one. 2010-07-04 14:25:34 +12:00
Chris Forbes
35b6f5c38b don't download the mixes if you already have them; split cg deps into /releases/windows/cg-win32.zip (1.5M) 2010-07-04 10:23:18 +12:00
Chris Forbes
8d88d73e53 hack windows installer to NOT reinstall freetype,zlib,sdl on upgrade 2010-07-03 10:56:06 +12:00
Chris Forbes
8018fa0aec please don't have insane options as the hardcoded default. that's what your personal settings file is for. 2010-07-01 19:04:07 +12:00
Chris Forbes
5bec019d55 add RALint checking to nearly everything 2010-07-01 18:57:10 +12:00
Chris Forbes
8974fb7ae8 hack the RALint output format so VS shows errors as errors. Source position would be nice too, but that requires actual work. 2010-07-01 18:34:27 +12:00
Chris Forbes
2d9e5c6fcd remove spam on loading RA MIX headers; add some more bits to RALint 2010-07-01 18:31:13 +12:00
Chris Forbes
c310713cd5 beginning of RALint 2010-07-01 13:11:32 +12:00
Paul Chote
521e6b8549 Log when something hits the path cache 2010-06-30 20:39:52 +12:00
Paul Chote
4c3930043e Reenable path cache to catch the most stupid path fails (doesn't help the most common fails) 2010-06-30 20:25:32 +12:00
Paul Chote
202d1a38d5 Specify valid filetypes in tilesets 2010-06-30 20:25:32 +12:00
Paul Chote
9ca9d9a47e Fix country names in lobby 2010-06-30 20:25:32 +12:00
Paul Chote
e5ce9196fa Nicer tooltips 2010-06-30 20:25:32 +12:00
Chris Forbes
51079f0876 add LevelUpCrateAction 2010-06-30 18:33:19 +12:00
Chris Forbes
c605a35ab0 only kill units on bridge death which cannot exist on their cell(s)' new terrain types 2010-06-30 18:11:39 +12:00
alzeih
aa64803f84 hacky chat line wrapping 2010-06-30 18:00:47 +12:00
Chris Forbes
7070b04cc9 new 1tnk concept; 2tnk/3tnk owners swapped back 2010-06-30 17:59:52 +12:00
Paul Chote
272e03603a Kill any units on a bridge piece when it dies. Todo: need to mask the death regions for cnc bridges 2010-06-28 13:05:52 +12:00
Paul Chote
797b1b4a84 Non-selectable fields in ra 2010-06-28 12:41:45 +12:00
Paul Chote
915c9460cf Theater specific artwork done properly 2010-06-28 12:38:35 +12:00
Paul Chote
b46cec91a8 Fix cnc shellmap uid 2010-06-28 00:24:04 +12:00
Paul Chote
15a72e893b Quick hack for theater-specific artwork. Should probably be done better; editor support required. 2010-06-28 00:23:58 +12:00
Paul Chote
560c3ce5af Regress the editor so it actually works 2010-06-27 23:59:54 +12:00
Paul Chote
dfb6d19646 Add missing road end to oasis 2010-06-27 23:19:41 +12:00
Paul Chote
4def9e0eae Fix Editor 2010-06-27 23:14:43 +12:00
Paul Chote
703d536e46 Map object polish (tooltips + pruning) 2010-06-27 23:13:30 +12:00
Paul Chote
b12b774deb Kill some obsoleted data 2010-06-27 22:39:02 +12:00
Paul Chote
f37a4ec9ed Add bridges to cnc 2010-06-27 17:50:05 +12:00
Paul Chote
25f2268f58 Bridge destruction etc works 2010-06-27 15:58:57 +12:00
Paul Chote
cdbe2d3a34 Friendly tree tooltips 2010-06-27 11:02:54 +12:00
Paul Chote
c5718456fd First half of bridge overhaul 2010-06-27 10:59:01 +12:00
Paul Chote
9a34b049a8 Reverse ra bridge metadata 2010-06-26 22:23:05 +12:00
Paul Chote
49d7833b04 Fix editor 2010-06-26 14:56:51 +12:00
Paul Chote
920b4f6856 Fix ra 2010-06-26 13:41:50 +12:00
Paul Chote
d275c72cb8 Cleaner TileSet init 2010-06-26 13:33:46 +12:00
Paul Chote
08ee425415 Fix some stupid bugs; remove hardcoded references to water/ore/tree terraintypes 2010-06-26 12:02:30 +12:00
Paul Chote
bf6b2da1a8 Unhardcode terrain types. Needs a bit more work re initialization and bridges 2010-06-26 10:55:29 +12:00
Paul Chote
8fbbaddce9 Merge all 4 tileset files together 2010-06-26 09:21:11 +12:00
Paul Chote
9cf6d8970a Merge templates.ini and tileset.til into theatre-specific yaml files.
Game doesn't use them yet.
2010-06-26 00:19:34 +12:00
Paul Chote
cf265c8b58 Fix ra 2010-06-25 23:07:11 +12:00
Paul Chote
2373528ad9 Kill UnitMovementType; bs-free crate spawning; fix "DOME crash" (caused by crate not IOccupying space); add money and hide-map crates to cnc 2010-06-25 21:58:09 +12:00
Paul Chote
7c3a10396c New crush code, now with less bs 2010-06-25 20:57:06 +12:00
Paul Chote
00b91bd7ad Reimplement ICustomTerrain with far less bs 2010-06-25 19:26:08 +12:00
Paul Chote
29fa9e3aeb Shift movement cost/speed into IMove; regressions in a few areas 2010-06-25 17:05:56 +12:00
Paul Chote
6a5869f2c6 Begin cleaning up terraintypes/movetypes 2010-06-25 15:52:12 +12:00
Paul Chote
7ac8d0cf59 Units automatically path around known hazards (eg static base defenses). Test using SAM and TRAN.
Todo: Ignore hazards when force-moving; Apply only to known enemy hazards; Implement more hazard classes

Also add a few files I forgot from previous patches
2010-06-25 13:53:37 +12:00
Paul Chote
0aeca2aadc Helicopters use pathfinder 2010-06-24 21:51:22 +12:00
Paul Chote
37cf30a097 Refactor Mobile.TeleportTo -> IMove.SetPosition 2010-06-24 21:51:22 +12:00
Paul Chote
3e664779ef Remove a bunch of unnecessary caching 2010-06-24 21:51:22 +12:00
Paul Chote
b42589b479 Fix vehicle production; Basic 5-to-a-cell logic. cnc only. Infantry stack; need to give a graphical offset. 2010-06-24 21:51:22 +12:00
Paul Chote
b7c8e55d14 Some initial hacks towards multiple-infantry-per-cell. Make the pathfinder smart enough to do what we need, and remove a *lot* of stupid duplication. Needs more work. 2010-06-24 21:51:22 +12:00
Chris Forbes
308a7b0cf6 remove hardcoded magic number 2010-06-24 21:51:22 +12:00
Chris Forbes
0cf39991db new range circle renderer; faster minefield renderer 2010-06-24 21:51:21 +12:00
Chris Forbes
b8093b7f6c removing a bunch of excessively low-level pixel -> cell conversions 2010-06-24 21:51:21 +12:00
Chris Forbes
2dcc85f608 fix aircraft so it actually works again 2010-06-24 21:51:21 +12:00
Chris Forbes
e56339897f add additional debug to WorldRenderer.DrawUnitPath so we can see waypoint density, etc 2010-06-24 21:51:21 +12:00
Paul Chote
7d717592c7 Rename IMovement -> IMove; Move GetCurrentPath from Mobile to IMove and implement for aircraft; fix regressions in Helicopter (ITick) and remove unused cruft from Aircraft (IOccupySpace). 2010-06-24 21:51:21 +12:00
Paul Chote
3be5b946ad Flesh out center of the map 2010-06-24 21:51:21 +12:00
Paul Chote
1592225855 WIP cnc map (note: editor needs better work-loss prevention) 2010-06-24 21:51:21 +12:00
Paul Chote
bdb77501f7 More Helicopter polish 2010-06-24 21:51:21 +12:00
alzeih
37ffd2207f Fix game locking up on crash. 2010-06-23 22:04:17 +12:00
Chris Forbes
5dcc7782d9 make editor use pickany metadata 2010-06-20 18:45:47 +12:00
Paul Chote
aff357db0b Actually render resources when shroud is disabled 2010-06-20 18:34:06 +12:00
Chris Forbes
c1aa25e307 add 'pickany' flag in TileTemplate 2010-06-20 18:32:21 +12:00
Chris Forbes
a4f694e51a that was horrible. beef up v2 so it can fill that role better 2010-06-20 18:15:04 +12:00
alzeih
a1ffb68e22 bugfix 2010-06-20 17:48:20 +12:00
Booom3
a00a5433e4 balance stick 2010-06-20 17:31:37 +12:00
Chris Forbes
5242854892 unfail crates 2010-06-20 13:22:23 +12:00
Chris Forbes
17a45a0d6c fix destroyer missile range 2010-06-19 20:26:29 +12:00
Booom3
0195e54c8c Updated testmap 2010-06-19 10:24:57 +02:00
Chris Forbes
04c07ed88b fix prereqs for 3tnk 2010-06-19 19:58:29 +12:00
Chris Forbes
542ec65f10 buff 3tnk hp to match its new role 2010-06-19 19:56:40 +12:00
Chris Forbes
a457b1f133 swap 2tnk and 3tnk owners 2010-06-19 19:55:17 +12:00
Chris Forbes
8f897f7840 nerf CA a bit, esp vs unarmored 2010-06-19 19:47:50 +12:00
Chris Forbes
68ce0d89e6 more jeep tuning 2010-06-19 19:33:57 +12:00
Chris Forbes
b719271f6f make jeep decent vs infantry and crap vs everything else 2010-06-19 19:24:06 +12:00
Chris Forbes
4d8238cd32 reintroduce dome for soviet 2010-06-19 19:20:55 +12:00
Chris Forbes
87973f9ef3 fix bug in prev 2010-06-19 15:23:30 +12:00
Chris Forbes
c3490fcb66 buildings under fog 2010-06-19 15:17:48 +12:00
Chris Forbes
75bfedecb2 more heli polish (paul) 2010-06-19 15:06:02 +12:00
Chris Forbes
66adbee2a6 moving Actor.Location onto the appropriate traits (bob) 2010-06-19 14:37:06 +12:00
Chris Forbes
db465e1fdd ActorInitializer, in preparation for next change (bob) 2010-06-19 14:28:30 +12:00
Chris Forbes
572cdc9dbf vacate cells earlier 2010-06-18 22:36:24 +12:00
Chris Forbes
0ef91ecc2d hack around crash on boat repair 2010-06-18 20:55:06 +12:00
Chris Forbes
0c25924789 the Tao.SDL docs are wrong; the params are backwards. working keyrepeat, kthx. 2010-06-18 20:21:45 +12:00
Booom3
d58f2de090 Test map 2010-06-18 19:58:25 +12:00
Chris Forbes
c83f78f259 fix it on nonwindows too 2010-06-18 18:34:33 +12:00
Chris Forbes
8afb17c3f5 default somewhere sensible in editor (by not failing at '\') 2010-06-18 18:33:06 +12:00
Chris Forbes
abc7b21994 add logos to cnc 2010-06-18 18:18:02 +12:00
alzeih
beec39daa4 fixing bug on loading shellmap 2010-06-18 17:42:19 +12:00
alzeih
2da06d3744 Avoid Sharing Violations in logs 2010-06-18 16:25:12 +12:00
alzeih
5922a6c446 Stop printing arrow keys etc , and print repeated keys faster 2010-06-18 16:04:30 +12:00
alzeih
981a6b65a7 Fix server crashing when server order fails to deserialise. 2010-06-18 16:03:24 +12:00
alzeih
d6c83eddbd truncate name if longer than 10 chars 2010-06-18 14:46:16 +12:00
Paul Chote
331706d75e Fix crash on repair non-buildables (fact,proc). Allow special powers to depend on them too. 2010-06-17 23:48:00 +12:00
Paul Chote
4b124950b9 Unlimit heli ammo; may make orca OP 2010-06-17 23:19:34 +12:00
Paul Chote
212b3259fe Try some tweaks 2010-06-17 22:25:30 +12:00
Chris Forbes
33971c06a6 fix crash in Activities.Repair 2010-06-16 22:42:22 +12:00
Paul Chote
81d5b9bc6a Fix stupid crash 2010-06-16 21:48:15 +12:00
Paul Chote
a0e4e40eaf Fix e6 2010-06-16 21:13:20 +12:00
Chris Forbes
1088e30158 fix small bug in BuildPaletteWidget - incorrectly used cash rather than cash+ore 2010-06-16 20:27:51 +12:00
Paul Chote
f3dc3b1da0 Recover gracefully if proc goes away while harv is docking 2010-06-16 20:22:11 +12:00
Chris Forbes
5f58379f5b reenable cash sounds; if you want to disable them for your mod, don't set those evaAlerts properties. (as done in cnc); add SplitOreAndCash property to MoneyBinWidget, restoring old RA behavior (cnc is unchanged) 2010-06-16 20:18:01 +12:00
Paul Chote
01e95b67d6 Restore ra proc behavior 2010-06-16 20:00:38 +12:00
Paul Chote
5ed8113d8e Steal docked harv on proc capture (needs multiplayer testing); framework for canceling dock on proc death/sell (needs further activity changes) 2010-06-16 19:47:15 +12:00
Paul Chote
f0a2bf128c Harvesters return to last used field 2010-06-16 19:22:59 +12:00
Paul Chote
5822caf7a8 Fix cancellation issues and animation flicker 2010-06-16 10:37:54 +12:00
Paul Chote
40ba80b1e3 Use palette indices that map to sane colors in both games. 2010-06-16 01:18:09 +12:00
Paul Chote
88df9ecaa2 Implement cnc harv/proc dock sequence and kill unnecessary duplication. Bad things happen if sequence is interrupted by another order (eg invisible harv).
Still todo: Make sequence non-interruptible; engineer steals harv docked with proc; the "right thing" if proc is sold/destroyed with harv docked.
2010-06-16 00:33:09 +12:00
Paul Chote
5f83f97747 Link harvesters with refineries. 2010-06-15 20:05:49 +12:00
Paul Chote
f4421d89ea Fix tooltip crash on non-buildable prereq 2010-06-15 18:17:40 +12:00
Paul Chote
48cf08dc7d proc comes with 2 free silos; fix silo/proc prereq 2010-06-15 11:17:36 +12:00
Paul Chote
e3de3cc0d2 Make c17 invulnerable 2010-06-15 11:17:36 +12:00
Chris Forbes
c3e15aab7d hacky fix for productionqueue desync (e3, etc) 2010-06-15 08:42:40 +12:00
Chris Forbes
0e0a8802ab enhance sync to work with nested syncable types, and properties 2010-06-15 01:15:41 +12:00
Paul Chote
06a78cd73d Deathweapon capability, refactoring, and Pip polishing on Silo, Proc, Harv. Lose ore on silo death. 2010-06-14 22:15:43 +12:00
Paul Chote
d36c8deb97 Fix Explodes 2010-06-14 21:36:52 +12:00
Paul Chote
24edba34a7 Remove thief; transfer ore along with stolen silo/proc. 2010-06-14 20:59:35 +12:00
Paul Chote
283512f314 Spend ore before cash; lose ore > capacity. 2010-06-14 20:59:35 +12:00
Chris Forbes
6f3667971a remove targeting of husks. has map design impact, since chokepoints can be filled now 2010-06-14 20:48:49 +12:00
Chris Forbes
24d9b44a66 non-crap music player buttons 2010-06-14 20:44:35 +12:00
alzeih
9425fb1def Fix unnecessary duplication and get a better UI out of it 2010-06-14 14:05:20 +12:00
alzeih
889d736d35 Use images for music player (public domain - but find better ones) 2010-06-14 01:37:58 +12:00
alzeih
7b837fd6c4 Prevent changes when marked as ready 2010-06-14 00:55:22 +12:00
alzeih
3ac0ca6a65 BuildPalette tooltips show build time (+ in red if in low power) 2010-06-14 00:18:36 +12:00
Paul Chote
fbeadb9869 Increase vehicle sight; don't crash on production 2010-06-13 22:00:39 +12:00
Paul Chote
2e094d3279 Add fuel to missiles 2010-06-13 22:00:39 +12:00
Paul Chote
a771e63603 Revamp tech tree and build palette ordering 2010-06-13 22:00:39 +12:00
Paul Chote
de6434c0f1 Use the same model for ra (but let proc hold ore as before) 2010-06-13 22:00:39 +12:00
Paul Chote
dc8178f984 Tweaks 2010-06-13 22:00:39 +12:00
Paul Chote
aba5c777db The original method worked better; take the best of both worlds 2010-06-13 22:00:39 +12:00
Paul Chote
640ac9b8e6 Trial a new resource model in cnc 2010-06-13 22:00:05 +12:00
Paul Chote
19ed7428c4 Reorder build palette 2010-06-13 21:59:10 +12:00
Paul Chote
6afc34e5c1 SAM Site 2010-06-13 21:59:10 +12:00
Paul Chote
48bc029174 Set building health to cncrules.ini values 2010-06-13 21:59:09 +12:00
Chris Forbes
09b58f46d9 remove some spikes 2010-06-13 21:42:14 +12:00
alzeih
3001d58ba0 text has colour 2010-06-13 21:39:08 +12:00
alzeih
f0ea329b2c Fix crash if no music 2010-06-13 21:10:23 +12:00
Chris Forbes
2890d29e7d ra faction flags prototype 2010-06-13 21:07:27 +12:00
Chris Forbes
5b40d4444a add soviet logo 2010-06-13 19:39:08 +12:00
Chris Forbes
215ca80713 adjust ra ui layout so flags are not flush with left of button 2010-06-13 19:15:28 +12:00
Chris Forbes
27902bc48a clickable spawnpoint polish 2010-06-13 19:09:08 +12:00
alzeih
5d66c6b7ba Tweak flag size, kill Spawn button. 2010-06-13 19:03:02 +12:00
alzeih
1a20249f44 Basic ImageButton for drawing flags 2010-06-13 18:03:17 +12:00
Paul Chote
5e630768a2 Missed a file 2010-06-13 17:01:52 +12:00
Paul Chote
a273f7f07e Defense queue 2010-06-13 17:00:18 +12:00
Paul Chote
3b4753d9a8 Fix aircraft targeting; add veterancy 2010-06-13 17:00:18 +12:00
Paul Chote
8397bc12b5 Tweak special powers 2010-06-13 17:00:18 +12:00
Paul Chote
77510b4bef STNK desc 2010-06-13 17:00:18 +12:00
Paul Chote
b0802466b2 tib tree animations 2010-06-13 17:00:18 +12:00
Chris Forbes
c4d143b729 completing alzeih's patch 2010-06-13 16:34:01 +12:00
alzeih
d2da37f026 start of clicking on spawn points, compile fail still 2010-06-13 16:17:00 +12:00
Chris Forbes
6774486027 cnc: htnk.husk looks like a htnk now, not ltnk. 2010-06-13 15:57:56 +12:00
Paul Chote
2f99bf5ba5 FACT tooltip 2010-06-13 15:42:46 +12:00
Paul Chote
e5ee2b9479 Heli pips and separation 2010-06-13 15:39:00 +12:00
Paul Chote
3edbfc3345 Fix TMPL footprint 2010-06-13 14:32:55 +12:00
Paul Chote
b168bc2365 FIX after vehicle structure; NUK2 after HQ 2010-06-13 14:25:56 +12:00
Paul Chote
196316f36c Fix tib tree sequences 2010-06-13 11:45:19 +12:00
Paul Chote
b50ad94efb Tweak helicopter movement / attack 2010-06-13 11:34:33 +12:00
Paul Chote
a7f5c4b03a Hack a screenshot key in 2010-06-13 00:33:13 +12:00
Chris Forbes
7812e1c314 don't fail with offscreen impacts 2010-06-13 00:25:14 +12:00
Chris Forbes
3c95a2886c hack hack 2010-06-13 00:04:14 +12:00
Paul Chote
7c34252cff cnc GDI gets e3, exclusive RMBO; increase building sight; starting cash to 5000 2010-06-12 23:34:49 +12:00
Chris Forbes
4c955c36e7 fix retarded crash in WorldUtils.IsVisible 2010-06-12 23:07:55 +12:00
Chris Forbes
bcf7328d77 a bit of cleanup 2010-06-12 21:48:52 +12:00
Chris Forbes
02350e6ac8 unbitrot cnc (editor); add mod name to editor title 2010-06-11 18:23:03 +12:00
Chris Forbes
ee0f90708f put perf in its own channel 2010-06-11 18:15:59 +12:00
Chris Forbes
5d823d8e6e fix some debug-channel stuff that beedee missed in rebase 2010-06-11 18:00:36 +12:00
Chris Forbes
3870be5122 fix various breakage in nuke code 2010-06-11 17:55:42 +12:00
Chris Forbes
1bd7a9b590 visualize minefields in OG 2010-06-11 17:53:35 +12:00
Chris Forbes
e60acc682a add logging to ProductionItem 2010-06-11 17:53:34 +12:00
Matthew Bowra-Dean
aa239d172d Log channels, PHP script diffs when told. 2010-06-10 12:50:22 +12:00
Matthew Bowra-Dean
5f48577ebc upload.php now groups log files into zip files by game ID. 2010-06-10 12:48:06 +12:00
Matthew Bowra-Dean
fd014e15a5 Support for master game ID. 2010-06-10 12:45:58 +12:00
Matthew Bowra-Dean
1839655eb5 Master server changes to add ID to schema. 2010-06-10 12:43:46 +12:00
Matthew Bowra-Dean
e7c7a117a8 Log uploading. 2010-06-10 12:43:45 +12:00
Chris Forbes
a6d0adbab3 fix perf of uim overlay so it's usable again 2010-06-03 20:54:44 +12:00
alzeih
52c69addc6 RA AFLD requires power and can be powered down 2010-05-31 20:28:39 +12:00
Bob
493dec031b allow queueing on Mobile 2010-05-31 14:24:35 +12:00
Bob
1e570b5edb added Queued field to order 2010-05-31 14:20:25 +12:00
unknown
f2bcf1afae Added support for keyboard scrolling 2010-05-30 14:27:53 +12:00
alzeih
b45c74fa0b meh 2010-05-30 14:12:10 +12:00
alzeih
f946382e38 Split Radar and Power widgets 2010-05-30 14:06:50 +12:00
Chris Forbes
5a5fa37397 fix up cnc nuke enough that it should WORK 2010-05-30 13:45:03 +12:00
Chris Forbes
c531343481 fix GUN sequences 2010-05-30 13:45:03 +12:00
Chris Forbes
b57ebcffea fix damaged state for agun 2010-05-30 13:45:02 +12:00
Chris Forbes
f89e9f6d06 unbitrot cnc 2010-05-30 13:45:02 +12:00
Chris Forbes
b5327a2cb7 add tire particle sprite (4 frames) 2010-05-30 13:45:01 +12:00
Chris Forbes
d379a1f78b increase barr/tent cost to 500 2010-05-30 13:45:01 +12:00
Chris Forbes
90e1e0e796 make 4tnk meatier 2010-05-30 13:45:00 +12:00
Chris Forbes
f3a0c94eb5 change starting cash to 5k 2010-05-30 13:45:00 +12:00
Chris Forbes
540a2da82a fix stupid desync in minelayer 2010-05-30 13:44:59 +12:00
Bob
8285c7d158 refactoring Widget 2010-05-29 18:01:36 +12:00
Chris Forbes
ac10ca3fad add some more logging to help track down this jealous desync bug 2010-05-29 12:13:09 +12:00
Chris Forbes
d824373853 housekeeping in paradrop 2010-05-29 11:59:55 +12:00
Chris Forbes
94e8edb1cd fix crash in TeslaInstantKills 2010-05-29 09:43:07 +12:00
Chris Forbes
b61db88402 fix sequences for hbox 2010-05-28 19:55:37 +12:00
Chris Forbes
9b11e79592 blame nuke damage on the player actor, not the silo, to prevent retaliation 2010-05-28 19:48:34 +12:00
Chris Forbes
2ca9a936a3 hack in facing management of turrets on husks, + some angular velocity 2010-05-28 19:43:45 +12:00
Chris Forbes
584a7091db add death voices for civilians 2010-05-27 22:27:03 +12:00
Chris Forbes
c1f76da011 fix U2 crashing due to GainsExperience but not prereqs 2010-05-27 22:25:41 +12:00
Chris Forbes
ba850ec3f1 improve error message in ActorInfo.TraitsInConstructOrder 2010-05-27 22:17:15 +12:00
Chris Forbes
04dceb4417 turn down veterancy bonus a bit 2010-05-27 22:04:25 +12:00
Chris Forbes
996344ea6e fix crash in EmitInfantryOnSell when destroying things that are not Valued 2010-05-27 22:02:36 +12:00
Chris Forbes
a259a0aca0 hack in rank overlay; fix last rank; add an extra (elite) rank 2010-05-27 21:40:45 +12:00
Chris Forbes
a399e0b682 strip 'locate game root' crap from game & editor; chrono both CAs 2010-05-27 21:13:35 +12:00
Chris Forbes
ce9f7666b4 make build process saner (emit binaries into root rather than spray them through /bin/Debug/) 2010-05-27 20:59:02 +12:00
Chris Forbes
4dcc65237d slightly reduce recoil again on ca 2010-05-27 20:12:40 +12:00
Chris Forbes
8ca03da277 add impact sounds to ca weapon 2010-05-27 19:10:41 +12:00
Chris Forbes
3f32275169 give ca dual barrels on each turret 2010-05-27 19:08:56 +12:00
Chris Forbes
230625897a hack CrateEffect to have a custom offset; add levelup.shp; change > to >= in GainsExperience 2010-05-27 19:02:07 +12:00
Chris Forbes
1bd9dc7536 increase default thresholds 2010-05-27 18:43:30 +12:00
Chris Forbes
294240de7f fix missing prereq on GainsExperience; List -> array; float -> int 2010-05-27 18:35:44 +12:00
Chris Forbes
0c8e8b5658 fix tk detection; fix crash on lacking ValuedInfo; fix traits being fetched twice; fix needless mutation of 'exp' 2010-05-27 18:31:42 +12:00
Paul Chote
a070820695 Hack in trait modifiers. Probably not the best approach. 2010-05-27 17:22:26 +12:00
Paul Chote
c15d721884 Units gain exp for kills and level up 2010-05-27 16:53:21 +12:00
Paul Chote
c792ce5686 Disconnect button in lobby (#191) 2010-05-26 21:39:06 +12:00
Paul Chote
49b1870eaa Nuke flash (fixes #16) 2010-05-26 21:26:49 +12:00
Paul Chote
a35d6207a9 Scriptable chronosphere + desaturate effect 2010-05-26 21:07:13 +12:00
Paul Chote
9dc8422adf Scriptable MSLO and shellmap win 2010-05-26 20:40:50 +12:00
Paul Chote
b286a71487 Add some combat to the shellmap; unfail init slightly 2010-05-26 20:40:49 +12:00
Chris Forbes
92ba40da1a floodfill in editor on holding 'shift' 2010-05-26 19:47:46 +12:00
Chris Forbes
270941cfde fix some fail desyncs in chronoshift code 2010-05-26 19:02:43 +12:00
Chris Forbes
e7b7f69caf housekeeping 2010-05-26 18:10:43 +12:00
Chris Forbes
878039fc4a fix tesla hax with a different style of tesla hax 2010-05-25 21:15:25 +12:00
Chris Forbes
fcea5bd2f0 multipath lightning - shows up some flaws in the lightning code, though 2010-05-25 20:23:50 +12:00
Chris Forbes
e8829f8e92 reduce CA damage slightly 2010-05-24 22:15:01 +12:00
Chris Forbes
081d1cdafc buff sam to be ~agun 2010-05-24 21:41:55 +12:00
Chris Forbes
f3a73fa53d slightly buff mig hp so it should survive one more rocket 2010-05-24 21:41:55 +12:00
Chris Forbes
81ccc6a0c8 nerf heli/hind hp & armortype 2010-05-24 21:41:54 +12:00
Chris Forbes
08756b7b4c reduce frequency of hidemap crate by 50% 2010-05-24 21:41:54 +12:00
Chris Forbes
5c9d6362c1 nerf money crate 2k -> 1k 2010-05-24 21:41:53 +12:00
Chris Forbes
d109dad4a2 change crate spawn interval to 2 minutes, not 20 seconds 2010-05-24 21:41:53 +12:00
Paul Chote
f5b313b5e8 blah 2010-05-24 21:29:16 +12:00
Paul Chote
7ef2ed1434 Actors as dict 2010-05-24 21:18:54 +12:00
Paul Chote
2dfa4d9db7 MapFormat = 1 and editor support 2010-05-24 21:18:54 +12:00
Paul Chote
78455a3dce IsSpecial -> NonCombatant 2010-05-24 21:18:53 +12:00
Paul Chote
35ca5f80b2 Nits. 2010-05-24 21:18:53 +12:00
Paul Chote
9837b4ce32 Fix map-player ctor. 2010-05-24 21:14:36 +12:00
Paul Chote
a6f5b12a55 world.NeutralPlayer has been defeated 2010-05-24 21:14:36 +12:00
Paul Chote
bbbd65a6eb Fix regressions. 2010-05-24 21:14:36 +12:00
Paul Chote
d9931af5ae First attempt; works, but has regressions in several areas 2010-05-24 21:14:36 +12:00
Chris Forbes
b8b3ef61aa fix dumb oversight when choosing a suitable fix 2010-05-24 21:10:13 +12:00
Chris Forbes
e850937022 make minelayer require force-attack to start minefield (otherwise move); return to fix and rearm/repair before heading out again 2010-05-24 21:10:13 +12:00
Chris Forbes
5ca590a16a working smart minelayer; needs auto-rearm though 2010-05-24 21:10:12 +12:00
Chris Forbes
f77c12e9a0 cleanup some leftover crap from StatelessTraitInfo<> fail 2010-05-24 21:10:12 +12:00
Chris Forbes
431bbe2764 remove spurious IProducer interface; add IBlocksBullets and move Wall 2010-05-24 21:10:11 +12:00
Chris Forbes
224489502e fix weird crap in ConstructionYard (badly named: just undeploys) 2010-05-24 21:10:11 +12:00
Chris Forbes
027d7e2c2b filtering of unusable cells in minefield support; rationalize mobile a bit 2010-05-24 21:10:10 +12:00
Chris Forbes
9dd1032683 generate a vaguely reasonable minefield locus 2010-05-24 21:10:10 +12:00
Chris Forbes
baf37f7d04 start of smart minelayer 2010-05-24 21:10:09 +12:00
Chris Forbes
bb289101fc improve perf somewhat for editor map loading 2010-05-24 20:59:59 +12:00
Chris Forbes
6cbebeebd5 'fix' interior for now, with the hack documented this time 2010-05-24 20:52:15 +12:00
Chris Forbes
e5bb541824 unhack some hacks in editor 2010-05-24 08:18:11 +12:00
Chris Forbes
4d7de9e790 type inference is fine too 2010-05-23 15:45:57 +12:00
Chris Forbes
87d7fd163b blah 2010-05-23 12:06:30 +12:00
Chris Forbes
b662cebfb8 clean up some old BS in SpriteSheetBuilder 2010-05-21 12:37:22 +12:00
Chris Forbes
630aee7b98 fix namespaces on stuff bob moved 2010-05-20 19:44:38 +12:00
Chris Forbes
560c41bf42 fix bad merge 2010-05-20 19:39:22 +12:00
Chris Forbes
40f981a80d blah 2010-05-20 19:35:50 +12:00
Bob
e9799ffdfa move CanPowerDown, PowerDownButton, and 3 IOGs 2010-05-20 19:33:10 +12:00
Chris Forbes
7609097f4f move render modifiers to ra 2010-05-20 19:26:09 +12:00
Chris Forbes
91a4ac5faf move victory conditions 2010-05-20 19:21:09 +12:00
Chris Forbes
586d5ec11e housekeeping 2010-05-20 19:19:28 +12:00
Chris Forbes
3276a4f557 moved Reservable to ra 2010-05-20 19:15:24 +12:00
Chris Forbes
9215fa4d28 moved CallFunc, Wait activities to ra 2010-05-20 19:14:16 +12:00
Chris Forbes
43eb4b03ea moved Follow to ra 2010-05-20 19:11:05 +12:00
Chris Forbes
1d0848466f moved most render bits to ra 2010-05-20 19:09:48 +12:00
Chris Forbes
b0d2bf2e51 moved air unit support to ra 2010-05-20 18:54:44 +12:00
Chris Forbes
7fc5007ac8 moved various other traits 2010-05-20 18:47:22 +12:00
Chris Forbes
f75a2d2fe6 moved infantry traits to ra 2010-05-20 18:41:24 +12:00
Chris Forbes
be974f7970 moved almost all Attack* to ra 2010-05-20 18:37:36 +12:00
Chris Forbes
d008fd9eed moved AutoTarget/AutoHeal to ra 2010-05-20 18:28:57 +12:00
Chris Forbes
b1327378ed moved CrateSpawner 2010-05-20 18:20:19 +12:00
Chris Forbes
7910f3fe54 moved ReturnOnIdle to ra 2010-05-20 18:18:25 +12:00
Chris Forbes
e5951b1502 moved bridge support into ra 2010-05-20 18:16:09 +12:00
Chris Forbes
4585addff2 move water & light palette manips into ra 2010-05-20 18:12:13 +12:00
Chris Forbes
d3332a7454 fix crash due to bad GeneratesGap removal 2010-05-20 18:08:56 +12:00
Chris Forbes
5deea6df93 move crate support to ra 2010-05-20 18:06:01 +12:00
Chris Forbes
561a2a86d0 moved Explodes to RA 2010-05-20 17:59:54 +12:00
Chris Forbes
99acb65502 removed GeneratesGap 2010-05-20 17:58:13 +12:00
Chris Forbes
248eba20fa EmitInfantryOnSell moved to RA 2010-05-20 17:56:44 +12:00
Chris Forbes
342ef2a498 removed SquishByTank 2010-05-20 17:47:12 +12:00
Chris Forbes
a33bb7bd8a move HasUnitOnBuild to RA 2010-05-20 17:41:07 +12:00
Chris Forbes
50cc18d1f4 moved SelfHealing to RA 2010-05-20 17:35:15 +12:00
Chris Forbes
ed21b3be8d moved cargo-related traits to ra 2010-05-20 17:28:48 +12:00
Chris Forbes
151f5acb2f remove spurious 'set' on IDisable and associated BS implementations 2010-05-20 12:55:29 +12:00
Chris Forbes
f9a2c20eee stop shooting the flares ! 2010-05-19 22:19:33 +12:00
Chris Forbes
e910ab87a1 buff turret gun to 50dps (60@30) 2010-05-19 21:06:43 +12:00
Chris Forbes
a49efda001 fix longdesc for afld 2010-05-19 20:37:47 +12:00
Chris Forbes
55a58394e4 instrument FindUnitsInCircle for perf 2010-05-19 20:13:01 +12:00
Chris Forbes
76bcd7cb26 cnc: make hq a detector, range=8 2010-05-19 19:47:38 +12:00
Chris Forbes
5adfd908c4 cnc: add range circles to defenses 2010-05-19 19:45:32 +12:00
Chris Forbes
82c895adee cnc: gtwr/atwr are now detectors 2010-05-19 19:44:17 +12:00
Chris Forbes
382636a3ba add AffectOwnUnits flag to DetectCloaked 2010-05-19 19:40:55 +12:00
Chris Forbes
3cbd62c6ec fix combat vs subs 2010-05-19 19:38:50 +12:00
Chris Forbes
7a426778d4 don't show cloaked units that are not your own, on the minimap 2010-05-19 19:35:17 +12:00
Chris Forbes
490d8d5a5f make autotarget not interested in cloaked units; make ss a normal ship (but cloaked) rather than its own unit type 2010-05-19 19:30:26 +12:00
Chris Forbes
b9ca655756 fix asymmetric stance interaction with decloak 2010-05-19 19:22:09 +12:00
Chris Forbes
47af8fc8f2 detectors 2010-05-19 19:20:31 +12:00
Chris Forbes
a6a1c1aabc if we've been forced to decloak, don't cut it short with another decloak 2010-05-19 18:40:38 +12:00
Chris Forbes
5c7838bafa sub stays uncloaked for 2s; submarine/cloak traits merged, since they do the same thing 2010-05-19 18:39:08 +12:00
Chris Forbes
56ec24a84e unbitrot cnc (due to bob's techtree changes) 2010-05-18 21:18:34 +12:00
Paul Chote
3475712075 Make PDOX/IRON worth building(?) 2010-05-18 20:18:05 +12:00
Paul Chote
78aa7bb3a9 Soviets DOME -> AFLD 2010-05-18 20:18:02 +12:00
Paul Chote
5c48465c65 Goodbye fake structures 2010-05-18 20:17:57 +12:00
Paul Chote
25a01adc27 Half of editor makefile support (resources file needs to be built manually with resgen2 OpenRA.Editor/Form1.resx Form1.resources) 2010-05-17 20:34:23 +12:00
Chris Forbes
12467b713b unhack buildspeed AGAIN 2010-05-16 22:24:03 +12:00
Bob
7deefc5246 debug (timing) spam, and perf fixed on SupportPower
Build timing (un)hacked by chrisf
2010-05-16 22:23:36 +12:00
Chris Forbes
de9ec12c8c order names stuff to remove clashes in ra-nng 2010-05-16 22:15:41 +12:00
Chris Forbes
9d5eab74b1 cnc: htnk tuning 2010-05-16 21:38:24 +12:00
Chris Forbes
69fbc68cfd add tank husks to ltnk/mtnk/htnk in cnc 2010-05-16 21:37:42 +12:00
Chris Forbes
cf76e9d893 add husk default for cnc 2010-05-16 21:34:07 +12:00
Chris Forbes
9fdc79bc49 add fire sequences to cnc 2010-05-16 21:32:39 +12:00
Chris Forbes
7e754a5590 husks should not be mobile 2010-05-16 16:30:49 +12:00
Chris Forbes
128f12e88e hack in team chat support 2010-05-16 16:18:27 +12:00
Chris Forbes
d87807809d disable group spam on console; put speed back to something sensible 2010-05-16 16:09:37 +12:00
Chris Forbes
c173dddcd5 remove AutoTarget from v2, until we have unit stances (otherwise v2 is useless) 2010-05-16 15:43:48 +12:00
Chris Forbes
362525cb94 v2 explodes with napalm if it dies while loaded 2010-05-16 15:42:59 +12:00
Chris Forbes
c7b2ac3d3f a bit of housekeeping fail 2010-05-16 15:21:42 +12:00
Chris Forbes
7c244df5d1 add burning 2010-05-16 15:20:14 +12:00
Chris Forbes
67d741e671 unfail recoil directions (wtf) 2010-05-16 15:05:01 +12:00
Chris Forbes
99e7ee23fb tanks explode much more satisfyingly 2010-05-16 14:46:07 +12:00
Chris Forbes
8e46f99ab9 make it actually sortof work 2010-05-16 12:53:20 +12:00
Chris Forbes
c20a1cc70a synced group creation 2010-05-16 12:08:37 +12:00
Chris Forbes
b871caa287 add receiving end of CreateGroup order 2010-05-16 11:41:56 +12:00
Chris Forbes
39c5877ebc mod UOG to create a group from all actors that generate orders together for a ui action 2010-05-16 11:35:02 +12:00
Chris Forbes
6c6a121746 space-to-pan (like PS) in editor, not scrollbars. 2010-05-16 09:24:30 +12:00
Paul Chote
84980789aa Render ore when gps is enabled 2010-05-15 09:17:10 +12:00
Matthew Bowra-Dean
af2fd1b93d Get Involved page. 2010-05-15 09:16:53 +12:00
Chris Forbes
4d2d70a767 fix broken cnc infantry anims 2010-05-14 23:02:01 +12:00
Chris Forbes
ae6b218157 cnc: nerf htnk speed 2010-05-14 22:57:48 +12:00
Chris Forbes
32dae9fd5d cnc: buff htnk 2010-05-14 22:56:38 +12:00
Chris Forbes
d9ad28b29e put buildspeed back to a sane value 2010-05-14 21:15:15 +12:00
Chris Forbes
3a1108aaec set increment to be useful on scrollbars 2010-05-14 21:08:10 +12:00
Chris Forbes
e5069a3a69 (re)fix middle-mouse in editor 2010-05-14 21:02:30 +12:00
Paul Chote
c911065442 give the editor scrollbars 2010-05-14 20:56:12 +12:00
Chris Forbes
6936c73b68 husk experiment 2010-05-14 20:46:47 +12:00
Chris Forbes
9606827f34 added new 6p cnc map 2010-05-14 19:06:30 +12:00
Chris Forbes
d142f4eb47 unbitrot cnc 2010-05-14 17:33:04 +12:00
Chris Forbes
9b1bb37944 fix s22 template (north end of ridge, west side high) 2010-05-14 17:21:17 +12:00
Chris Forbes
82c9c12cae NO THAT IS NOT WHAT YOU DO WITH USELESS CODE 2010-05-14 08:16:33 +12:00
alzeih
43ad339ffe Squelch almost all compile errors 2010-05-14 01:00:28 +12:00
Chris Forbes
798c4cb2d3 east vs west (2v2 map) 2010-05-13 21:24:18 +12:00
Chris Forbes
b7f20327f9 move some more crap around 2010-05-13 19:59:43 +12:00
Chris Forbes
842584c388 move some ra crap around 2010-05-13 19:59:06 +12:00
Chris Forbes
753f3660aa fix exploitable support powers 2010-05-13 19:57:13 +12:00
Bob
e05defed67 allow building near your allies 2010-05-13 19:26:26 +12:00
Bob
bed3c28233 removed TechLevel from Buildable; fixed lineendings in structures.yaml 2010-05-13 19:13:25 +12:00
Chris Forbes
aa1c149dbb fix bob's lack of a traitinfo 2010-05-13 18:21:01 +12:00
Chris Forbes
78d40b5bb0 unbitrot cnc AGAIN; remove 'wood' and 'wall' flags from warheads 2010-05-13 18:09:13 +12:00
Chris Forbes
4bf7476044 less noise 2010-05-13 18:09:12 +12:00
Chris Forbes
00d8505b42 simplify repair order 2010-05-13 18:09:11 +12:00
Bob
823d7d44a9 did tesla instakill via damagemodifier instead 2010-05-13 18:06:20 +12:00
Bob
8aad7f8350 make infantry die instantly to tesla 2010-05-13 17:55:04 +12:00
Bob
01af30d0a9 change player-choosable factions to allies/soviets, since the countries didn't actually do anything 2010-05-13 17:05:53 +12:00
Chris Forbes
8c22f29ee0 tent is a barracks too 2010-05-13 17:02:14 +12:00
Chris Forbes
bb752406f1 fix some dog bugs; powr -> kenn 2010-05-13 16:33:58 +12:00
Chris Forbes
baa53b32d3 e3 dragon is AT only. use redeye to attack air 2010-05-13 15:57:19 +12:00
Booom3
00375b057d changes 2010-05-13 05:20:58 +02:00
Chris Forbes
e8b7e834d7 reduce cost of FIX 1k -> 700 2010-05-13 13:41:59 +12:00
Chris Forbes
14e8f67480 better timebased damage on pbox/hbox 2010-05-13 13:41:21 +12:00
Chris Forbes
9ae3abcb5f tweaks to defenses 2010-05-13 13:18:05 +12:00
Chris Forbes
5d3397ba83 non-high weapons impact walls - not perfect yet, but it will do 2010-05-13 13:00:58 +12:00
Chris Forbes
25d135f6bc walls further from base 2010-05-13 12:35:14 +12:00
Chris Forbes
385b3d0a2b simplify AutoAttack so it probably actually works 2010-05-13 12:15:07 +12:00
Chris Forbes
0669758d26 enable overriding of weapon on Explodes: 2010-05-13 12:07:08 +12:00
Chris Forbes
55cb2d49a4 balance changes to encourage expansions 2010-05-13 10:53:31 +12:00
Chris Forbes
2ef13f374b fix bug in placebuilding sounds (was using Player actor location) 2010-05-13 08:44:47 +12:00
Chris Forbes
65c42ce9d7 more positional sound 2010-05-13 08:44:47 +12:00
Chris Forbes
dd52aa1728 positional sound! 2010-05-13 08:44:46 +12:00
Matthew
4bb268075c Tweaked the package building scripts a little. 2010-05-13 08:44:35 +12:00
Matthew
00050b3f37 Wrapper script for RPM package building. 2010-05-13 08:44:33 +12:00
Chris Forbes
0585bade6c fix information leak in minimap 2010-05-12 19:18:25 +12:00
Chris Forbes
ae1a476cc4 readd gap, but unbuildable. shellmap depends on it 2010-05-12 19:12:39 +12:00
Chris Forbes
33b384c127 doubled CA/8Inch inaccuracy; reduced CA ROF 160 -> 200; increased jeep speed and sight; increased sight on controllable flying units to 10/12 2010-05-12 19:06:59 +12:00
Chris Forbes
f8f03e8031 cut useless units 2010-05-12 19:03:04 +12:00
Chris Forbes
ddf0908d99 removed Tuple<> 2010-05-12 18:48:39 +12:00
Chris Forbes
7dbd9f1f76 real class for a shake effect instance, rather than tuple 2010-05-12 18:48:02 +12:00
Chris Forbes
29277d01d2 remove use of Tuple in chat 2010-05-12 18:44:54 +12:00
Chris Forbes
72213adb45 fix stupid crash on startup 2010-05-12 18:31:09 +12:00
Chris Forbes
46e465cf33 resources moved off player onto a synced trait 2010-05-12 18:29:25 +12:00
Chris Forbes
a4592e7019 slim down the ore capacity update 2010-05-12 18:05:43 +12:00
Chris Forbes
77c5522602 turn off combat log spam 2010-05-12 18:03:03 +12:00
Chris Forbes
480d13653e remove hardcoded spen/syrd from RepairableNear 2010-05-12 18:01:50 +12:00
Chris Forbes
fd324e2804 remove spurious ctor on Activities.Repair 2010-05-12 17:59:50 +12:00
Chris Forbes
fb592b90d5 added ReadAllLines() for stream; rewrote TerrainColorSet to use it 2010-05-12 17:53:09 +12:00
Chris Forbes
8cd38812d9 make editor work in non-en locales 2010-05-12 17:41:37 +12:00
Chris Forbes
f0e5b9728f unfail slightly player color handling 2010-05-12 17:39:30 +12:00
Chris Forbes
b3fbe96627 export correct width/height 2010-05-12 17:39:30 +12:00
Chris Forbes
54bc5c920f export a templates.ini 2010-05-12 17:39:29 +12:00
Chris Forbes
2f7ac0d201 export a tileset.til 2010-05-12 17:39:29 +12:00
Chris Forbes
495dd7bbd9 enabled unsafe in TilesetBuilder; we now export TMPs 2010-05-12 17:39:28 +12:00
Chris Forbes
8e3c6bd175 tidy up RepairsUnits file 2010-05-12 17:39:28 +12:00
Chris Forbes
f7a1e2f71d fix #212 crash on repairing ships 2010-05-12 17:39:27 +12:00
Matthew
636a88b11e Changed arch package build script to use wput instead of ftp. 2010-05-12 17:00:59 +12:00
Matthew
2175dba18b More automation for arch packaging. 2010-05-12 16:38:22 +12:00
Chris Forbes
a8e4546958 update setup script 2010-05-11 18:10:11 +12:00
Boomer
bd72146548 Building hotkeys 2010-05-11 17:34:58 +12:00
Chris Forbes
ac75259efd make it actually work, except for half the export 2010-05-11 14:11:54 +12:00
Chris Forbes
c814aaa5de added TilesetBuilder (about half-built) 2010-05-11 10:54:30 +12:00
Chris Forbes
950ec40aee fix high & low 2010-05-10 22:29:17 +12:00
Chris Forbes
f63d906473 clean up all the ra maps 2010-05-10 22:27:34 +12:00
Chris Forbes
26b2b5515b fixup spawns for Middle of Hell 2010-05-10 22:18:01 +12:00
Chris Forbes
541c3e9165 set PlayerCount based on #waypoints 2010-05-10 22:13:22 +12:00
Chris Forbes
095e145507 fix cnc clear template 2010-05-10 22:12:00 +12:00
Chris Forbes
d703bd580f fix data sln for cnc 2010-05-10 22:10:38 +12:00
Chris Forbes
017140318f enjoy the first dogfood from the map editor - Snowy Ridge (2-3) 2010-05-10 22:04:06 +12:00
Chris Forbes
a64e17edc5 fix more broken templates 2010-05-10 21:28:31 +12:00
Chris Forbes
f16986e308 fix cnc new map support 2010-05-10 21:22:05 +12:00
Chris Forbes
caf77ab03c hack in spawnpoint support 2010-05-10 21:17:52 +12:00
Chris Forbes
b7ebcaa7fa blah 2010-05-10 21:05:46 +12:00
Chris Forbes
1483addb99 don't load mjolnir on startup; and use the mod specified on the commandline 2010-05-10 21:02:06 +12:00
Chris Forbes
de59ce1091 add map metadata dialog, and make it work 2010-05-10 20:57:22 +12:00
Chris Forbes
a6fd36bf44 hack hack hack newmap works 2010-05-10 20:44:34 +12:00
Chris Forbes
5c7a545855 new map dialog; not quite wired yet 2010-05-10 20:23:11 +12:00
Chris Forbes
c14a2eab88 saving works 2010-05-10 20:04:04 +12:00
Chris Forbes
c816e62a22 add a bunch more buttons 2010-05-10 19:51:47 +12:00
Chris Forbes
639465ba97 hack hack hack mostly works 2010-05-10 19:49:17 +12:00
Chris Forbes
94fdc4abba hack hack resources 2010-05-10 18:59:59 +12:00
Chris Forbes
8118e022cb don't allow stacking of mapactors 2010-05-10 18:27:01 +12:00
Chris Forbes
e275677d11 add removal of mapactors via rmb; add highlight on mouseover 2010-05-10 18:13:52 +12:00
Chris Forbes
2921618067 mapactor rendering 2010-05-10 18:05:03 +12:00
Chris Forbes
0673fc23bf actortemplate hax 2010-05-10 17:49:11 +12:00
Chris Forbes
22afe4f80b fix lots of template errors 2010-05-10 17:27:42 +12:00
Chris Forbes
d1326f606f fix broken ra templates 2010-05-09 21:01:26 +12:00
Chris Forbes
12b46bd562 add tooltips on mapactor stuff 2010-05-09 20:52:48 +12:00
Chris Forbes
b801c7a601 add actor images to palette 2010-05-09 20:49:00 +12:00
Chris Forbes
bac0268716 fixed editor use with cnc 2010-05-09 14:25:20 +12:00
Chris Forbes
1b3527f8de workaround broken int promotion in gmcs 2010-05-09 14:15:43 +12:00
Chris Forbes
f04b38aba0 fix render artifacts on mono 2010-05-09 14:10:12 +12:00
Chris Forbes
7f46323f51 add actors panel 2010-05-09 13:49:11 +12:00
Chris Forbes
12b6980402 continuous painting with brush 2010-05-09 13:47:35 +12:00
Chris Forbes
5be3da3d12 resize support working 2010-05-09 13:35:27 +12:00
Chris Forbes
b7e6dc90c3 resize dialog 2010-05-09 13:24:07 +12:00
Chris Forbes
88689ddaf7 kill another dead overload 2010-05-09 13:04:15 +12:00
Chris Forbes
7482907c80 kill dead overload of LoadRules 2010-05-09 13:03:34 +12:00
Chris Forbes
e06b2dd9e6 set editor to x86-only; editor loads rules 2010-05-09 13:02:21 +12:00
Chris Forbes
9332332771 fix templates for cnc (103x1 tiles were quite clearly broken) 2010-05-08 22:02:16 +12:00
Chris Forbes
e9fd21d1e5 oh. 2010-05-08 22:00:34 +12:00
Chris Forbes
5bcebade32 working toward something sane 2010-05-08 21:49:27 +12:00
Chris Forbes
edc73f2df8 zOMG perf 2010-05-08 21:43:09 +12:00
Chris Forbes
6d4431411a fix crash in engine for missing rules sections (music, etc) 2010-05-08 21:39:33 +12:00
Chris Forbes
08f5238be0 a bit of perf 2010-05-08 21:09:01 +12:00
Chris Forbes
0feb2da477 works 2010-05-08 20:59:18 +12:00
Chris Forbes
5124319a29 almost working 2010-05-08 20:38:41 +12:00
Chris Forbes
a09aed3370 almost working renderer 2010-05-08 20:24:23 +12:00
Chris Forbes
f08247afd0 beginning of an editor 2010-05-08 19:05:05 +12:00
alzeih
29d670dd79 MusicPlayer visibility controls 2010-05-08 13:45:59 +12:00
Matthew
c6af772d92 Updated linux packaging. 2010-05-08 12:45:16 +12:00
Matthew
722d850e78 Updated Makefile to remove RA-NG target. 2010-05-08 12:45:13 +12:00
Matthew
2f8da85858 Interstital page for Linux downloads. 2010-05-08 12:45:03 +12:00
Chris Forbes
2bce53b3d8 really fix the undeploy-while-damaged crash 2010-05-07 23:15:58 +12:00
Chris Forbes
8ca7909b5d take hax out of sample ini 2010-05-07 21:36:36 +12:00
Chris Forbes
20aa3d6764 fix not-even-vaguely-close random distribution 2010-05-07 21:32:30 +12:00
Chris Forbes
4de64ae5a8 blah 2010-05-07 21:00:44 +12:00
Chris Forbes
9f7c844528 tweaking vis on some Game stuff 2010-05-07 20:55:34 +12:00
Chris Forbes
ebd62e41da increase dog speed; decrease attack range 2010-05-07 20:49:47 +12:00
alzeih
1c862832ed Make music stop button behave as expected 2010-05-06 23:46:50 +12:00
alzeih
3c539daf20 We have more music 2010-05-06 23:42:03 +12:00
alzeih
930ad6e9a1 fix noob mistake, still goes boom 2010-05-06 23:42:03 +12:00
alzeih
30ee0afdc0 Half of having choices of music and a player of it (not finished) 2010-05-06 23:42:03 +12:00
Chris Forbes
acf55f1bb0 hack hack hack... working dog 2010-05-06 22:15:02 +12:00
Chris Forbes
888706befa initial work on DOG attack 2010-05-06 20:28:28 +12:00
Chris Forbes
3f25163b39 better sound match for wall destruction 2010-05-06 19:41:21 +12:00
Chris Forbes
7a25bea751 crushable walls 2010-05-06 19:05:31 +12:00
Chris Forbes
48c5a2ba19 remove ra-ng sample config 2010-05-06 18:24:59 +12:00
Chris Forbes
78021d4984 missed project file from prev; fixed description for MRJ 2010-05-06 18:20:54 +12:00
Chris Forbes
173c374de0 renamed VictoryConditions -> ConquestVictoryConditions in prep for adding a custom map 2010-05-06 18:16:36 +12:00
Chris Forbes
e574776704 make APWR count as a power plant for prerequisites 2010-05-06 18:07:46 +12:00
Chris Forbes
acf73ca4f8 add speed values for Nike (SAM missile) and RedEye (e3/aa missile) 2010-05-06 18:05:29 +12:00
Chris Forbes
38bfd53d65 merged ra-ng into ra base mod 2010-05-06 18:01:28 +12:00
Chris Forbes
00a9e2519c Merge branch 'chris' 2010-05-06 08:15:57 +12:00
Matthew
ecfba3dad8 Makefile fixed. 2010-05-06 04:28:44 +12:00
Matthew
4a94cb1960 RPM spec added. 2010-05-06 04:12:42 +12:00
Chris Forbes
9297aedfcc don't explode on taking damage to <50% while selling 2010-05-06 01:25:48 +12:00
Matthew
b7dba51251 Fixed IRC link 2010-05-06 01:11:26 +12:00
Chris Forbes
854dfcf470 fix stupid bug in prev [and in release] 2010-05-05 23:37:41 +12:00
Chris Forbes
dcad3939ce update upload tool so it works. 2010-05-05 23:07:43 +12:00
Chris Forbes
ef7114b1f6 make blue blue 2010-05-05 22:41:34 +12:00
Chris Forbes
c87c4f5d18 change orange palette to 'bad 70s orange' 2010-05-05 22:34:31 +12:00
alzeih
21a6b8abe0 But flush over here 2010-05-05 22:26:27 +12:00
alzeih
38a1cb89b5 Don't forget to flush 2010-05-05 22:20:10 +12:00
Chris Forbes
06f530b562 choose under-cursor actor by priority 2010-05-05 22:05:47 +12:00
Chris Forbes
f0a071e52b enhanced server browser display a bit 2010-05-05 21:31:32 +12:00
Chris Forbes
a795dfb7f2 beef up e2 inaccuracy 2010-05-05 21:25:09 +12:00
Chris Forbes
113fc187ab tweak e2 damage modifiers 2010-05-05 21:17:09 +12:00
Chris Forbes
008287406a e3/dragon gets impact sound; bullet animation fixed 2010-05-05 21:13:15 +12:00
Chris Forbes
6fc230974c #182 victory conditions need to know about teams 2010-05-05 20:59:31 +12:00
Chris Forbes
c6ab4be268 #153 mouse cursor issues in vicinity of trees 2010-05-05 20:56:21 +12:00
Chris Forbes
1c50ec1879 hack hack hack - no longer crash on failing to connect, etc 2010-05-05 20:05:07 +12:00
Chris Forbes
39920499e0 fix double-playing of music, etc. 2010-05-05 20:00:54 +12:00
Chris Forbes
5cdc47ea6b ordermanager will dispose IDisposable connections on dispose 2010-05-05 18:53:32 +12:00
Chris Forbes
f084f6d446 fix (one) crash on connection drop 2010-05-05 18:18:16 +12:00
Chris Forbes
9302440613 dispose the previous ordermanager (so the file will get closed, among other things) 2010-05-05 18:15:48 +12:00
Chris Forbes
d2009e9e7d inlined ChangeMap, since that wasnt really what it did 2010-05-05 18:11:49 +12:00
Chris Forbes
fcdc3c2bf0 some cleanup 2010-05-05 18:11:48 +12:00
Chris Forbes
c0ad315c66 fix small bug in prev 2010-05-05 18:11:48 +12:00
Chris Forbes
3bd3fd5e56 hack it so it works 2010-05-05 18:11:47 +12:00
Chris Forbes
74564c7b0a get this to the point where it crashes (a good thing) 2010-05-05 18:11:47 +12:00
Chris Forbes
d85bde324e route disconnect back to Game 2010-05-05 18:11:46 +12:00
Matthew
75f5855881 Forgot SDL dependency 2010-05-05 17:57:14 +12:00
Matthew
02e9a451e0 PKGBUILD for Arch-Linux 2010-05-05 13:56:39 +12:00
Matthew
49c82c7486 Removed script file generation from install target in Makefile. 2010-05-05 13:51:18 +12:00
Matthew
10b7e0c59f More Makefile tweaks. 2010-05-05 13:36:35 +12:00
Matthew
d5e049d05e Minor bug in Makefile 2010-05-05 13:15:03 +12:00
Chris Forbes
7052013c02 #205 crash on tsla killing c1/c2 2010-05-05 09:11:44 +12:00
Matthew
b28f55077f Makefile install target now uses install(1) rather than cp(1) for binaries. 2010-05-04 21:12:55 +12:00
Matthew
1303f4d9eb Install target on Makefile. 2010-05-04 16:35:07 +12:00
Matthew
95eaa9d94a Fixed log and replay file paths to save into user home dir. 2010-05-04 16:34:30 +12:00
Matthew Bowra-Dean
bea0b2299c Remvoing spurious blank lines. 2010-05-04 12:39:29 +12:00
Paul Chote
50501da26c Hacks for the osx launcher for playtest 2010-05-04 12:35:27 +12:00
Matthew
3f1a66a02b Fixed screenshot height bug, added ajax for download versions. 2010-05-04 12:31:54 +12:00
Matthew Bowra-Dean
82b09bbba0 Screenshots added. 2010-05-04 12:31:53 +12:00
Matthew Bowra-Dean
d75174a671 Upload tool. 2010-05-04 12:29:32 +12:00
Chris Forbes
cf31999703 tweaks 2010-05-03 19:54:44 +12:00
Chris Forbes
19b743af0b add game counter to website 2010-05-03 19:54:44 +12:00
Matthew Bowra-Dean
96515d91f9 Skeletons for the rest of the pages. 2010-05-03 19:54:43 +12:00
Matthew Bowra-Dean
d1701ad4fb License page. 2010-05-03 19:54:43 +12:00
Matthew Bowra-Dean
1a0e5329ff Gameplay footage page added. Screenshot nav tabs added. 2010-05-03 19:54:42 +12:00
Matthew Bowra-Dean
4ddc63f6bf Some client side stats and platform detection + updates to server side script to support download stats. 2010-05-03 19:54:42 +12:00
Matthew Bowra-Dean
3f6963dc2c GPLv3 logo 2010-05-03 19:54:41 +12:00
Matthew Bowra-Dean
193a315f0c Tweaking Paul's changes 2010-05-03 19:54:41 +12:00
Matthew Bowra-Dean
5b70db9a3e Paul's changes 2010-05-03 19:54:40 +12:00
Matthew Bowra-Dean
0c059af2ae Back to fixed width 2010-05-03 19:54:40 +12:00
Matthew Bowra-Dean
c76e5e541d Variable width site. 2010-05-03 19:54:39 +12:00
Matthew Bowra-Dean
a051e62cb8 Replaced download images with div. 2010-05-03 19:54:39 +12:00
Matthew Bowra-Dean
7e323c4f56 Tweaking things. 2010-05-03 19:54:38 +12:00
Matthew Bowra-Dean
a805bdcef6 Download buttons 2010-05-03 19:54:38 +12:00
Matthew Bowra-Dean
811362f570 Screenshot gallery. 2010-05-03 19:54:36 +12:00
Matthew Bowra-Dean
aee2f9739e Added placeholder stats and changed screenshot in the background. 2010-05-03 19:54:36 +12:00
Matthew Bowra-Dean
b319e3f298 Forgot CSS 2010-05-03 19:54:35 +12:00
Matthew Bowra-Dean
45e9b0f689 Beginnings of websitesite redo. 2010-05-03 19:54:34 +12:00
Chris Forbes
c7db8bee90 increment game counter on start of each game 2010-05-03 19:34:21 +12:00
Chris Forbes
e8b77963e3 send new=1 on initial server ping so we can easily count games 2010-05-03 19:10:06 +12:00
Chris Forbes
5db6a389b3 (re)add ring smudge/scorch - required by nuke 2010-05-03 17:52:58 +12:00
Chris Forbes
8c4502429c add 'h' hotkey to cycle through bases (fact/mcv) 2010-05-03 17:47:08 +12:00
Chris Forbes
b47317f9db add proper victory conditions support to cnc 2010-05-02 16:00:08 +12:00
Chris Forbes
510cfc4afb unbitrot cnc; fix double-surrender oddity 2010-05-02 15:58:44 +12:00
Chris Forbes
4bd195e21c factor out some hardcoded constants from various Heli activities 2010-05-02 15:10:52 +12:00
Chris Forbes
104d188d9b make surrender actually work 2010-05-02 13:59:21 +12:00
Chris Forbes
447cd78757 add resume & surrender buttons to ingame menu 2010-05-02 13:57:31 +12:00
Chris Forbes
94b2055eb2 added tracking of deaths as well as kills 2010-05-02 13:31:56 +12:00
Chris Forbes
32c73fa72f heli separation 2010-05-02 13:18:13 +12:00
Chris Forbes
63b150f3fd revamp ore growth for massive simplification - pure SeedsResource-based 2010-05-01 15:27:42 +12:00
Chris Forbes
affd853a96 add sounds for grenades; fix crash in -2 2010-05-01 14:58:06 +12:00
Chris Forbes
0c81356449 fix TSLA firing in low power or disabled 2010-05-01 14:51:56 +12:00
Chris Forbes
897c102d8e IsVisible patched to know about GPS 2010-05-01 14:48:54 +12:00
Chris Forbes
71cdb81ad8 accept null warheads in RenderInfantry.Damaged 2010-05-01 01:22:10 +12:00
Paul Chote
b5398b66f7 Try that again 2010-05-01 01:17:15 +12:00
Paul Chote
80621ca97a Test lose actions 2010-05-01 01:12:04 +12:00
Chris Forbes
9683ff64fb fix missing 7w, 8w animations 2010-05-01 00:35:22 +12:00
Chris Forbes
36fc025a86 fix desync due to bad FP in Combat.DoImpact 2010-04-30 22:01:03 +12:00
Chris Forbes
a22aa7ccb8 tidy up syncreport so it's just the interesting frame 2010-04-30 19:19:22 +12:00
Chris Forbes
b2ec750bcd add debug to Combat.DoImpact 2010-04-30 19:17:02 +12:00
Chris Forbes
4b1f6cf6fc shellmap centering 2010-04-30 18:51:11 +12:00
Chris Forbes
b9082503fd write all damage to log 2010-04-30 18:27:00 +12:00
Chris Forbes
2d0f30a341 remove VisualDest crap from bullets & combat code 2010-04-30 12:20:22 +12:00
Chris Forbes
66b1974237 unbreak AcceptSmudge on terraintypes again. 2010-04-30 10:49:34 +12:00
Chris Forbes
a526ebb254 mersenne twister implementation rather than mono's RNG 2010-04-29 20:12:02 +12:00
Chris Forbes
44ccb82904 dump all traits with nonzero sync 2010-04-29 18:10:55 +12:00
Chris Forbes
ce36f40ee2 fail 2010-04-29 17:45:34 +12:00
Chris Forbes
0c31e1c8a1 sync report on by default 2010-04-29 17:21:01 +12:00
Chris Forbes
cc2a18d5cb reveal start positions of allies 2010-04-29 16:51:48 +12:00
Chris Forbes
e53bbfc523 clean up spurious usings 2010-04-29 16:32:26 +12:00
Chris Forbes
ff7321cb12 decent sync reports 2010-04-29 16:28:26 +12:00
Chris Forbes
0e5c06521c reduce spam in log 2010-04-29 16:00:02 +12:00
Chris Forbes
6b82f21569 working orders via minimap 2010-04-28 11:29:36 +12:00
Chris Forbes
2f4df42924 strip a lot of dead crap from Minimap; fix bugs in prev; rudimentary input handler for minimap 2010-04-28 11:14:21 +12:00
Chris Forbes
79558dc57a unfailing some more radarbin bits 2010-04-28 10:55:34 +12:00
Chris Forbes
f57986030b blah 2010-04-28 10:53:46 +12:00
Chris Forbes
ffa6ede648 moved minimap update into RadarBinWidget.Tick 2010-04-28 10:42:38 +12:00
522 changed files with 32410 additions and 15561 deletions

3
.gitignore vendored
View File

@@ -21,6 +21,7 @@ log.txt
#binary stuff
/*.dll
*.pdb
*.mdb
/*.exe
OpenRA
@@ -50,3 +51,5 @@ packaging/osx/launcher/OpenRA.xcodeproj/*.mode1v3
temp.c
temp.o
temp.s
*.config

View File

@@ -1,10 +1,19 @@
CSC = gmcs
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
DEFINE = DEBUG;TRACE
PROGRAMS =fileformats gl game ra cnc aftermath ra_ng seqed mapcvtr
PROGRAMS =fileformats gl game ra cnc aftermath seqed mapcvtr editor
prefix = /usr/local
datarootdir = $(prefix)/share
datadir = $(datarootdir)
bindir = $(prefix)/bin
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
INSTALL = install
INSTALL_PROGRAM = $(INSTALL)
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll
CORE = fileformats gl game seqed mapcvtr
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
fileformats_TARGET = OpenRA.FileFormats.dll
fileformats_KIND = library
@@ -44,18 +53,20 @@ aftermath_KIND = library
aftermath_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
aftermath_LIBS = $(COMMON_LIBS) $(aftermath_DEPS)
ra_ng_SRCS = $(shell find OpenRA.Mods.RA-NG/ -iname '*.cs')
ra_ng_TARGET = mods/ra-ng/OpenRA.Mods.RA_NG.dll
ra_ng_KIND = library
ra_ng_DEPS = $(ra_TARGET) $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
ra_ng_LIBS = $(COMMON_LIBS) $(ra_ng_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)
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
mapcvtr_SRCS = $(shell find MapConverter/ -iname '*.cs')
mapcvtr_TARGET = MapConverter.exe
mapcvtr_KIND = winexe
@@ -64,6 +75,57 @@ mapcvtr_LIBS = $(COMMON_LIBS) $(mapcvtr_DEPS)
# -platform:x86
.SUFFIXES:
.PHONY: clean all default mods seqed mapcvtr install uninstall
all: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET) $(aftermath_TARGET) $(seqed_TARGET) $(mapcvtr_TARGET)
clean:
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb
distclean: clean
install: all
@-echo "Installing OpenRA to $(INSTALL_DIR)"
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) $(INSTALL_DIR)
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/aftermath
@$(INSTALL_PROGRAM) $(aftermath_TARGET) $(INSTALL_DIR)/mods/aftermath
@-cp $(foreach f,$(shell ls mods/aftermath --hide=*.dll),mods/aftermath/$(f)) $(INSTALL_DIR)/mods/aftermath
@cp -r mods/aftermath/packages $(INSTALL_DIR)/mods/aftermath
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) $(cnc_TARGET) $(INSTALL_DIR)/mods/cnc
@-cp $(foreach f,$(shell ls mods/cnc --hide=*.dll),mods/cnc/$(f)) $(INSTALL_DIR)/mods/cnc
@cp -r mods/cnc/maps $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
@$(INSTALL_PROGRAM) $(ra_TARGET) $(INSTALL_DIR)/mods/ra
@-cp $(foreach f,$(shell ls mods/ra --hide=*.dll),mods/ra/$(f)) $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/maps $(INSTALL_DIR)/mods/ra
@cp -r shaders $(INSTALL_DIR)
@cp *.ttf $(INSTALL_DIR)
@-cp *.ini $(INSTALL_DIR)
@cp -r thirdparty $(INSTALL_DIR)
@echo "OpenRA is now installed. You will now want to download"
@echo "http://open-ra.org/packages/ra-packages.zip and"
@echo "http://open-ra.org/packages/cnc-packages.zip"
@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
mods: $(ra_TARGET) $(cnc_TARGET) $(aftermath_TARGET)
seqed: $(seqed_TARGET)
mapcvtr: $(mapcvtr_TARGET)
editor: $(editor_TARGET)
define BUILD_ASSEMBLY
@@ -73,23 +135,8 @@ $$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS)
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
-define:"$(DEFINE)" \
-t:"$$($(1)_KIND)" \
$$($(1)_EXTRA) \
$$($(1)_SRCS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
.SUFFIXES:
.PHONY: clean all default mods seqed mapcvtr
clean:
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb
mods: $(ra_TARGET) $(cnc_TARGET) $(aftermath_TARGET) $(ra_ng_TARGET)
seqed: $(seqed_TARGET)
mapcvtr: $(mapcvtr_TARGET)
all: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET) $(aftermath_TARGET) $(ra_ng_TARGET) $(seqed_TARGET) $(mapcvtr_TARGET)
.DEFAULT: all

View File

@@ -112,7 +112,6 @@ namespace MapConverter
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
ConvertIniMap(args[1]);
Map.DebugContents();
Save(args[2]);
}
@@ -127,7 +126,6 @@ namespace MapConverter
{Pair.New("cnc","WINTER"),Pair.New("win","winter.col")},
};
TerrainColorSet terrainTypeColors;
TileSet tileset;
public void ConvertIniMap(string iniFile)
{
@@ -155,16 +153,17 @@ namespace MapConverter
UnpackRATileData(ReadPackedSection(file.GetSection("MapPack")));
UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack")));
ReadRATrees(file);
terrainTypeColors = new TerrainColorSet(fileMapping[Pair.New("ra",Map.Tileset)].Second);
tileset = new TileSet("tileSet.til","templates.ini",fileMapping[Pair.New("ra",Map.Tileset)].First);
// TODO: Fixme
//tileset = new TileSet("tileSet.til","templates.ini",fileMapping[Pair.New("ra",Map.Tileset)].First);
}
else // CNC
{
UnpackCncTileData(FileSystem.Open(iniFile.Substring(0,iniFile.Length-4)+".bin"));
ReadCncOverlay(file);
ReadCncTrees(file);
terrainTypeColors = new TerrainColorSet(fileMapping[Pair.New("cnc",Map.Tileset)].Second);
tileset = new TileSet("tileSet.til","templates.ini",fileMapping[Pair.New("cnc",Map.Tileset)].First);
// TODO: Fixme
//tileset = new TileSet("tileSet.til","templates.ini",fileMapping[Pair.New("cnc",Map.Tileset)].First);
}
LoadActors(file, "STRUCTURES");
@@ -275,7 +274,7 @@ namespace MapConverter
Map.MapResources[i,j] = new TileReference<byte,byte>(res.First, res.Second);
if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o]))
Map.Actors.Add("Actor"+ActorCount++, new ActorReference( overlayActorMapping[raOverlayNames[o]], new int2(i,j), "Neutral"));
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, overlayActorMapping[raOverlayNames[o]], new int2(i,j), "Neutral"));
}
}
@@ -288,7 +287,7 @@ namespace MapConverter
foreach( KeyValuePair<string, string> kv in terrain )
{
var loc = int.Parse( kv.Key );
Map.Actors.Add("Actor"+ActorCount++, new ActorReference(kv.Value.ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), "Neutral" ) );
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++,kv.Value.ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), "Neutral" ) );
}
}
@@ -329,7 +328,7 @@ namespace MapConverter
Map.MapResources[ cell.X, cell.Y ] = new TileReference<byte,byte>(res.First, res.Second);
if (overlayActorMapping.ContainsKey(kv.Value.ToLower()))
Map.Actors.Add("Actor"+ActorCount++, new ActorReference( overlayActorMapping[kv.Value.ToLower()], new int2(cell.X,cell.Y), "Neutral"));
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, overlayActorMapping[kv.Value.ToLower()], new int2(cell.X,cell.Y), "Neutral"));
}
}
@@ -343,7 +342,7 @@ namespace MapConverter
foreach( KeyValuePair<string, string> kv in terrain )
{
var loc = int.Parse( kv.Key );
Map.Actors.Add("Actor"+ActorCount++, new ActorReference( kv.Value.Split(',')[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize),"Neutral"));
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, kv.Value.Split(',')[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize),"Neutral"));
}
}
@@ -356,7 +355,7 @@ namespace MapConverter
var loc = int.Parse(parts[3]);
if (parts[0] == "")
parts[0] = "Neutral";
Map.Actors.Add("Actor"+ActorCount++, new ActorReference( parts[1].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), parts[0]));
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, parts[1].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), parts[0]));
}
}
@@ -374,31 +373,12 @@ namespace MapConverter
{
return s.Length <= maxLength ? s : s.Substring(0,maxLength );
}
public void SavePreviewImage(string filepath)
{
var xs = Map.TopLeft.X;
var ys = Map.TopLeft.Y;
var bitmap = new Bitmap(Map.Width, Map.Height);
for (var x = 0; x < Map.Width; x++)
for (var y = 0; y < Map.Height; y++)
bitmap.SetPixel(x, y, terrainTypeColors.ColorForTerrainType(tileset.GetTerrainType(Map.MapTiles[x+xs, y+ys])));
for (var x = 0; x < Map.Width; x++)
for (var y = 0; y < Map.Height; y++)
if (Map.MapResources[x+xs, y+ys].type > 0)
bitmap.SetPixel(x, y, terrainTypeColors.ColorForTerrainType(TerrainType.Ore));
bitmap.Save(filepath,ImageFormat.Png);
}
public void Save(string filepath)
{
Directory.CreateDirectory(filepath);
Map.Package = new Folder(filepath);
SavePreviewImage(Path.Combine(filepath,"preview.png"));
Map.Save(filepath);
}
}

View File

@@ -14,7 +14,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<OutputPath>..\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@@ -28,7 +28,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
@@ -44,5 +44,5 @@
<Name>OpenRA.FileFormats</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

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

View File

@@ -0,0 +1,30 @@
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Editor
{
class ActorTemplate
{
public Bitmap Bitmap;
public ActorInfo Info;
public bool Centered;
}
class BrushTemplate
{
public Bitmap Bitmap;
public ushort N;
}
class ResourceTemplate
{
public Bitmap Bitmap;
public ResourceTypeInfo Info;
public int Value;
}
class WaypointTemplate
{
}
}

324
OpenRA.Editor/Form1.Designer.cs generated Normal file
View File

@@ -0,0 +1,324 @@
namespace OpenRA.Editor
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </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.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.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolStripButton3 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton5 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton4 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton1 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton6 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton7 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton2 = new System.Windows.Forms.ToolStripButton();
this.tt = new System.Windows.Forms.ToolTip(this.components);
this.folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
this.surface1 = new OpenRA.Editor.Surface();
this.toolStripContainer1.ContentPanel.SuspendLayout();
this.toolStripContainer1.TopToolStripPanel.SuspendLayout();
this.toolStripContainer1.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.toolStrip1.SuspendLayout();
this.SuspendLayout();
//
// toolStripContainer1
//
//
// toolStripContainer1.ContentPanel
//
this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1);
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 680);
this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.toolStripContainer1.Location = new System.Drawing.Point(0, 0);
this.toolStripContainer1.Name = "toolStripContainer1";
this.toolStripContainer1.Size = new System.Drawing.Size(985, 705);
this.toolStripContainer1.TabIndex = 1;
this.toolStripContainer1.Text = "toolStripContainer1";
//
// toolStripContainer1.TopToolStripPanel
//
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1);
//
// 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.tabControl1);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.surface1);
this.splitContainer1.Size = new System.Drawing.Size(985, 680);
this.splitContainer1.SplitterDistance = 198;
this.splitContainer1.TabIndex = 0;
//
// tabControl1
//
this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Left;
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(198, 680);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tilePalette);
this.tabPage1.Location = new System.Drawing.Point(23, 4);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(171, 672);
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(165, 666);
this.tilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.actorPalette);
this.tabPage2.Location = new System.Drawing.Point(23, 4);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(171, 672);
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(165, 666);
this.actorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.resourcePalette);
this.tabPage3.Location = new System.Drawing.Point(23, 4);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(171, 672);
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(171, 672);
this.resourcePalette.TabIndex = 3;
//
// toolStrip1
//
this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripButton3,
this.toolStripButton5,
this.toolStripButton4,
this.toolStripButton1,
this.toolStripButton6,
this.toolStripButton7,
this.toolStripButton2});
this.toolStrip1.Location = new System.Drawing.Point(3, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(480, 25);
this.toolStrip1.TabIndex = 0;
//
// toolStripButton3
//
this.toolStripButton3.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton3.Image")));
this.toolStripButton3.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton3.Name = "toolStripButton3";
this.toolStripButton3.Size = new System.Drawing.Size(51, 22);
this.toolStripButton3.Text = "New";
this.toolStripButton3.Click += new System.EventHandler(this.NewClicked);
//
// toolStripButton5
//
this.toolStripButton5.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton5.Image")));
this.toolStripButton5.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton5.Name = "toolStripButton5";
this.toolStripButton5.Size = new System.Drawing.Size(56, 22);
this.toolStripButton5.Text = "Open";
this.toolStripButton5.Click += new System.EventHandler(this.OpenClicked);
//
// toolStripButton4
//
this.toolStripButton4.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton4.Image")));
this.toolStripButton4.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton4.Name = "toolStripButton4";
this.toolStripButton4.Size = new System.Drawing.Size(51, 22);
this.toolStripButton4.Text = "Save";
this.toolStripButton4.Click += new System.EventHandler(this.SaveClicked);
//
// toolStripButton1
//
this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image")));
this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton1.Name = "toolStripButton1";
this.toolStripButton1.Size = new System.Drawing.Size(76, 22);
this.toolStripButton1.Text = "Save As...";
this.toolStripButton1.Click += new System.EventHandler(this.SaveAsClicked);
//
// toolStripButton6
//
this.toolStripButton6.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton6.Image")));
this.toolStripButton6.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton6.Name = "toolStripButton6";
this.toolStripButton6.Size = new System.Drawing.Size(59, 22);
this.toolStripButton6.Text = "Resize";
this.toolStripButton6.Click += new System.EventHandler(this.ResizeClicked);
//
// toolStripButton7
//
this.toolStripButton7.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton7.Image")));
this.toolStripButton7.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton7.Name = "toolStripButton7";
this.toolStripButton7.Size = new System.Drawing.Size(80, 22);
this.toolStripButton7.Text = "Properties";
this.toolStripButton7.Click += new System.EventHandler(this.PropertiesClicked);
//
// toolStripButton2
//
this.toolStripButton2.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton2.Image")));
this.toolStripButton2.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton2.Name = "toolStripButton2";
this.toolStripButton2.Size = new System.Drawing.Size(95, 22);
this.toolStripButton2.Text = "Spawnpoints";
this.toolStripButton2.Click += new System.EventHandler(this.SpawnPointsClicked);
//
// tt
//
this.tt.ShowAlways = true;
//
// 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, 680);
this.surface1.TabIndex = 5;
this.surface1.Text = "surface1";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(985, 705);
this.Controls.Add(this.toolStripContainer1);
this.KeyPreview = true;
this.Name = "Form1";
this.Text = "OpenRA Editor";
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
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.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ToolStripContainer toolStripContainer1;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.ToolTip tt;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton toolStripButton1;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.FlowLayoutPanel tilePalette;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.ToolStripButton toolStripButton2;
private System.Windows.Forms.FlowLayoutPanel actorPalette;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
private System.Windows.Forms.ToolStripButton toolStripButton3;
private System.Windows.Forms.ToolStripButton toolStripButton5;
private System.Windows.Forms.ToolStripButton toolStripButton4;
private System.Windows.Forms.FolderBrowserDialog folderBrowser;
private System.Windows.Forms.ToolStripButton toolStripButton6;
private System.Windows.Forms.ToolStripButton toolStripButton7;
private Surface surface1;
}
}

432
OpenRA.Editor/Form1.cs Normal file
View File

@@ -0,0 +1,432 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Editor
{
public partial class Form1 : Form
{
public Form1(string[] mods)
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
currentMod = mods.FirstOrDefault() ?? "ra";
Text = "OpenRA Editor (mod:{0})".F(currentMod);
var manifest = new Manifest(new[] { currentMod });
Game.LoadModAssemblies(manifest);
FileSystem.UnmountAll();
foreach (var folder in manifest.Folders) FileSystem.Mount(folder);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
Rules.LoadRules(manifest, new Map());
folderBrowser.SelectedPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
}
string loadedMapName;
string colors;
string currentMod = "ra";
TileSet tileset;
void LoadMap(string mapname)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = mapname;
var manifest = new Manifest(new[] { currentMod });
Game.LoadModAssemblies(manifest);
FileSystem.UnmountAll();
foreach (var folder in manifest.Folders) FileSystem.Mount(folder);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
// load the map
var map = new Map(new Folder(mapname));
PrepareMapResources(manifest, map);
}
void NewMap(Map map)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = null;
var manifest = new Manifest(new[] { currentMod });
Game.LoadModAssemblies(manifest);
FileSystem.UnmountAll();
foreach (var folder in manifest.Folders) FileSystem.Mount(folder);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
PrepareMapResources(manifest, map);
}
void PrepareMapResources(Manifest manifest, Map map)
{
Rules.LoadRules(manifest, map);
tileset = Rules.TileSets[map.Theater];
tileset.LoadTiles();
var palette = new Palette(FileSystem.Open(map.Theater.ToLowerInvariant() + ".pal"), true);
surface1.Bind(map, tileset, palette);
// construct the palette of tiles
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
foreach (var t in tileset.Templates)
{
try
{
var bitmap = RenderTemplate(tileset, (ushort)t.Key, palette);
var ibox = new PictureBox
{
Image = bitmap,
Width = bitmap.Width / 2,
Height = bitmap.Height / 2,
SizeMode = PictureBoxSizeMode.StretchImage
};
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
ibox.Click += (_, e) => surface1.SetBrush(brushTemplate);
var template = t.Value;
tilePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{1}:{0} ({2}x{3})".F(
template.Image,
template.Id,
template.Size.X,
template.Size.Y));
}
catch { }
}
var actorTemplates = new List<ActorTemplate>();
foreach (var a in Rules.Info.Keys)
{
try
{
var info = Rules.Info[a];
var template = RenderActor(info, tileset, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = template.Bitmap.Width / 2,
Height = template.Bitmap.Height / 2,
SizeMode = PictureBoxSizeMode.StretchImage
};
ibox.Click += (_, e) => surface1.SetActor(template);
actorPalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}:{1}".F(
info.Name,
info.Category));
actorTemplates.Add(template);
}
catch { }
}
surface1.BindActorTemplates(actorTemplates);
var resourceTemplates = new List<ResourceTemplate>();
foreach (var a in Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>())
{
try
{
var template = RenderResourceType(a, tileset.Extensions, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = template.Bitmap.Width,
Height = template.Bitmap.Height,
SizeMode = PictureBoxSizeMode.StretchImage
};
ibox.Click += (_, e) => surface1.SetResource(template);
resourcePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}:{1}cr".F(
template.Info.Name,
template.Info.ValuePerUnit));
resourceTemplates.Add(template);
}
catch { }
}
surface1.BindResourceTemplates(resourceTemplates);
foreach (var p in palettes) { p.Visible = true; p.ResumeLayout(); }
}
static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(24 * template.Size.X, 24 * template.Size.Y);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < 24; i++)
for (var j = 0; j < 24; j++)
q[(v * 24 + j) * stride + u * 24 + i] = p.GetColor(rawImage[i + 24 * j]).ToArgb();
}
else
{
for (var i = 0; i < 24; i++)
for (var j = 0; j < 24; j++)
q[(v * 24 + j) * stride + u * 24 + i] = Color.Transparent.ToArgb();
}
}
bitmap.UnlockBits(data);
return bitmap;
}
static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
string image = null;
if (ri.OverrideTheater != null)
for (int i = 0; i < ri.OverrideTheater.Length; i++)
if (ri.OverrideTheater[i] == tileset.Id)
image = ri.OverrideImage[i];
image = image ?? ri.Image ?? info.Name;
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
}
}
static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
{
var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts))
{
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
}
}
void ResizeClicked(object sender, EventArgs e)
{
using (var rd = new ResizeDialog())
{
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;
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);
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
{
surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value);
surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches
}
surface1.Invalidate();
}
}
void SavePreviewImage(string filepath)
{
var Map = surface1.Map;
var xs = Map.TopLeft.X;
var ys = Map.TopLeft.Y;
var bitmap = new Bitmap(Map.Width, Map.Height);
for (var x = 0; x < Map.Width; x++)
for (var y = 0; y < Map.Height; y++)
bitmap.SetPixel(x, y, tileset.Terrain[tileset.GetTerrainType(Map.MapTiles[x + xs, y + ys])].Color);
for (var x = 0; x < Map.Width; x++)
for (var y = 0; y < Map.Height; y++)
if (Map.MapResources[x + xs, y + ys].type > 0)
bitmap.SetPixel(x, y, tileset.Terrain["Ore"].Color);
bitmap.Save(filepath, ImageFormat.Png);
}
void SaveClicked(object sender, EventArgs e)
{
if (loadedMapName == null)
SaveAsClicked(sender, e);
else
{
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
surface1.Map.Package = new Folder(loadedMapName);
SavePreviewImage(Path.Combine(loadedMapName, "preview.png"));
surface1.Map.Save(loadedMapName);
}
}
void SaveAsClicked(object sender, EventArgs e)
{
folderBrowser.ShowNewFolderButton = true;
if (DialogResult.OK == folderBrowser.ShowDialog())
{
loadedMapName = folderBrowser.SelectedPath;
SaveClicked(sender, e);
}
}
void OpenClicked(object sender, EventArgs e)
{
folderBrowser.ShowNewFolderButton = true;
if (DialogResult.OK == folderBrowser.ShowDialog())
LoadMap(folderBrowser.SelectedPath);
}
void NewClicked(object sender, EventArgs e)
{
using (var nmd = new NewMapDialog())
{
nmd.theater.Items.Clear();
nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray());
nmd.theater.SelectedIndex = 0;
if (DialogResult.OK == nmd.ShowDialog())
{
var map = new Map();
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
map.TopLeft = new int2((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value);
map.BottomRight = new int2((int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.Tileset = nmd.theater.SelectedItem as string;
NewMap(map);
}
}
}
void PropertiesClicked(object sender, EventArgs e)
{
using (var pd = new PropertiesDialog())
{
pd.title.Text = surface1.Map.Title;
pd.desc.Text = surface1.Map.Description;
pd.author.Text = surface1.Map.Author;
pd.selectable.Checked = surface1.Map.Selectable;
if (DialogResult.OK != pd.ShowDialog())
return;
surface1.Map.Title = pd.title.Text;
surface1.Map.Description = pd.desc.Text;
surface1.Map.Author = pd.author.Text;
surface1.Map.Selectable = pd.selectable.Checked;
}
}
void SpawnPointsClicked(object sender, EventArgs e) { surface1.SetWaypoint(new WaypointTemplate()); }
void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; }
void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; }
}
}

235
OpenRA.Editor/Form1.resx Normal file
View File

@@ -0,0 +1,235 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>77, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="toolStripButton3.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton4.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
</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="folderBrowser.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>182, 17</value>
</metadata>
</root>

280
OpenRA.Editor/NewMapDialog.Designer.cs generated Normal file
View File

@@ -0,0 +1,280 @@
namespace OpenRA.Editor
{
partial class NewMapDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.cordonBottom = new System.Windows.Forms.NumericUpDown();
this.cordonTop = new System.Windows.Forms.NumericUpDown();
this.cordonRight = new System.Windows.Forms.NumericUpDown();
this.cordonLeft = new System.Windows.Forms.NumericUpDown();
this.height = new System.Windows.Forms.NumericUpDown();
this.width = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.theater = new System.Windows.Forms.ComboBox();
((System.ComponentModel.ISupportInitialize)(this.cordonBottom)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonTop)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonRight)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonLeft)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.height)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.width)).BeginInit();
this.SuspendLayout();
//
// button2
//
this.button2.DialogResult = System.Windows.Forms.DialogResult.OK;
this.button2.Location = new System.Drawing.Point(229, 160);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 12;
this.button2.Text = "OK";
this.button2.UseVisualStyleBackColor = true;
//
// button1
//
this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button1.Location = new System.Drawing.Point(310, 160);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 13;
this.button1.Text = "Cancel";
this.button1.UseVisualStyleBackColor = true;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(31, 77);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(107, 13);
this.label3.TabIndex = 9;
this.label3.Text = "Cordon Right/Bottom";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(31, 51);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(86, 13);
this.label2.TabIndex = 11;
this.label2.Text = "Cordon Left/Top";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(31, 25);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(27, 13);
this.label1.TabIndex = 10;
this.label1.Text = "Size";
//
// cordonBottom
//
this.cordonBottom.Location = new System.Drawing.Point(280, 75);
this.cordonBottom.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonBottom.Name = "cordonBottom";
this.cordonBottom.Size = new System.Drawing.Size(105, 20);
this.cordonBottom.TabIndex = 8;
this.cordonBottom.Value = new decimal(new int[] {
112,
0,
0,
0});
//
// cordonTop
//
this.cordonTop.Location = new System.Drawing.Point(280, 49);
this.cordonTop.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonTop.Name = "cordonTop";
this.cordonTop.Size = new System.Drawing.Size(105, 20);
this.cordonTop.TabIndex = 3;
this.cordonTop.Value = new decimal(new int[] {
16,
0,
0,
0});
//
// cordonRight
//
this.cordonRight.Location = new System.Drawing.Point(169, 75);
this.cordonRight.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonRight.Name = "cordonRight";
this.cordonRight.Size = new System.Drawing.Size(105, 20);
this.cordonRight.TabIndex = 5;
this.cordonRight.Value = new decimal(new int[] {
112,
0,
0,
0});
//
// cordonLeft
//
this.cordonLeft.Location = new System.Drawing.Point(169, 49);
this.cordonLeft.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonLeft.Name = "cordonLeft";
this.cordonLeft.Size = new System.Drawing.Size(105, 20);
this.cordonLeft.TabIndex = 7;
this.cordonLeft.Value = new decimal(new int[] {
16,
0,
0,
0});
//
// height
//
this.height.Increment = new decimal(new int[] {
8,
0,
0,
0});
this.height.Location = new System.Drawing.Point(280, 23);
this.height.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.height.Name = "height";
this.height.Size = new System.Drawing.Size(105, 20);
this.height.TabIndex = 6;
this.height.Value = new decimal(new int[] {
128,
0,
0,
0});
//
// width
//
this.width.Increment = new decimal(new int[] {
8,
0,
0,
0});
this.width.Location = new System.Drawing.Point(169, 23);
this.width.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.width.Name = "width";
this.width.Size = new System.Drawing.Size(105, 20);
this.width.TabIndex = 4;
this.width.Value = new decimal(new int[] {
128,
0,
0,
0});
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(31, 124);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(44, 13);
this.label4.TabIndex = 14;
this.label4.Text = "Theater";
//
// theater
//
this.theater.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.theater.FormattingEnabled = true;
this.theater.Location = new System.Drawing.Point(169, 121);
this.theater.Name = "theater";
this.theater.Size = new System.Drawing.Size(216, 21);
this.theater.TabIndex = 15;
//
// NewMapDialog
//
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(418, 210);
this.Controls.Add(this.theater);
this.Controls.Add(this.label4);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.cordonBottom);
this.Controls.Add(this.cordonTop);
this.Controls.Add(this.cordonRight);
this.Controls.Add(this.cordonLeft);
this.Controls.Add(this.height);
this.Controls.Add(this.width);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "NewMapDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "New Map";
((System.ComponentModel.ISupportInitialize)(this.cordonBottom)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonTop)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonRight)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonLeft)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.height)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.width)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
public System.Windows.Forms.NumericUpDown cordonBottom;
public System.Windows.Forms.NumericUpDown cordonTop;
public System.Windows.Forms.NumericUpDown cordonRight;
public System.Windows.Forms.NumericUpDown cordonLeft;
public System.Windows.Forms.NumericUpDown height;
public System.Windows.Forms.NumericUpDown width;
private System.Windows.Forms.Label label4;
public System.Windows.Forms.ComboBox theater;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{00038B75-405B-44F5-8691-BD2546DBE224}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenRA.Editor</RootNamespace>
<AssemblyName>OpenRA.Editor</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ActorTemplate.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="NewMapDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="NewMapDialog.Designer.cs">
<DependentUpon>NewMapDialog.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="PropertiesDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="PropertiesDialog.Designer.cs">
<DependentUpon>PropertiesDialog.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="NewMapDialog.resx">
<DependentUpon>NewMapDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="PropertiesDialog.resx">
<DependentUpon>PropertiesDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="ResizeDialog.resx">
<DependentUpon>ResizeDialog.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="ResizeDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ResizeDialog.Designer.cs">
<DependentUpon>ResizeDialog.cs</DependentUpon>
</Compile>
<Compile Include="Surface.cs">
<SubType>Component</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
<Name>OpenRA.FileFormats</Name>
</ProjectReference>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
<Project>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</Project>
<Name>OpenRA.Game</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

18
OpenRA.Editor/Program.cs Normal file
View File

@@ -0,0 +1,18 @@
using System;
using System.Globalization;
using System.Windows.Forms;
namespace OpenRA.Editor
{
static class Program
{
[STAThread]
static void Main( string[] args )
{
Application.CurrentCulture = CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenRA.Editor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("OpenRA.Editor")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e18ea68f-f344-46c9-b026-8bda76fa91f8")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace OpenRA.Editor.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenRA.Editor.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

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

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace OpenRA.Editor.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

159
OpenRA.Editor/PropertiesDialog.Designer.cs generated Normal file
View File

@@ -0,0 +1,159 @@
namespace OpenRA.Editor
{
partial class PropertiesDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </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();
}
#endregion
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
public System.Windows.Forms.TextBox title;
private System.Windows.Forms.Label label2;
public System.Windows.Forms.TextBox desc;
public System.Windows.Forms.CheckBox selectable;
private System.Windows.Forms.Label label3;
public System.Windows.Forms.TextBox author;
}
}

View File

@@ -0,0 +1,12 @@
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class PropertiesDialog : Form
{
public PropertiesDialog()
{
InitializeComponent();
}
}
}

View File

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

226
OpenRA.Editor/ResizeDialog.Designer.cs generated Normal file
View File

@@ -0,0 +1,226 @@
namespace OpenRA.Editor
{
partial class ResizeDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.width = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.cordonLeft = new System.Windows.Forms.NumericUpDown();
this.cordonTop = new System.Windows.Forms.NumericUpDown();
this.cordonRight = new System.Windows.Forms.NumericUpDown();
this.cordonBottom = new System.Windows.Forms.NumericUpDown();
this.label3 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.height = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.width)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonLeft)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonTop)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonRight)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.cordonBottom)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.height)).BeginInit();
this.SuspendLayout();
//
// width
//
this.width.Increment = new decimal(new int[] {
8,
0,
0,
0});
this.width.Location = new System.Drawing.Point(161, 18);
this.width.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.width.Name = "width";
this.width.Size = new System.Drawing.Size(105, 20);
this.width.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(23, 20);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(27, 13);
this.label1.TabIndex = 1;
this.label1.Text = "Size";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(23, 46);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(86, 13);
this.label2.TabIndex = 1;
this.label2.Text = "Cordon Left/Top";
//
// cordonLeft
//
this.cordonLeft.Location = new System.Drawing.Point(161, 44);
this.cordonLeft.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonLeft.Name = "cordonLeft";
this.cordonLeft.Size = new System.Drawing.Size(105, 20);
this.cordonLeft.TabIndex = 0;
//
// cordonTop
//
this.cordonTop.Location = new System.Drawing.Point(272, 44);
this.cordonTop.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonTop.Name = "cordonTop";
this.cordonTop.Size = new System.Drawing.Size(105, 20);
this.cordonTop.TabIndex = 0;
//
// cordonRight
//
this.cordonRight.Location = new System.Drawing.Point(161, 70);
this.cordonRight.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonRight.Name = "cordonRight";
this.cordonRight.Size = new System.Drawing.Size(105, 20);
this.cordonRight.TabIndex = 0;
//
// cordonBottom
//
this.cordonBottom.Location = new System.Drawing.Point(272, 70);
this.cordonBottom.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.cordonBottom.Name = "cordonBottom";
this.cordonBottom.Size = new System.Drawing.Size(105, 20);
this.cordonBottom.TabIndex = 0;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(23, 72);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(107, 13);
this.label3.TabIndex = 1;
this.label3.Text = "Cordon Right/Bottom";
//
// button1
//
this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button1.Location = new System.Drawing.Point(302, 111);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 2;
this.button1.Text = "Cancel";
this.button1.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.DialogResult = System.Windows.Forms.DialogResult.OK;
this.button2.Location = new System.Drawing.Point(221, 111);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "OK";
this.button2.UseVisualStyleBackColor = true;
//
// height
//
this.height.Increment = new decimal(new int[] {
8,
0,
0,
0});
this.height.Location = new System.Drawing.Point(272, 18);
this.height.Maximum = new decimal(new int[] {
2048,
0,
0,
0});
this.height.Name = "height";
this.height.Size = new System.Drawing.Size(105, 20);
this.height.TabIndex = 0;
//
// ResizeDialog
//
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(409, 146);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.cordonBottom);
this.Controls.Add(this.cordonTop);
this.Controls.Add(this.cordonRight);
this.Controls.Add(this.cordonLeft);
this.Controls.Add(this.height);
this.Controls.Add(this.width);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "ResizeDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Resize Map";
((System.ComponentModel.ISupportInitialize)(this.width)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonLeft)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonTop)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonRight)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.cordonBottom)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.height)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
public System.Windows.Forms.NumericUpDown width;
public System.Windows.Forms.NumericUpDown cordonLeft;
public System.Windows.Forms.NumericUpDown cordonTop;
public System.Windows.Forms.NumericUpDown cordonRight;
public System.Windows.Forms.NumericUpDown cordonBottom;
public System.Windows.Forms.NumericUpDown height;
}
}

View File

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

View File

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

406
OpenRA.Editor/Surface.cs Normal file
View File

@@ -0,0 +1,406 @@
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Thirdparty;
using System.Collections;
namespace OpenRA.Editor
{
class Surface : Control
{
public Map Map { get; private set; }
public TileSet TileSet { get; private set; }
public Palette Palette { get; private set; }
int2 Offset;
BrushTemplate Brush;
ActorTemplate Actor;
ResourceTemplate Resource;
WaypointTemplate Waypoint;
public bool IsPanning;
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
public void Bind(Map m, TileSet ts, Palette p)
{
Map = m;
TileSet = ts;
Palette = p;
Brush = null;
Chunks.Clear();
}
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 BindActorTemplates(IEnumerable<ActorTemplate> templates)
{
ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant());
}
public void BindResourceTemplates(IEnumerable<ResourceTemplate> templates)
{
ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType);
}
Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
public Surface()
: base()
{
BackColor = Color.Black;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
static readonly Pen CordonPen = new Pen(Color.Red);
int2 MousePos;
public void Scroll(int2 dx)
{
Offset -= dx;
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var oldMousePos = MousePos;
MousePos = new int2(e.Location);
if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
Scroll(oldMousePos - MousePos);
else
{
if (e.Button == MouseButtons.Right)
Erase();
if (e.Button == MouseButtons.Left)
Draw();
Invalidate();
}
}
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();
}
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);
}
}
}
}
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());
}
void Erase()
{
Actor = null;
Brush = null;
Resource = null;
Waypoint = null;
var key = Map.Actors.FirstOrDefault(a => a.Value.Location == GetBrushLocation());
if (key.Key != null) Map.Actors.Remove(key.Key);
if (Map.MapResources[GetBrushLocation().X, GetBrushLocation().Y].type != 0)
{
Map.MapResources[GetBrushLocation().X, GetBrushLocation().Y] = new TileReference<byte, byte>();
var ch = new int2((GetBrushLocation().X) / ChunkSize, (GetBrushLocation().Y) / ChunkSize);
if (Chunks.ContainsKey(ch))
{
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
}
var k = Map.Waypoints.FirstOrDefault(a => a.Value == GetBrushLocation());
if (k.Key != null) Map.Waypoints.Remove(k.Key);
}
void Draw()
{
if (Brush != null) DrawWithBrush();
if (Actor != null) DrawWithActor();
if (Resource != null) DrawWithResource();
if (Waypoint != null) DrawWithWaypoint();
}
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(id,Actor.Info.Name.ToLowerInvariant(), GetBrushLocation(), owner);
}
Random r = new 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);
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
if (e.Button == MouseButtons.Left) Draw();
}
Invalidate();
}
const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
Bitmap RenderChunk(int u, int v)
{
var bitmap = new Bitmap(ChunkSize * 24, ChunkSize * 24);
bitmap.SetPixel(0, 0, Color.Green);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* p = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < ChunkSize; i++)
for (var j = 0; j < ChunkSize; j++)
{
var tr = Map.MapTiles[u * ChunkSize + i, v * ChunkSize + j];
var tile = TileSet.Tiles[tr.type];
var index = (tr.image < tile.TileBitmapBytes.Count) ? tr.image : (byte)0;
var rawImage = tile.TileBitmapBytes[index];
for (var x = 0; x < 24; x++)
for (var y = 0; y < 24; y++)
p[ (j * 24 + y) * stride + i * 24 + x ] = Palette.GetColor(rawImage[x + 24 * y]).ToArgb();
if (Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type != 0)
{
var resourceImage = ResourceTemplates[Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap;
var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int* q = (int*)srcdata.Scan0.ToPointer();
var srcstride = srcdata.Stride >> 2;
for (var x = 0; x < 24; x++)
for (var y = 0; y < 24; y++)
{
var c = q[y * srcstride + x];
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
p[(j * 24 + y) * stride + i * 24 + x] = c;
}
resourceImage.UnlockBits(srcdata);
}
}
}
bitmap.UnlockBits(data);
return bitmap;
}
int2 GetBrushLocation()
{
var v = MousePos - Offset;
return new int2(v.X / 24, v.Y / 24);
}
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
g.DrawImage(t.Bitmap,
((24 * p + Offset
- (t.Centered
? new int2(t.Bitmap.Width / 2 - 12, t.Bitmap.Height / 2 - 12)
: int2.Zero)).ToPoint()));
}
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
var origin = (24 * p + Offset
- (t.Centered
? new int2(t.Bitmap.Width / 2 - 12, t.Bitmap.Height / 2 - 12)
: int2.Zero)).ToPoint();
g.DrawRectangle(CordonPen,
origin.X, origin.Y,
t.Bitmap.Width, t.Bitmap.Height );
}
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 v = 0; v < Map.MapSize.Y; v += ChunkSize)
{
var x = new int2(u/ChunkSize,v/ChunkSize);
if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
e.Graphics.DrawImage(Chunks[x], (24 * ChunkSize * x + Offset).ToPoint());
}
e.Graphics.DrawRectangle(CordonPen,
new Rectangle(Map.XOffset * 24 + Offset.X, Map.YOffset * 24 + Offset.Y, Map.Width * 24, Map.Height * 24));
foreach (var ar in Map.Actors)
DrawActor(e.Graphics, ar.Value.Location, ActorTemplates[ar.Value.Type]);
foreach (var wp in Map.Waypoints)
e.Graphics.DrawRectangle(Pens.LimeGreen, new Rectangle(
24 * wp.Value.X + Offset.X + 4,
24 * wp.Value.Y + Offset.Y + 4,
16, 16));
if (Brush != null)
e.Graphics.DrawImage(Brush.Bitmap,
(24 * GetBrushLocation() + Offset).ToPoint());
if (Actor != null)
DrawActor(e.Graphics, GetBrushLocation(), Actor);
if (Resource != null)
e.Graphics.DrawImage(Resource.Bitmap,
(24 * GetBrushLocation() + Offset).ToPoint());
if (Waypoint != null)
e.Graphics.DrawRectangle(Pens.LimeGreen, new Rectangle(
24 * GetBrushLocation().X + Offset.X + 4,
24 * GetBrushLocation().Y + Offset.Y + 4,
16, 16));
if (Brush == null && Actor == null && Resource == null)
{
var x = Map.Actors.FirstOrDefault(a => a.Value.Location == GetBrushLocation());
if (x.Key != null)
DrawActorBorder(e.Graphics, x.Value.Location, ActorTemplates[x.Value.Type]);
}
}
}
}

View File

@@ -20,9 +20,9 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA
{
@@ -60,5 +60,18 @@ namespace OpenRA
return data;
}
}
public static IEnumerable<string> ReadAllLines(this Stream s)
{
using (var sr = new StreamReader(s))
for (; ; )
{
var line = sr.ReadLine();
if (line == null)
yield break;
else
yield return line;
}
}
}
}

View File

@@ -55,7 +55,6 @@ namespace OpenRA.FileFormats
FieldLoader.LoadField(self,field,my[field].Value);
}
}
public static void LoadField( object self, string key, string value )
{
@@ -70,13 +69,22 @@ namespace OpenRA.FileFormats
if (x != null) x = x.Trim();
if( fieldType == typeof( int ) )
return int.Parse( x );
else if( fieldType == typeof( ushort ) )
return ushort.Parse( x );
else if (fieldType == typeof(float))
return float.Parse(x.Replace("%","")) * (x.Contains( '%' ) ? 0.01f : 1f);
else if (fieldType == typeof(string))
return x;
else if (fieldType == typeof(System.Drawing.Color))
{
var parts = x.Split(',');
return System.Drawing.Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
}
else if (fieldType.IsEnum)
return Enum.Parse(fieldType, x, true);

View File

@@ -20,22 +20,25 @@
namespace OpenRA.FileFormats
{
public struct ActorReference
public class ActorReference
{
public readonly string Id;
public readonly string Type;
public readonly int2 Location;
public readonly string Name;
public readonly string Owner;
public ActorReference( string name, int2 location, string owner )
public ActorReference(MiniYaml my)
{
Name = name;
FieldLoader.Load(this, my);
}
// Legacy construtor for old format maps
public ActorReference(string id, string type, int2 location, string owner )
{
Id = id;
Type = type;
Location = location;
Owner = owner;
}
public override string ToString ()
{
return string.Format("{0} {1} {2},{3}", Name, Owner, Location.X,Location.Y);
}
}
}

View File

@@ -34,23 +34,26 @@ namespace OpenRA.FileFormats
public string Uid;
// Yaml map data
public bool Selectable;
public int MapFormat = 1;
public bool Selectable = true;
public int MapFormat;
public string Title;
public string Description;
public string Author;
public int PlayerCount;
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
public Dictionary<string, MiniYaml> Rules = new Dictionary<string, MiniYaml>();
public Dictionary<string, MiniYaml> Weapons = new Dictionary<string, MiniYaml>();
public Dictionary<string, MiniYaml> Voices = new Dictionary<string, MiniYaml>();
public Dictionary<string, MiniYaml> Terrain = new Dictionary<string, MiniYaml>();
public Dictionary<string, MiniYaml> Music = new Dictionary<string, MiniYaml>();
public Dictionary<string, MiniYaml> Terrain = new Dictionary<string, MiniYaml>();
// Binary map data
public byte TileFormat = 1;
public int2 MapSize;
@@ -76,7 +79,27 @@ namespace OpenRA.FileFormats
"Selectable", "MapFormat", "Title", "Description", "Author", "PlayerCount", "Tileset", "MapSize", "TopLeft", "BottomRight"
};
public Map() { }
public Map()
{
MapSize = new int2(1, 1);
MapResources = new TileReference<byte, byte>[1, 1];
MapTiles = new TileReference<ushort, byte>[1, 1]
{ { new TileReference<ushort, byte> {
type = (ushort)0xffffu,
image = (byte)0xffu,
index = (byte)0xffu } } };
PlayerCount = 0;
TopLeft = new int2(0,0);
BottomRight = new int2(0,0);
Tileset = "TEMPERAT";
Players.Add("Neutral", new PlayerReference("Neutral", "neutral", "allies", true, true));
Title = "Name your map here";
Description = "Describe your map here";
Author = "Your name here";
}
public Map(IFolder package)
{
@@ -91,16 +114,42 @@ namespace OpenRA.FileFormats
{
string[] loc = wp.Value.Value.Split(',');
Waypoints.Add(wp.Key, new int2(int.Parse(loc[0]), int.Parse(loc[1])));
}
// Actors
foreach (var kv in yaml["Actors"].Nodes)
{
string[] vals = kv.Value.Value.Split(' ');
string[] loc = vals[2].Split(',');
var a = new ActorReference(vals[0], new int2(int.Parse(loc[0]), int.Parse(loc[1])), vals[2]);
Actors.Add(kv.Key, a);
}
}
// Players
if (MapFormat == 1)
{
Players.Add("Neutral", new PlayerReference("Neutral", "neutral", "allies", true, true));
}
else
{
foreach (var kv in yaml["Players"].Nodes)
{
var player = new PlayerReference(kv.Value);
Players.Add(player.Name, player);
}
}
// Actors
if (MapFormat == 1)
{
int actors = 0;
foreach (var kv in yaml["Actors"].Nodes)
{
string[] vals = kv.Value.Value.Split(' ');
string[] loc = vals[2].Split(',');
var a = new ActorReference("Actor"+actors++, vals[0], new int2(int.Parse(loc[0]), int.Parse(loc[1])), "Neutral");
Actors.Add(a.Id, a);
}
}
else
{
foreach (var kv in yaml["Actors"].Nodes)
{
var a = new ActorReference(kv.Value);
Actors.Add(a.Id, a);
}
}
// Smudges
foreach (var kv in yaml["Smudges"].Nodes)
@@ -119,17 +168,28 @@ namespace OpenRA.FileFormats
public void Save(string filepath)
{
MapFormat = 2;
Dictionary<string, MiniYaml> root = new Dictionary<string, MiniYaml>();
foreach (var field in SimpleFields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add(field, new MiniYaml(FieldSaver.FormatValue(this, f), null));
}
root.Add("Actors", MiniYaml.FromDictionary<string, ActorReference>(Actors));
root.Add(field, new MiniYaml(FieldSaver.FormatValue(this, f), null));
}
Dictionary<string, MiniYaml> playerYaml = new Dictionary<string, MiniYaml>();
foreach(var p in Players)
playerYaml.Add("PlayerReference@{0}".F(p.Key), FieldSaver.Save(p.Value));
root.Add("Players",new MiniYaml(null, playerYaml));
Dictionary<string, MiniYaml> actorYaml = new Dictionary<string, MiniYaml>();
foreach(var p in Actors)
actorYaml.Add("ActorReference@{0}".F(p.Key), FieldSaver.Save(p.Value));
root.Add("Actors",new MiniYaml(null, actorYaml));
root.Add("Waypoints", MiniYaml.FromDictionary<string, int2>(Waypoints));
root.Add("Smudges", MiniYaml.FromList<SmudgeReference>(Smudges));
root.Add("Smudges", MiniYaml.FromList<SmudgeReference>(Smudges));
root.Add("Rules", new MiniYaml(null, Rules));
SaveBinaryData(Path.Combine(filepath, "map.bin"));
root.WriteToFile(Path.Combine(filepath, "map.yaml"));
@@ -156,8 +216,10 @@ namespace OpenRA.FileFormats
{
using (var dataStream = Package.GetContent("map.bin"))
{
if (ReadByte(dataStream) != 1)
throw new InvalidDataException("Unknown binary map format");
// Load header info
byte version = ReadByte(dataStream);
var width = ReadWord(dataStream);
var height = ReadWord(dataStream);
@@ -243,22 +305,21 @@ namespace OpenRA.FileFormats
return (x >= TopLeft.X && y >= TopLeft.Y && x < BottomRight.X && y < BottomRight.Y);
}
public void DebugContents()
static T[,] ResizeArray<T>(T[,] ts, T t, int width, int height)
{
foreach (var field in SimpleFields)
Console.WriteLine("Loaded {0}: {1}", field, this.GetType().GetField(field).GetValue(this));
var result = new T[width, height];
for (var i = 0; i < width; i++)
for (var j = 0; j < height; j++)
result[i, j] = i <= ts.GetUpperBound(0) && j <= ts.GetUpperBound(1)
? ts[i, j] : t;
return result;
}
Console.WriteLine("Loaded Waypoints:");
foreach (var wp in Waypoints)
Console.WriteLine("\t{0} => {1}", wp.Key, wp.Value);
Console.WriteLine("Loaded Actors:");
foreach (var wp in Actors)
Console.WriteLine("\t{0} => {1} {2} {3}", wp.Key, wp.Value.Name, wp.Value.Owner, wp.Value.Location);
Console.WriteLine("Loaded Smudges:");
foreach (var s in Smudges)
Console.WriteLine("\t{0} {1} {2}", s.Type, s.Location, s.Depth);
public void Resize(int width, int height) // editor magic.
{
MapTiles = ResizeArray(MapTiles, MapTiles[0, 0], width, height);
MapResources = ResizeArray(MapResources, MapResources[0, 0], width, height);
MapSize = new int2(width, height);
}
}
}

View File

@@ -0,0 +1,45 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.FileFormats
{
public class PlayerReference
{
public readonly string Name;
public readonly string Palette;
public readonly string Race;
public readonly bool OwnsWorld = false;
public readonly bool NonCombatant = false;
public PlayerReference(MiniYaml my)
{
FieldLoader.Load(this, my);
}
public PlayerReference(string name, string palette, string race, bool ownsworld, bool noncombatant)
{
Name = name;
Palette = palette;
Race = race;
OwnsWorld = ownsworld;
NonCombatant = noncombatant;
}
}
}

View File

@@ -1,69 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System;
namespace OpenRA.FileFormats
{
public class TerrainColorSet
{
public readonly Dictionary<TerrainType, Color> colors = new Dictionary<TerrainType, Color>();
string NextLine( StreamReader reader )
{
string ret;
do
{
ret = reader.ReadLine();
if( ret == null )
return null;
ret = ret.Trim();
}
while( ret.Length == 0 || ret[ 0 ] == ';' );
return ret;
}
public TerrainColorSet( string colorFile )
{
StreamReader file = new StreamReader( FileSystem.Open(colorFile) );
while( true )
{
string line = NextLine( file );
if( line == null )
break;
string[] kv = line.Split('=');
TerrainType key = (TerrainType)Enum.Parse(typeof(TerrainType),kv[0]);
string[] entries = kv[1].Split(',');
Color val = Color.FromArgb(int.Parse(entries[0]),int.Parse(entries[1]),int.Parse(entries[2]));
colors.Add(key,val);
}
file.Close();
}
public Color ColorForTerrainType(TerrainType type)
{
return colors[type];
}
}
}

View File

@@ -21,74 +21,87 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Drawing;
namespace OpenRA.FileFormats
{
public class TerrainTypeInfo
{
public string Type;
public bool Buildable = true;
public bool AcceptSmudge = true;
public bool IsWater = false;
public Color Color;
public TerrainTypeInfo(MiniYaml my)
{
FieldLoader.Load(this, my);
}
}
public class TileTemplate
{
public ushort Id;
public string Image;
public int2 Size;
public bool PickAny;
public Dictionary<byte, string> Tiles = new Dictionary<byte, string>();
static List<string> fields = new List<string>() {"Id", "Image", "Size", "PickAny"};
public TileTemplate(Dictionary<string,MiniYaml> my)
{
FieldLoader.LoadFields(this, my, fields);
foreach (var tt in my["Tiles"].Nodes)
Tiles.Add(byte.Parse(tt.Key), tt.Value.Value);
}
}
public class TileSet
{
public readonly Dictionary<ushort, Terrain> tiles = new Dictionary<ushort, Terrain>();
public readonly Walkability Walkability;
public readonly Dictionary<ushort, TileTemplate> walk
= new Dictionary<ushort, TileTemplate>();
string NextLine( StreamReader reader )
public readonly string Name;
public readonly string Id;
public readonly string[] Extensions;
public readonly Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
public readonly Dictionary<ushort, Terrain> Tiles = new Dictionary<ushort, Terrain>();
public readonly Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
public TileSet( string filepath )
{
string ret;
do
var yaml = MiniYaml.FromFile(filepath);
// General info
FieldLoader.Load(this, yaml["General"]);
// TerrainTypes
foreach (var tt in yaml["Terrain"].Nodes)
{
ret = reader.ReadLine();
if( ret == null )
return null;
ret = ret.Trim();
var t = new TerrainTypeInfo(tt.Value);
Terrain.Add(t.Type, t);
}
while( ret.Length == 0 || ret[ 0 ] == ';' );
return ret;
}
public TileSet( string tilesetFile, string templatesFile, string suffix )
{
Walkability = new Walkability(templatesFile);
char tileSetChar = char.ToUpperInvariant( suffix[ 0 ] );
StreamReader tileIdFile = new StreamReader( FileSystem.Open(tilesetFile) );
while( true )
// Templates
foreach (var tt in yaml["Templates"].Nodes)
{
string tileSetStr = NextLine( tileIdFile );
string countStr = NextLine( tileIdFile );
string startStr = NextLine( tileIdFile );
string pattern = NextLine( tileIdFile );
if( tileSetStr == null || countStr == null || startStr == null || pattern == null )
break;
if( tileSetStr.IndexOf( tileSetChar.ToString() ) == -1 )
continue;
int count = int.Parse( countStr );
int start = int.Parse( startStr, NumberStyles.HexNumber );
for( int i = 0 ; i < count ; i++ )
var t = new TileTemplate(tt.Value.Nodes);
Templates.Add(t.Id, t);
}
}
public void LoadTiles()
{
foreach (var t in Templates)
using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
{
string tilename = string.Format(pattern, i + 1);
if (!walk.ContainsKey((ushort)(start + i)))
walk.Add((ushort)(start + i), Walkability.GetTileTemplate(tilename));
using( Stream s = FileSystem.Open( tilename + "." + suffix ) )
{
if( !tiles.ContainsKey( (ushort)( start + i ) ) )
tiles.Add( (ushort)( start + i ), new Terrain( s ) );
}
if( !Tiles.ContainsKey( t.Key ) )
Tiles.Add( t.Key, new Terrain( s ) );
}
}
tileIdFile.Close();
}
public byte[] GetBytes(TileReference<ushort,byte> r)
{
Terrain tile;
if( tiles.TryGetValue( r.type, out tile ) )
if( Tiles.TryGetValue( r.type, out tile ) )
return tile.TileBitmapBytes[ r.image ];
byte[] missingTile = new byte[ 24 * 24 ];
@@ -98,12 +111,12 @@ namespace OpenRA.FileFormats
return missingTile;
}
public TerrainType GetTerrainType( TileReference<ushort, byte> r )
public string GetTerrainType(TileReference<ushort, byte> r)
{
var tt = walk[ r.type ].TerrainType;
TerrainType ret;
if( !tt.TryGetValue( r.image, out ret ) )
return 0;// Default zero (walkable)
var tt = Templates[r.type].Tiles;
string ret;
if (!tt.TryGetValue(r.image, out ret))
return "Clear"; // Default walkable
return ret;
}
}

View File

@@ -1,89 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using System;
namespace OpenRA.FileFormats
{
public enum TerrainType : byte
{
Clear = 0,
Water = 1,
Road = 2,
Rock = 3,
Tree = 4,
River = 5,
Rough = 6,
Wall = 7,
Beach = 8,
Ore = 9,
Special = 10,
}
public class TileTemplate
{
public int Index; // not valid for `interior` stuff. only used for bridges.
public string Name;
public int2 Size;
public string Bridge;
public float HP;
public Dictionary<int, TerrainType> TerrainType = new Dictionary<int, TerrainType>();
}
public class Walkability
{
Dictionary<string, TileTemplate> templates
= new Dictionary<string,TileTemplate>();
public Walkability(string templatesFile)
{
var file = new IniFile( FileSystem.Open( templatesFile ) );
foreach (var section in file.Sections)
{
var tile = new TileTemplate
{
Size = new int2(
int.Parse(section.GetValue("width", "0")),
int.Parse(section.GetValue("height", "0"))),
TerrainType = section
.Where(p => p.Key.StartsWith("tiletype"))
.ToDictionary(
p => int.Parse(p.Key.Substring(8)),
p => (TerrainType)Enum.Parse(typeof(TerrainType),p.Value)),
Name = section.GetValue("Name", null).ToLowerInvariant(),
Bridge = section.GetValue("bridge", null),
HP = float.Parse(section.GetValue("hp", "0"))
};
tile.Index = -1;
int.TryParse(section.Name.Substring(3), out tile.Index);
templates[tile.Name] = tile;
}
}
public TileTemplate GetTileTemplate(string terrainName)
{
return templates[terrainName];
}
}
}

View File

@@ -19,7 +19,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<OutputPath>..\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
@@ -80,13 +80,10 @@
<Compile Include="Map\ActorReference.cs" />
<Compile Include="Map\Map.cs" />
<Compile Include="Map\TileReference.cs" />
<Compile Include="Map\Walkability.cs" />
<Compile Include="Map\Terrain.cs" />
<Compile Include="Primitives\Cache.cs" />
<Compile Include="Primitives\float2.cs" />
<Compile Include="Primitives\Pair.cs" />
<Compile Include="Map\TerrainColorSet.cs" />
<Compile Include="Primitives\Tuple.cs" />
<Compile Include="Map\TileSet.cs" />
<Compile Include="Primitives\PriorityQueue.cs" />
<Compile Include="Primitives\Lazy.cs" />
@@ -103,6 +100,7 @@
<Compile Include="Primitives\int2.cs" />
<Compile Include="Map\MapStub.cs" />
<Compile Include="Map\SmudgeReference.cs" />
<Compile Include="Map\PlayerReference.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

@@ -80,8 +80,6 @@ namespace OpenRA.FileFormats
ushort numFiles = reader2.ReadUInt16();
uint datasize = reader2.ReadUInt32();
Console.WriteLine("{0} files, {1} kb", numFiles, datasize >> 10);
s.Position = headerStart;
reader = new BinaryReader(s);

View File

@@ -61,7 +61,7 @@ namespace OpenRA.FileFormats
public readonly string[]
Folders, Packages, Rules,
Sequences, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Terrain;
Weapons, Voices, Music, TileSets;
public readonly string ShellmapUid;
@@ -80,11 +80,15 @@ namespace OpenRA.FileFormats
ChromeLayout = YamlList(yaml, "ChromeLayout");
Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices");
Terrain = YamlList(yaml, "Terrain");
Music = YamlList(yaml, "Music");
TileSets = YamlList(yaml, "TileSets");
ShellmapUid = yaml["ShellmapUid"].Value;
}
static string[] YamlList(Dictionary<string, MiniYaml> ys, string key) { return ys[key].Nodes.Keys.ToArray(); }
static string[] YamlList(Dictionary<string, MiniYaml> ys, string key)
{
return ys.ContainsKey(key) ? ys[key].Nodes.Keys.ToArray() : new string[] { };
}
}
}

View File

@@ -20,21 +20,87 @@
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO.Compression;
using System.Net;
namespace OpenRA
{
public struct ChannelInfo
{
public bool Upload;
public string Filename;
public StreamWriter Writer;
public bool Diff;
}
public static class Log
{
static StreamWriter writer = File.CreateText(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "openra.log.txt");
public static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar;
static Dictionary<string, ChannelInfo> channels = new Dictionary<string,ChannelInfo>();
static Log()
{
writer.AutoFlush = true;
AddChannel("debug", "openra.log.txt", false, false);
}
public static void Write(string format, params object[] args)
public static void AddChannel(string channelName, string filename, bool upload, bool diff)
{
writer.WriteLine(format, args);
if (channels.ContainsKey(channelName)) return;
/* HACK: avoid sharing violations if running multiple instances */
StreamWriter writer = null;
while (writer == null)
{
try
{
writer = File.CreateText(LogPathPrefix + filename);
}
catch(IOException e){ filename = new Random().Next().ToString() + filename; }
}
writer.AutoFlush = true;
channels.Add(channelName, new ChannelInfo() { Upload = upload, Filename = filename, Writer = writer, Diff = diff });
}
public static void Write(string channel, string format, params object[] args)
{
ChannelInfo info;
if (!channels.TryGetValue(channel, out info))
throw new Exception("Tried logging to non-existant channel " + channel);
info.Writer.WriteLine(format, args);
}
public static void Upload(int gameId)
{
foreach (var kvp in channels.Where(x => x.Value.Upload))
{
kvp.Value.Writer.Close();
var logfile = File.OpenRead(Log.LogPathPrefix + kvp.Value.Filename);
byte[] fileContents = logfile.ReadAllBytes();
var ms = new MemoryStream();
using (var gzip = new GZipStream(ms, CompressionMode.Compress, true))
gzip.Write(fileContents, 0, fileContents.Length);
ms.Position = 0;
byte[] buffer = ms.ReadAllBytes();
WebRequest request = WebRequest.Create("http://open-ra.org/logs/upload.php");
request.ContentType = "application/x-gzip";
request.ContentLength = buffer.Length;
request.Method = "POST";
request.Headers.Add("Game-ID", gameId.ToString());
request.Headers.Add("Channel", kvp.Key);
// request.Headers.Add("Diff", kvp.Value.Diff ? "1" : "0");
using (var requestStream = request.GetRequestStream())
requestStream.Write(buffer, 0, buffer.Length);
//var response = (HttpWebResponse)request.GetResponse();
}
}
}
}

View File

@@ -28,7 +28,9 @@ namespace OpenRA.Support
public static void Time( string message )
{
var time = sw.ElapsedTime();
Log.Write( message, time - lastTime );
var dt = time - lastTime;
if( dt > 0.0001 )
Log.Write("perf", message, dt );
lastTime = time;
}
}

View File

@@ -1,139 +1,53 @@
//
// System.Random.cs
//
// Authors:
// Bob Smith (bob@thestuff.net)
// Ben Maurer (bmaurer@users.sourceforge.net)
//
// (C) 2001 Bob Smith. http://www.thestuff.net
// (C) 2003 Ben Maurer
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace OpenRA.Thirdparty
{
[Serializable]
// quick & dirty Mersenne Twister [MT19937] implementation
public class Random
{
const int MBIG = int.MaxValue;
const int MSEED = 161803398;
const int MZ = 0;
uint[] mt = new uint[624];
int index = 0;
int inext, inextp;
int [] SeedArray = new int [56];
public Random() : this(Environment.TickCount) { }
public Random ()
: this (Environment.TickCount)
public Random(int seed)
{
mt[0] = (uint)seed;
for (var i = 1u; i < mt.Length; i++)
mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i;
}
public Random (int Seed)
public int Next()
{
int ii;
int mj, mk;
if (index == 0) Generate();
// Numerical Recipes in C online @ http://www.library.cornell.edu/nr/bookcpdf/c7-1.pdf
mj = MSEED - Math.Abs (Seed);
SeedArray [55] = mj;
mk = 1;
for (int i = 1; i < 55; i++) { // [1, 55] is special (Knuth)
ii = (21 * i) % 55;
SeedArray [ii] = mk;
mk = mj - mk;
if (mk < 0)
mk += MBIG;
mj = SeedArray [ii];
}
for (int k = 1; k < 5; k++) {
for (int i = 1; i < 56; i++) {
SeedArray [i] -= SeedArray [1 + (i + 30) % 55];
if (SeedArray [i] < 0)
SeedArray [i] += MBIG;
var y = mt[index];
y ^= (y >> 11);
y ^= ((y << 7) & 2636928640);
y ^= ((y << 15) & 4022730752);
y ^= y >> 18;
index = (index + 1) % 624;
return (int)(y % int.MaxValue);
}
public int Next(int low, int high) { return low + Next() % (high - low); }
public int Next(int high) { return Next() % high; }
public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); }
void Generate()
{
unchecked
{
for (var i = 0u; i < mt.Length; i++)
{
var y = (mt[i] & 0x80000000) | (mt[(i + 1) % 624] & 0x7fffffff);
mt[i] = mt[(i + 397u) % 624u] ^ (y >> 1);
if ((y & 1) == 1)
mt[i] = (mt[i] ^ 2567483615);
}
}
inext = 0;
inextp = 31;
}
protected virtual double Sample ()
{
int retVal;
if (++inext >= 56) inext = 1;
if (++inextp >= 56) inextp = 1;
retVal = SeedArray [inext] - SeedArray [inextp];
if (retVal < 0)
retVal += MBIG;
SeedArray [inext] = retVal;
return retVal * (1.0 / MBIG);
}
public virtual int Next ()
{
return (int)(Sample () * int.MaxValue);
}
public virtual int Next (int maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException("Max value is less then min value.");
return (int)(Sample () * maxValue);
}
public virtual int Next (int minValue, int maxValue)
{
if (minValue > maxValue)
throw new ArgumentOutOfRangeException("Min value is greater then max value.");
uint diff = (uint)(maxValue - minValue);
if (diff == 0)
return minValue;
int result = (int)(Sample () * diff + minValue);
return ((result != maxValue) ? result : (result - 1));
}
public virtual void NextBytes (byte [] buffer)
{
if (buffer == null)
throw new ArgumentNullException ("buffer");
for (int i = 0; i < buffer.Length; i++) {
buffer [i] = (byte)(Sample () * (byte.MaxValue + 1));
}
}
public virtual double NextDouble ()
{
return this.Sample ();
}
}
}

View File

@@ -1,247 +1,273 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA
{
public class Actor
{
[Sync]
public readonly TypeDictionary traits = new TypeDictionary();
public readonly ActorInfo Info;
public readonly World World;
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA
{
public class Actor
{
[Sync]
public readonly TypeDictionary traits = new TypeDictionary();
public readonly ActorInfo Info;
public readonly World World;
public readonly uint ActorID;
[Sync]
public int2 Location;
[Sync]
public Player Owner;
[Sync]
public int Health;
public int2 Location { get { return traits.Get<IOccupySpace>().TopLeft; } }
[Sync]
public Player Owner;
[Sync]
public int Health;
IActivity currentActivity;
public Actor(World world, string name, int2 location, Player owner)
public Group Group;
public Actor(World world, string name, int2 location, Player owner)
{
World = world;
ActorID = world.NextAID();
Location = location;
CenterLocation = Traits.Util.CenterOfCell(Location);
Owner = owner;
if (name != null)
{
if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
Info = Rules.Info[name.ToLowerInvariant()];
Health = this.GetMaxHP();
foreach (var trait in Info.TraitsInConstructOrder())
traits.Add(trait.Create(this));
World = world;
ActorID = world.NextAID();
Owner = owner;
var init = new ActorInitializer( this, location );
if (name != null)
{
if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
Info = Rules.Info[name.ToLowerInvariant()];
Health = this.GetMaxHP();
foreach (var trait in Info.TraitsInConstructOrder())
traits.Add(trait.Create(init));
}
Size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null)
return new float2(si.Bounds[0], si.Bounds[1]);
if( CenterLocation == float2.Zero && traits.Contains<IOccupySpace>() )
CenterLocation = Traits.Util.CenterOfCell(Location);
// auto size from render
var firstSprite = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size;
});
}
public void Tick()
{
var wasIdle = currentActivity is Idle;
while (currentActivity != null)
{
var a = currentActivity;
currentActivity = a.Tick(this) ?? new Idle();
if (a == currentActivity) break;
if (currentActivity is Idle)
{
if (!wasIdle)
foreach (var ni in traits.WithInterface<INotifyIdle>())
ni.Idle(this);
break;
}
}
}
public bool IsIdle
{
get { return currentActivity == null || currentActivity is Idle; }
}
public float2 CenterLocation;
Lazy<float2> Size;
public IEnumerable<Renderable> Render()
{
var mods = traits.WithInterface<IRenderModifier>();
var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
public Order Order( int2 xy, MouseInput mi )
{
if (Owner != World.LocalPlayer)
return null;
if (!World.Map.IsInMap(xy.X, xy.Y))
return null;
var underCursor = World.FindUnitsAtMouse(mi.Location).FirstOrDefault();
if (underCursor != null && !underCursor.traits.Contains<Selectable>())
underCursor = null;
return traits.WithInterface<IIssueOrder>()
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
public RectangleF GetBounds(bool useAltitude)
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
var size = Size.Value;
var loc = CenterLocation - 0.5f * size;
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
loc += new float2(si.Bounds[2], si.Bounds[3]);
if (useAltitude)
{
var unit = traits.GetOrDefault<Unit>();
if (unit != null) loc -= new float2(0, unit.Altitude);
}
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
}
public bool IsDead { get { return Health <= 0; } }
public bool IsInWorld { get; set; }
public bool RemoveOnDeath = true;
public DamageState GetDamageState()
{
if (Health <= 0)
return DamageState.Dead;
if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
return DamageState.Half;
return DamageState.Normal;
}
public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
{
if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var oldState = GetDamageState();
/* apply the damage modifiers, if we have any. */
damage = (int)traits.WithInterface<IDamageModifier>().Aggregate(
(float)damage, (a, t) => t.GetDamageModifier() * a);
Health -= damage;
if (Health <= 0)
{
Health = 0;
if (attacker.Owner != null)
attacker.Owner.Kills++;
if (RemoveOnDeath)
Size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null)
return new float2(si.Bounds[0], si.Bounds[1]);
// auto size from render
var firstSprite = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size;
});
}
public void Tick()
{
var wasIdle = currentActivity is Idle;
while (currentActivity != null)
{
var a = currentActivity;
currentActivity = a.Tick(this) ?? new Idle();
if (a == currentActivity) break;
if (currentActivity is Idle)
{
if (!wasIdle)
foreach (var ni in traits.WithInterface<INotifyIdle>())
ni.Idle(this);
break;
}
}
}
public bool IsIdle
{
get { return currentActivity == null || currentActivity is Idle; }
}
public float2 CenterLocation;
OpenRA.FileFormats.Lazy<float2> Size;
public IEnumerable<Renderable> Render()
{
var mods = traits.WithInterface<IRenderModifier>();
var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
public Order Order( int2 xy, MouseInput mi )
{
if (Owner != World.LocalPlayer)
return null;
if (!World.Map.IsInMap(xy.X, xy.Y))
return null;
var underCursor = World.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
.OrderByDescending(a => a.Info.Traits.Get<SelectableInfo>().Priority)
.FirstOrDefault();
return traits.WithInterface<IIssueOrder>()
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
public RectangleF GetBounds(bool useAltitude)
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
var size = Size.Value;
var loc = CenterLocation - 0.5f * size;
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
loc += new float2(si.Bounds[2], si.Bounds[3]);
if (useAltitude)
{
var unit = traits.GetOrDefault<Unit>();
if (unit != null) loc -= new float2(0, unit.Altitude);
}
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
}
public bool IsDead { get { return Health <= 0; } }
public bool IsInWorld { get; set; }
public bool RemoveOnDeath = true;
public DamageState GetDamageState()
{
if (Health <= 0)
return DamageState.Dead;
if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
return DamageState.Half;
return DamageState.Normal;
}
public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
{
if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var rawDamage = damage;
var oldState = GetDamageState();
/* apply the damage modifiers, if we have any. */
var modifier = (float)traits.WithInterface<IDamageModifier>()
.Select(t => t.GetDamageModifier(warhead)).Product();
damage = (int)(damage * modifier);
Health -= damage;
if (Health <= 0)
{
Health = 0;
attacker.Owner.Kills++;
Owner.Deaths++;
if (RemoveOnDeath)
World.AddFrameEndTask(w => w.Remove(this));
}
var maxHP = this.GetMaxHP();
if (Health > maxHP) Health = maxHP;
var newState = GetDamageState();
foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, new AttackInfo
{
Attacker = attacker,
Damage = damage,
DamageState = newState,
DamageStateChanged = newState != oldState,
Warhead = warhead
});
}
public void QueueActivity( IActivity nextActivity )
{
if( currentActivity == null )
{
currentActivity = nextActivity;
return;
}
var act = currentActivity;
while( act.NextActivity != null )
{
act = act.NextActivity;
}
act.NextActivity = nextActivity;
}
public void CancelActivity()
{
if( currentActivity != null )
currentActivity.Cancel( this );
}
// For pathdebug, et al
public IActivity GetCurrentActivity()
{
return currentActivity;
}
public override int GetHashCode()
{
return (int)ActorID;
}
public override bool Equals( object obj )
{
var o = obj as Actor;
return ( o != null && o.ActorID == ActorID );
}
Log.Write("debug", "{0} #{1} killed by {2} #{3}", Info.Name, ActorID, attacker.Info.Name, attacker.ActorID);
}
var maxHP = this.GetMaxHP();
if (Health > maxHP) Health = maxHP;
// Log.Write("debug", "InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}",
// attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier);
var newState = GetDamageState();
foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, new AttackInfo
{
Attacker = attacker,
Damage = damage,
DamageState = newState,
DamageStateChanged = newState != oldState,
Warhead = warhead
});
}
public void QueueActivity( IActivity nextActivity )
{
if( currentActivity == null )
{
currentActivity = nextActivity;
return;
}
var act = currentActivity;
while( act.NextActivity != null )
{
act = act.NextActivity;
}
act.NextActivity = nextActivity;
}
public void CancelActivity()
{
if( currentActivity != null )
currentActivity.Cancel( this );
}
// For pathdebug, et al
public IActivity GetCurrentActivity()
{
return currentActivity;
}
public override int GetHashCode()
{
return (int)ActorID;
}
public override bool Equals( object obj )
{
var o = obj as Actor;
return ( o != null && o.ActorID == ActorID );
}
}
}
public class ActorInitializer
{
public readonly Actor self;
public World world { get { return self.World; } }
public readonly int2 location;
public ActorInitializer( Actor actor, int2 location )
{
this.self = actor;
this.location = location;
}
}
}

View File

@@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.Text;
namespace OpenRA
{
@@ -29,14 +30,15 @@ namespace OpenRA
{
const int logLength = 10;
public List<Tuple<Color, string, string>> recentLines = new List<Tuple<Color, string, string>>();
public List<ChatLine> recentLines = new List<ChatLine>();
public string typing = "";
public bool isChatting = true;
public bool isTeamChat = false;
public void Toggle()
{
if( isChatting && typing.Length > 0 )
Game.IssueOrder( Order.Chat( typing ) );
Game.IssueOrder( isTeamChat ? Order.TeamChat( typing ) : Order.Chat( typing ) );
typing = "";
if( Game.orderManager.GameStarted )
@@ -63,15 +65,39 @@ namespace OpenRA
public void AddLine(Session.Client p, string text)
{
AddLine(Player.PlayerColors( Game.world )[p.PaletteIndex].c, p.Name, text);
AddLine(Game.world.PlayerColors()[p.PaletteIndex].Color, p.Name, text);
}
public void AddLine(Color c, string from, string text)
{
recentLines.Add(Tuple.New(c, from, text));
var sizeOwner = Game.chrome.renderer.RegularFont.Measure(from);
var sizeText = Game.chrome.renderer.RegularFont.Measure(text);
if (sizeOwner.X + sizeText.X + 10 <= Chrome.ChatWidth)
recentLines.Add(new ChatLine { Color = c, Owner = from, Text = text });
else
{
StringBuilder sb = new StringBuilder();
foreach (var w in text.Split(' '))
{
if ( Game.chrome.renderer.RegularFont.Measure(sb.ToString() + ' ' + w).X > Chrome.ChatWidth )
{
recentLines.Add(new ChatLine { Color = c, Owner = from, Text = sb.ToString() } );
sb = new StringBuilder();
sb.Append(w);
}
else
sb.Append( ' ' + w);
}
if (sb.Length != 0)
recentLines.Add(new ChatLine { Color = c, Owner = from, Text = sb.ToString() } );
}
var eva = Rules.Info["world"].Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.ChatBeep);
while (recentLines.Count > logLength) recentLines.RemoveAt(0);
}
}
class ChatLine { public Color Color = Color.White; public string Owner, Text; public bool wrapped = false; }
}

View File

@@ -31,6 +31,9 @@ namespace OpenRA
{
class Chrome : IHandleInput
{
//todo: remove when have a real chat widget
public static int ChatWidth = 760;
public readonly Renderer renderer;
public readonly LineRenderer lineRenderer;
@@ -144,8 +147,7 @@ namespace OpenRA
new int2(mapContainer.Left + mapContainer.Width / 2, y), Color.White);
y += 20;
var theaterInfo = Rules.Info["world"].Traits.WithInterface<TheaterInfo>().FirstOrDefault(t => t.Theater == currentMap.Tileset);
DrawCentered("Theater: {0}".F(theaterInfo.Name),
DrawCentered("Theater: {0}".F(Rules.TileSets[currentMap.Tileset].Name),
new int2(mapContainer.Left + mapContainer.Width / 2, y), Color.White);
y += 20;
DrawCentered("Spawnpoints: {0}".F(currentMap.PlayerCount),
@@ -155,7 +157,7 @@ namespace OpenRA
}
public void DrawWidgets(World world) { rootWidget.Draw(world); shpRenderer.Flush(); rgbaRenderer.Flush(); }
public void DrawWidgets(World world) { rootWidget.Draw(world); shpRenderer.Flush(); rgbaRenderer.Flush(); lineRenderer.Flush(); }
public void DrawLobby()
{
@@ -170,8 +172,8 @@ namespace OpenRA
var h = 600;
var r = new Rectangle( (Game.viewport.Width - w) / 2, (Game.viewport.Height - h) / 2, w, h );
var typingBox = new Rectangle(r.Left + 20, r.Bottom - 47, r.Width - 40, 27);
var chatBox = new Rectangle(r.Left + 20, r.Bottom - 269, r.Width - 40, 220);
var typingBox = new Rectangle(r.Left + 20, r.Bottom - 77, r.Width - 40, 27);
var chatBox = new Rectangle(r.Left + 20, r.Bottom - 269, r.Width - 40, 190);
DrawDialogBackground(typingBox, "dialog2");
DrawDialogBackground(chatBox, "dialog3");
@@ -188,11 +190,13 @@ namespace OpenRA
void DrawChat(Rectangle typingArea, Rectangle chatLogArea)
{
var chatpos = new int2(chatLogArea.X + 10, chatLogArea.Bottom - 6);
ChatWidth = chatLogArea.Width - 10;
renderer.Device.EnableScissor(typingArea.Left, typingArea.Top, typingArea.Width, typingArea.Height);
if (Game.chat.isChatting)
RenderChatLine(Tuple.New(Color.White, "Chat:", Game.chat.typing),
RenderChatLine(new ChatLine { Owner = Game.chat.isTeamChat ? "TeamChat:" : "Chat:", Text = Game.chat.typing },
new int2(typingArea.X + 10, typingArea.Y + 6));
rgbaRenderer.Flush();
@@ -209,11 +213,11 @@ namespace OpenRA
renderer.Device.DisableScissor();
}
void RenderChatLine(Tuple<Color, string, string> line, int2 p)
void RenderChatLine(ChatLine line, int2 p)
{
var size = renderer.RegularFont.Measure(line.b);
renderer.RegularFont.DrawText(line.b, p, line.a);
renderer.RegularFont.DrawText(line.c, p + new int2(size.X + 10, 0), Color.White);
var size = renderer.RegularFont.Measure(line.Owner);
renderer.RegularFont.DrawText(line.Owner, p, line.Color);
renderer.RegularFont.DrawText(line.Text, p + new int2(size.X + 10, 0), Color.White);
}
public int ticksSinceLastMove = 0;

View File

@@ -40,25 +40,39 @@ namespace OpenRA
return null;
}
public static void DoImpact(WarheadInfo warhead, ProjectileArgs args, int2 visualLocation)
public static void DoImpact(WarheadInfo warhead, ProjectileArgs args)
{
var world = args.firedBy.World;
var targetTile = ((1f / Game.CellSize) * args.dest.ToFloat2()).ToInt2();
var isWater = world.GetTerrainType(targetTile) == TerrainType.Water;
var targetTile = Util.CellContaining(args.dest);
if (warhead.Explosion != 0)
if (!world.Map.IsInMap(targetTile))
return;
var isWater = world.GetTerrainInfo(targetTile).IsWater;
var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion;
if (explosionType != null)
world.AddFrameEndTask(
w => w.Add(new Explosion(w, visualLocation, warhead.Explosion, isWater)));
w => w.Add(new Explosion(w, args.dest, explosionType, isWater)));
Sound.Play(GetImpactSound(warhead, isWater));
Sound.Play(GetImpactSound(warhead, isWater), args.dest);
if (warhead.SmudgeType != null)
{
var smudgeLayer = world.WorldActor.traits.WithInterface<SmudgeLayer>().FirstOrDefault(x => x.Info.Type == warhead.SmudgeType);
var smudgeLayer = world.WorldActor.traits.WithInterface<SmudgeLayer>()
.FirstOrDefault(x => x.Info.Type == warhead.SmudgeType);
if (smudgeLayer == null)
throw new NotImplementedException("Unknown smudge type `{0}`".F(warhead.SmudgeType));
if (!isWater)
if (warhead.Size[0] > 0)
{
var smudgeCells = world.FindTilesInCircle(targetTile, warhead.Size[0])
.Except(world.FindTilesInCircle(targetTile, warhead.Size[1]));
foreach (var sc in smudgeCells)
smudgeLayer.AddSmudge(sc);
}
else
smudgeLayer.AddSmudge(targetTile);
}
@@ -78,8 +92,10 @@ namespace OpenRA
var hitActors = world.FindUnitsInCircle(args.dest, maxSpread);
foreach (var victim in hitActors)
victim.InflictDamage(args.firedBy,
(int)GetDamageToInflict(victim, args, warhead, firepowerModifier), warhead);
{
var damage = (int)GetDamageToInflict(victim, args, warhead, firepowerModifier);
victim.InflictDamage(args.firedBy, damage, warhead);
}
} break;
case DamageModel.PerCell:
@@ -93,11 +109,11 @@ namespace OpenRA
}
}
public static void DoImpacts(ProjectileArgs args, int2 visualLocation)
public static void DoImpacts(ProjectileArgs args)
{
foreach (var warhead in args.weapon.Warheads)
{
Action a = () => DoImpact(warhead, args, visualLocation);
Action a = () => DoImpact(warhead, args);
if (warhead.Delay > 0)
args.firedBy.World.AddFrameEndTask(
w => w.Add(new DelayedAction(warhead.Delay, a)));
@@ -120,7 +136,21 @@ namespace OpenRA
facing = 0
};
DoImpacts(args, location);
DoImpacts(args);
}
static readonly float[] falloff =
{
1f, 0.3678795f, 0.1353353f, 0.04978707f,
0.01831564f, 0.006737947f, 0.002478752f, 0.000911882f
};
static float GetDamageFalloff(float x)
{
var u = (int)x;
if (u >= falloff.Length - 1) return 0;
var t = x - u;
return (falloff[u] * (1 - t)) + (falloff[u + 1] * t);
}
static float GetDamageToInflict(Actor target, ProjectileArgs args, WarheadInfo warhead, float modifier)
@@ -130,10 +160,12 @@ namespace OpenRA
var selectable = target.Info.Traits.GetOrDefault<SelectableInfo>();
var radius = selectable != null ? selectable.Radius : 0;
var distance = Math.Max(0, (target.CenterLocation - args.dest).Length - radius);
var rawDamage = warhead.Damage * modifier * (float)Math.Exp(-distance / warhead.Spread);
var multiplier = warhead.EffectivenessAgainst(target.Info.Traits.Get<OwnedActorInfo>().Armor);
return rawDamage * multiplier;
var distance = (int)Math.Max(0, (target.CenterLocation - args.dest).Length - radius);
var falloff = (float)GetDamageFalloff(distance / warhead.Spread);
var rawDamage = (float)(warhead.Damage * modifier * falloff);
var multiplier = (float)warhead.EffectivenessAgainst(target.Info.Traits.Get<OwnedActorInfo>().Armor);
return (float)(rawDamage * multiplier);
}
public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target)

View File

@@ -48,6 +48,11 @@ namespace OpenRA
}
}
static bool HasVoice(Actor a)
{
return a.Info.Traits.Contains<SelectableInfo>() && a.Info.Traits.Get<SelectableInfo>().Voice != null;
}
void ApplyOrders(World world, float2 xy, MouseInput mi)
{
if (orderGenerator == null) return;
@@ -56,15 +61,14 @@ namespace OpenRA
Game.orderManager.IssueOrders( orders );
var voicedActor = orders.Select(o => o.Subject)
.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.traits.Contains<Unit>());
.FirstOrDefault(a => a.Owner == world.LocalPlayer && HasVoice(a));
var isMove = orders.Any(o => o.OrderString == "Move");
var isAttack = orders.Any( o => o.OrderString == "Attack" );
if (voicedActor != null)
{
if(voicedActor.traits.GetOrDefault<IMovement>().CanEnterCell(xy.ToInt2()))
if(voicedActor.traits.GetOrDefault<IMove>().CanEnterCell(xy.ToInt2()))
Sound.PlayVoice(isAttack ? "Attack" : "Move", voicedActor);
if (isMove)
@@ -79,8 +83,7 @@ namespace OpenRA
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
{
if (!(orderGenerator is PlaceBuildingOrderGenerator))
dragStart = dragEnd = xy;
dragStart = dragEnd = xy;
ApplyOrders(world, xy, mi);
}
@@ -146,5 +149,23 @@ namespace OpenRA
public void SetModifiers(Modifiers mods) { modifiers = mods; }
public Modifiers GetModifiers() { return modifiers; }
public void GotoNextBase()
{
var bases = Game.world.Queries.OwnedBy[Game.world.LocalPlayer].WithTrait<BaseBuilding>().ToArray();
if (!bases.Any()) return;
var next = bases
.Select( b => b.Actor )
.SkipWhile(b => Game.controller.selection.Actors.Contains(b))
.Skip(1)
.FirstOrDefault();
if (next == null)
next = bases.Select(b => b.Actor).First();
Game.controller.selection.Combine(Game.world, new Actor[] { next }, false, true);
Game.viewport.Center(Game.controller.selection.Actors);
}
}
}

View File

@@ -19,6 +19,7 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -45,7 +46,6 @@ namespace OpenRA.Effects
{
readonly BulletInfo Info;
readonly ProjectileArgs Args;
readonly int2 VisualDest;
int t = 0;
Animation anim;
@@ -63,8 +63,6 @@ namespace OpenRA.Effects
Args.dest += (info.Inaccuracy * factor * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2();
}
VisualDest = Args.dest + (10 * Game.CosmeticRandom.Gauss2D(1)).ToInt2();
if (Info.Image != null)
{
anim = new Animation(Info.Image, () => Traits.Util.GetFacing(Args.dest - Args.src, 0));
@@ -78,22 +76,37 @@ namespace OpenRA.Effects
{
t += 40;
if (anim != null) anim.Tick();
if (t > TotalTime()) Explode( world );
if (Info.Trail != null)
{
var at = (float)t / TotalTime();
var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at);
var pos = float2.Lerp(Args.src, VisualDest, at)
- 0.5f * anim.Image.size - new float2(0, altitude);
var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude);
var highPos = (Info.High || Info.Arcing)
? (pos - new float2(0, (VisualDest - Args.src).Length * height * 4 * at * (1 - at)))
? (pos - new float2(0, (Args.dest - Args.src).Length * height * 4 * at * (1 - at)))
: pos;
world.AddFrameEndTask(w => w.Add(
new Smoke(w, highPos.ToInt2(), Info.Trail)));
}
if (!Info.High) // check for hitting a wall
{
var at = (float)t / TotalTime();
var pos = float2.Lerp(Args.src, Args.dest, at);
var cell = Traits.Util.CellContaining(pos);
if (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(cell).Any(
a => a.traits.Contains<IBlocksBullets>()))
{
Args.dest = pos.ToInt2();
Explode(world);
}
}
}
const float height = .1f;
@@ -105,15 +118,14 @@ namespace OpenRA.Effects
var at = (float)t / TotalTime();
var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at);
var pos = float2.Lerp( Args.src, VisualDest, at)
- 0.5f * anim.Image.size - new float2( 0, altitude );
var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude);
if (Info.High || Info.Arcing)
{
if (Info.Shadow)
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow");
var highPos = pos - new float2(0, (VisualDest - Args.src).Length * height * 4 * at * (1 - at));
var highPos = pos - new float2(0, (Args.dest - Args.src).Length * height * 4 * at * (1 - at));
yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, Args.firedBy.Owner.Palette);
}
@@ -126,7 +138,7 @@ namespace OpenRA.Effects
void Explode( World world )
{
world.AddFrameEndTask(w => w.Remove(this));
Combat.DoImpacts(Args, VisualDest - new int2(0, Args.destAltitude));
Combat.DoImpacts(Args);
}
}
}

View File

@@ -29,12 +29,11 @@ namespace OpenRA.Effects
Animation anim;
int2 pos;
public Explosion(World world, int2 pixelPos, int style, bool isWater)
public Explosion(World world, int2 pixelPos, string style, bool isWater)
{
this.pos = pixelPos;
var variantSuffix = isWater ? "w" : "";
anim = new Animation("explosion");
anim.PlayThen(style.ToString() + variantSuffix,
anim.PlayThen(style,
() => world.AddFrameEndTask(w => w.Remove(this)));
}

View File

@@ -54,7 +54,7 @@ namespace OpenRA.Effects
if (--altitude <= Args.destAltitude)
{
world.AddFrameEndTask(w => w.Remove(this));
Combat.DoImpacts(Args, Args.dest);
Combat.DoImpacts(Args);
}
anim.Tick();

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Effects
if (!doneDamage)
{
Combat.DoImpacts(args, args.dest);
Combat.DoImpacts(args);
doneDamage = true;
}
}

View File

@@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -109,6 +110,15 @@ namespace OpenRA.Effects
if (Info.RangeLimit != 0 && t > Info.RangeLimit * 40)
Explode(world);
if (!Info.High) // check for hitting a wall
{
var cell = Traits.Util.CellContaining(Pos);
if (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(cell).Any(
a => a.traits.Contains<IBlocksBullets>()))
Explode(world);
}
}
void Explode(World world)
@@ -116,7 +126,7 @@ namespace OpenRA.Effects
world.AddFrameEndTask(w => w.Remove(this));
Args.dest = Pos.ToInt2();
if (t > Info.Arm * 40) /* don't blow up in our launcher's face! */
Combat.DoImpacts(Args, Pos.ToInt2());
Combat.DoImpacts(Args);
}
public IEnumerable<Renderable> Render()

View File

@@ -18,10 +18,12 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
using OpenRA.GameRules;
namespace OpenRA.Effects
{
@@ -33,14 +35,21 @@ namespace OpenRA.Effects
class TeslaZap : IEffect
{
readonly ProjectileArgs Args;
readonly Sequence tesla;
int timeUntilRemove = 2; // # of frames
bool doneDamage = false;
const int numZaps = 3;
readonly List<Renderable> renderables = new List<Renderable>();
public TeslaZap(TeslaZapInfo info, ProjectileArgs args)
{
Args = args;
tesla = SequenceProvider.GetSequence("litning", "bright");
var bright = SequenceProvider.GetSequence("litning", "bright");
var dim = SequenceProvider.GetSequence("litning", "dim");
for (var n = 0; n < numZaps; n++)
renderables.AddRange(DrawZapWandering(args.src, args.dest, n == numZaps - 1 ? bright : dim));
}
public void Tick( World world )
@@ -51,69 +60,72 @@ namespace OpenRA.Effects
if (!doneDamage)
{
Combat.DoImpacts(Args, Args.dest);
Combat.DoImpacts(Args);
doneDamage = true;
}
}
public IEnumerable<Renderable> Render()
{
var from = Args.src;
var to = Args.dest;
public IEnumerable<Renderable> Render() { return renderables; }
if( from.X < to.X )
return DrawZap( from, to, tesla );
else if( from.X > to.X || from.Y > to.Y )
return DrawZap( to, from, tesla );
else
return DrawZap( from, to, tesla );
}
static IEnumerable<Renderable> DrawZap( int2 from, int2 to, Sequence tesla )
static IEnumerable<Renderable> DrawZapWandering(int2 from, int2 to, Sequence s)
{
int2 d = to - from;
if( d.X < 8 )
var z = float2.Zero; /* hack */
var dist = to - from;
var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X);
var renderables = new List<Renderable>();
if (Game.CosmeticRandom.Next(2) != 0)
{
var prev = new int2( 0, 0 );
var y = d.Y;
while( y >= prev.Y + 8 )
{
yield return new Renderable( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), "effect");
prev.Y += 8;
}
var p1 = from + (1 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
var p2 = from + (2 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
renderables.AddRange(DrawZap(from, p1, s, out p1));
renderables.AddRange(DrawZap(p1, p2, s, out p2));
renderables.AddRange(DrawZap(p2, to, s, out z));
}
else
{
var prev = new int2( 0, 0 );
for( int i = 1 ; i < d.X ; i += 8 )
{
var y = i * d.Y / d.X;
if( y <= prev.Y - 8 )
{
yield return new Renderable(tesla.GetSprite(3), (float2)(from + prev - new int2(8, 16)), "effect");
prev.Y -= 8;
while( y <= prev.Y - 8 )
{
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 16)), "effect");
prev.Y -= 8;
}
}
else if( y >= prev.Y + 8 )
{
yield return new Renderable(tesla.GetSprite(0), (float2)(from + prev - new int2(8, 8)), "effect");
prev.Y += 8;
while( y >= prev.Y + 8 )
{
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 8)), "effect");
prev.Y += 8;
}
}
else
yield return new Renderable(tesla.GetSprite(1), (float2)(from + prev - new int2(8, 8)), "effect");
var p1 = from + (1 / 2f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
prev.X += 8;
}
renderables.AddRange(DrawZap(from, p1, s, out p1));
renderables.AddRange(DrawZap(p1, to, s, out z));
}
return renderables;
}
static IEnumerable<Renderable> DrawZap(float2 from, float2 to, Sequence s, out float2 p)
{
var dist = to - from;
var q = new float2(-dist.Y, dist.X);
var c = -float2.Dot(from, q);
var rs = new List<Renderable>();
var z = from;
while ((to - z).X > 5 || (to - z).X < -5 || (to - z).Y > 5 || (to - z).Y < -5)
{
var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared )
.OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First();
rs.Add(new Renderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), "effect"));
z += new float2(step[0], step[1]);
}
p = z;
return rs;
}
static int[][] steps = new []
{
new int[] { 8, 8, -8, -8, 0 },
new int[] { -8, -8, -16, -16, 0 },
new int[] { 8, 0, -8, -8, 1 },
new int[] { -8, 0, -16, -8, 1 },
new int[] { 0, 8, -8, -8, 2 },
new int[] { 0, -8, -8, -16, 2 },
new int[] { -8, 8, -16, -8, 3 },
new int[] { 8, -8, -8, -16, 3 }
};
}
}

View File

@@ -23,6 +23,7 @@ using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Traits;
using OpenRA.Support;
namespace OpenRA
{
@@ -92,5 +93,19 @@ namespace OpenRA
var xs = ts.ToArray();
return xs[r.Next(xs.Length)];
}
public static void DoTimed<T>( this IEnumerable<T> e, Action<T> a, string text, double time )
{
var sw = new Stopwatch();
e.Do( x =>
{
var t = sw.ElapsedTime();
a( x );
var dt = sw.ElapsedTime() - t;
if( dt > time )
Log.Write("perf", text, x, dt * 1000);
} );
}
}
}

View File

@@ -1,38 +1,41 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Traits;
using Timer = OpenRA.Support.Timer;
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Widgets;
using Timer = OpenRA.Support.Timer;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
@@ -45,8 +48,8 @@ namespace OpenRA
internal static Viewport viewport;
public static Controller controller;
internal static Chrome chrome;
public static UserSettings Settings;
internal static UserSettings Settings;
internal static OrderManager orderManager;
public static bool skipMakeAnims = true;
@@ -56,11 +59,16 @@ namespace OpenRA
internal static Renderer renderer;
static int2 clientSize;
static string mapName;
internal static Session LobbyInfo = new Session();
public static Session LobbyInfo = new Session();
static bool packageChangePending;
static bool mapChangePending;
public static Pair<Assembly, string>[] ModAssemblies;
static Pair<Assembly, string>[] ModAssemblies;
static internal bool scrollUp = false;
static internal bool scrollDown = false;
static internal bool scrollLeft = false;
static internal bool scrollRight = false;
static void LoadModPackages(Manifest manifest)
{
FileSystem.UnmountAll();
@@ -68,12 +76,12 @@ namespace OpenRA
foreach (var dir in manifest.Folders) FileSystem.Mount(dir);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
Timer.Time("mount temporary packages: {0}");
}
static void LoadModAssemblies(Manifest m)
{
public static void LoadModAssemblies(Manifest m)
{
// All the core namespaces
var asms = typeof(Game).Assembly.GetNamespaces()
.Select(c => Pair.New(typeof(Game).Assembly, c))
@@ -101,11 +109,11 @@ namespace OpenRA
throw new InvalidOperationException("Cannot locate type: {0}".F(classname));
}
public static Dictionary<string,MapStub> AvailableMaps;
public static Dictionary<string, MapStub> AvailableMaps;
// TODO: Do this nicer
public static Dictionary<string, MapStub> FindMaps(string[] mods)
static Dictionary<string, MapStub> FindMaps(string[] mods)
{
Console.WriteLine("Finding maps");
foreach (var mod in mods)
@@ -117,108 +125,159 @@ namespace OpenRA
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
}
public static void ChangeMods()
static void ChangeMods()
{
Timer.Time( "----ChangeMods" );
Timer.Time("----ChangeMods");
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "manifest: {0}" );
Game.LoadModAssemblies(manifest);
Timer.Time("manifest: {0}");
LoadModAssemblies(manifest);
SheetBuilder.Initialize(renderer);
LoadModPackages(manifest);
Timer.Time( "load assemblies, packages: {0}" );
Game.packageChangePending = false;
Timer.Time("load assemblies, packages: {0}");
packageChangePending = false;
}
public static void ChangeMap(string mapName)
static void LoadMap(string mapName)
{
Game.mapName = mapName;
Game.mapChangePending = false;
}
public static void LoadMap(string mapName)
{
Timer.Time( "----LoadMap" );
Timer.Time("----LoadMap");
SheetBuilder.Initialize(renderer);
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "manifest: {0}" );
Timer.Time("manifest: {0}");
if (!Game.AvailableMaps.ContainsKey(mapName))
throw new InvalidDataException("Cannot find map with Uid {0}".F(mapName));
var map = new Map( Game.AvailableMaps[mapName].Package );
var map = new Map(Game.AvailableMaps[mapName].Package);
viewport = new Viewport(clientSize, map.TopLeft, map.BottomRight, renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
ChromeProvider.Initialize(manifest.Chrome);
Timer.Time( "viewport, ChromeProvider: {0}" );
world = new World(manifest,map);
Timer.Time( "world: {0}" );
SequenceProvider.Initialize(manifest.Sequences);
Timer.Time( "ChromeProv, SeqProv: {0}" );
Timer.Time("viewport, ChromeProvider: {0}");
world = new World(manifest, map);
Timer.Time("world: {0}");
SequenceProvider.Initialize(manifest.Sequences, map.Theater);
Timer.Time("ChromeProv, SeqProv: {0}");
chrome = new Chrome(renderer, manifest);
Timer.Time( "chrome: {0}" );
Timer.Time("chrome: {0}");
Timer.Time( "----end LoadMap" );
Timer.Time("----end LoadMap");
Debug("Map change {0} -> {1}".F(Game.mapName, mapName));
}
public static void MoveViewport(int2 loc)
{
viewport.Center(loc);
}
public static string CurrentHost = "";
public static int CurrentPort = 0;
internal static string CurrentHost = "";
internal static int CurrentPort = 0;
internal static void JoinServer(string host, int port)
{
if (orderManager != null) orderManager.Dispose();
CurrentHost = host;
CurrentPort = port;
orderManager = new OrderManager(new NetworkConnection( host, port ), ChooseReplayFilename());
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
}
internal static void JoinLocal()
static void JoinLocal()
{
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
}
static int lastTime = Environment.TickCount;
public static void ResetTimer()
static void ResetTimer()
{
lastTime = Environment.TickCount;
}
public static int RenderFrame = 0;
internal static int RenderFrame = 0;
internal static Chat chat = new Chat();
public static int LocalTick = 0;
internal static int LocalTick = 0;
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public static void Tick()
static Queue<Pair<int, string>> syncReports = new Queue<Pair<int, string>>();
const int numSyncReports = 5;
internal static void UpdateSyncReport()
{
if (!Settings.RecordSyncReports)
return;
while (syncReports.Count >= numSyncReports) syncReports.Dequeue();
syncReports.Enqueue(Pair.New(orderManager.FrameNumber, GenerateSyncReport()));
}
static string GenerateSyncReport()
{
var sb = new StringBuilder();
sb.AppendLine("Actors:");
foreach (var a in world.Actors)
sb.AppendLine("\t {0} {1} {2} ({3})".F(
a.ActorID,
a.Info.Name,
(a.Owner == null) ? "null" : a.Owner.InternalName,
Sync.CalculateSyncHash(a)));
sb.AppendLine("Tick Actors:");
foreach (var a in world.Queries.WithTraitMultiple<object>())
{
var sync = Sync.CalculateSyncHash(a.Trait);
if (sync != 0)
sb.AppendLine("\t {0} {1} {2} {3} ({4})".F(
a.Actor.ActorID,
a.Actor.Info.Name,
(a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
a.Trait.GetType().Name,
sync));
}
return sb.ToString();
}
internal static void DumpSyncReport(int frame)
{
var f = syncReports.FirstOrDefault(a => a.First == frame);
if (f == null)
{
Log.Write("sync", "No sync report available!");
return;
}
Log.Write("sync", "Sync for net frame {0} -------------", f.First);
Log.Write("sync", "{0}", f.Second);
}
static void Tick()
{
if (packageChangePending)
{
// TODO: Only do this on mod change
Timer.Time("----begin maplist");
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "maplist: {0}" );
Timer.Time("maplist: {0}");
ChangeMods();
return;
}
if (mapChangePending)
{
ChangeMap(LobbyInfo.GlobalSettings.Map);
mapName = LobbyInfo.GlobalSettings.Map;
mapChangePending = false;
return;
}
@@ -229,9 +288,9 @@ namespace OpenRA
using (new PerfSample("tick_time"))
{
lastTime += Settings.Timestep;
chrome.Tick( world );
chrome.Tick(world);
orderManager.TickImmediate( world );
orderManager.TickImmediate(world);
var isNetTick = LocalTick % NetTickScale == 0;
@@ -254,10 +313,20 @@ namespace OpenRA
}
}
if (scrollUp == true)
viewport.Scroll(new float2(0, -10));
if (scrollRight == true)
viewport.Scroll(new float2(10, 0));
if (scrollDown == true)
viewport.Scroll(new float2(0, 10));
if (scrollLeft == true)
viewport.Scroll(new float2(-10, 0));
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions( world );
viewport.DrawRegions(world);
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
}
PerfHistory.items["render"].Tick();
@@ -268,9 +337,9 @@ namespace OpenRA
MasterServerQuery.Tick();
}
public static event Action LobbyInfoChanged = () => { };
internal static event Action LobbyInfoChanged = () => { };
public static void SyncLobbyInfo(string data)
internal static void SyncLobbyInfo(string data)
{
var oldLobbyInfo = LobbyInfo;
@@ -300,19 +369,19 @@ namespace OpenRA
if (!world.GameHasStarted)
world.SharedRandom = new OpenRA.Thirdparty.Random(LobbyInfo.GlobalSettings.RandomSeed);
if (Game.orderManager.Connection.ConnectionState == ConnectionState.Connected)
world.SetLocalPlayer(Game.orderManager.Connection.LocalClientId);
if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
world.SetLocalPlayer(orderManager.Connection.LocalClientId);
if (Game.orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
&& !Game.orderManager.GameStarted)
if (orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
&& !orderManager.GameStarted)
{
Game.orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
Debug("Order lag is now {0} frames.".F(LobbyInfo.GlobalSettings.OrderLatency));
}
if (mapName != LobbyInfo.GlobalSettings.Map)
mapChangePending = true;
if (string.Join(",", oldLobbyInfo.GlobalSettings.Mods)
!= string.Join(",", LobbyInfo.GlobalSettings.Mods))
{
@@ -325,53 +394,42 @@ namespace OpenRA
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
public static void LoadShellMap(string map)
static void LoadShellMap(string map)
{
LoadMap(map);
LoadMap(map);
world.Queries = new World.AllQueries(world);
foreach (var p in world.players.Values)
foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
gs.GameStarted(world);
orderManager.StartGame();
}
public static void StartGame()
internal static void StartGame()
{
LoadMap(LobbyInfo.GlobalSettings.Map);
if (orderManager.GameStarted) return;
chat.Reset();
world.SetLocalPlayer(orderManager.Connection.LocalClientId);
foreach (var c in LobbyInfo.Clients)
world.AddPlayer(new Player(world, c));
foreach (var p in world.players.Values)
foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q);
world.Queries = new World.AllQueries(world);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
gs.GameStarted(world);
Game.viewport.GoToStartLocation( world.LocalPlayer );
viewport.GoToStartLocation(world.LocalPlayer);
orderManager.StartGame();
}
static Stance ChooseInitialStance(Player p, Player q)
public static Stance ChooseInitialStance(Player p, Player q)
{
if (p == q) return Stance.Ally;
if (p == world.NeutralPlayer || q == world.NeutralPlayer) return Stance.Neutral;
// Hack: All map players are neutral wrt everyone else
if (p.Index < 0 || q.Index < 0) return Stance.Neutral;
var pc = GetClientForPlayer(p);
var qc = GetClientForPlayer(q);
return pc.Team != 0 && pc.Team == qc.Team
return pc.Team != 0 && pc.Team == qc.Team
? Stance.Ally : Stance.Enemy;
}
@@ -383,19 +441,22 @@ namespace OpenRA
static int2 lastPos;
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
int sync = Game.world.SyncHash();
int sync = world.SyncHash();
var initialWorld = world;
if (ev == MouseInputEvent.Down)
lastPos = new int2(e.Location);
if (ev == MouseInputEvent.Move && (e.Button == MouseButtons.Middle || e.Button == (MouseButtons.Left | MouseButtons.Right)))
if (ev == MouseInputEvent.Move &&
(e.Button == MouseButtons.Middle ||
e.Button == (MouseButtons.Left | MouseButtons.Right)))
{
var p = new int2(e.Location);
viewport.Scroll(lastPos - p);
lastPos = p;
}
Game.viewport.DispatchMouseInput( world,
viewport.DispatchMouseInput(world,
new MouseInput
{
Button = (MouseButton)(int)e.Button,
@@ -404,42 +465,45 @@ namespace OpenRA
Modifiers = modifierKeys,
});
if( sync != Game.world.SyncHash() )
throw new InvalidOperationException( "Desync in DispatchMouseInput" );
if (sync != world.SyncHash() && world == initialWorld)
throw new InvalidOperationException("Desync in DispatchMouseInput");
}
public static bool IsHost
internal static bool IsHost
{
get { return orderManager.Connection.LocalClientId == 0; }
}
public static Session.Client LocalClient
internal static Session.Client LocalClient
{
get { return LobbyInfo.Clients.FirstOrDefault(c => c.Index == orderManager.Connection.LocalClientId); }
}
static Dictionary<char, char> RemapKeys = new Dictionary<char, char>
{
{ '!', '1' },
{ '@', '2' },
{ '#', '3' },
{ '$', '4' },
{ '%', '5' },
{ '^', '6' },
{ '&', '7' },
{ '*', '8' },
{ '(', '9' },
{ ')', '0' },
static Dictionary<char, char> RemapKeys = new Dictionary<char, char>
{
{ '!', '1' },
{ '@', '2' },
{ '#', '3' },
{ '$', '4' },
{ '%', '5' },
{ '^', '6' },
{ '&', '7' },
{ '*', '8' },
{ '(', '9' },
{ ')', '0' },
};
public static void HandleKeyPress( KeyPressEventArgs e, Modifiers modifiers )
public static void HandleKeyPress(KeyPressEventArgs e, Modifiers modifiers)
{
int sync = Game.world.SyncHash();
if( e.KeyChar == '\r' )
Game.chat.Toggle();
int sync = world.SyncHash();
if (e.KeyChar == '\r')
{
chat.Toggle();
chat.isTeamChat = modifiers.HasModifier(Modifiers.Shift);
}
else if (Game.chat.isChatting)
Game.chat.TypeChar(e.KeyChar);
chat.TypeChar(e.KeyChar);
else
{
var c = RemapKeys.ContainsKey(e.KeyChar) ? RemapKeys[e.KeyChar] : e.KeyChar;
@@ -447,10 +511,38 @@ namespace OpenRA
if (c >= '0' && c <= '9')
Game.controller.selection.DoControlGroup(world,
c - '0', modifiers);
if (c == 08)
Game.controller.GotoNextBase();
if (c == 09)
BuildPaletteWidget.TabChange((Control.ModifierKeys & Keys.Shift) == Keys.Shift ? true : false);
BuildPaletteWidget.DoBuildingHotkey(c, world);
}
if( sync != Game.world.SyncHash() )
throw new InvalidOperationException( "Desync in OnKeyPress" );
if (sync != Game.world.SyncHash())
throw new InvalidOperationException("Desync in OnKeyPress");
}
public static void HandleArrowKeyScroll(String k, Boolean pressed)
{
if (k == "up")
{
scrollUp = pressed;
}
if (k == "left")
{
scrollLeft = pressed;
}
if (k == "down")
{
scrollDown = pressed;
}
if (k == "right")
{
scrollRight = pressed;
}
}
public static void HandleModifierKeys(Modifiers mods)
@@ -461,71 +553,68 @@ namespace OpenRA
static Size GetResolution(Settings settings)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
if (Game.Settings.Width > 0 && Game.Settings.Height > 0)
if (Settings.Width > 0 && Settings.Height > 0)
{
desktopResolution.Width = Game.Settings.Width;
desktopResolution.Height = Game.Settings.Height;
desktopResolution.Width = Settings.Width;
desktopResolution.Height = Settings.Height;
}
return new Size(
desktopResolution.Width,
desktopResolution.Height);
}
public static void Initialize(Settings settings)
internal static void Initialize(Settings settings)
{
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
while (!Directory.Exists("mods"))
{
var current = Directory.GetCurrentDirectory();
if (Directory.GetDirectoryRoot(current) == current)
throw new InvalidOperationException("Unable to find game root.");
Directory.SetCurrentDirectory("..");
}
LoadUserSettings(settings);
Game.LobbyInfo.GlobalSettings.Mods = Game.Settings.InitialMods;
LobbyInfo.GlobalSettings.Mods = Settings.InitialMods;
// Load the default mod to access required files
Game.LoadModPackages(new Manifest(Game.LobbyInfo.GlobalSettings.Mods));
Renderer.SheetSize = Game.Settings.SheetSize;
LoadModPackages(new Manifest(LobbyInfo.GlobalSettings.Mods));
Renderer.SheetSize = Settings.SheetSize;
bool windowed = !Game.Settings.Fullscreen;
var resolution = GetResolution(settings);
renderer = new Renderer(resolution, windowed);
resolution = renderer.Resolution;
Game.controller = new Controller();
Game.clientSize = new int2(resolution);
controller = new Controller();
clientSize = new int2(resolution);
Sound.Initialize();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false;
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
ChangeMods();
if( Settings.Replay != "" )
orderManager = new OrderManager( new ReplayConnection( Settings.Replay ) );
if (Settings.Replay != "")
orderManager = new OrderManager(new ReplayConnection(Settings.Replay));
else
JoinLocal();
LoadShellMap(new Manifest(LobbyInfo.GlobalSettings.Mods).ShellmapUid);
Game.ResetTimer();
ResetTimer();
Log.AddChannel("sync", "openra.syncreport.txt", true, true);
}
static void LoadUserSettings(Settings settings)
{
Game.Settings = new UserSettings();
Settings = new UserSettings();
var settingsFile = settings.GetValue("settings", "settings.ini");
FileSystem.Mount("./");
if (FileSystem.Exists(settingsFile))
FieldLoader.Load(Game.Settings,
FieldLoader.Load(Settings,
new IniFile(FileSystem.Open(settingsFile)).GetSection("Settings"));
FileSystem.UnmountAll();
FileSystem.UnmountAll();
Settings.AddSettings(settings);
}
static bool quit;
@@ -533,7 +622,7 @@ namespace OpenRA
{
while (!quit)
{
Game.Tick();
Tick();
Application.DoEvents();
}
}
@@ -541,5 +630,38 @@ namespace OpenRA
public static void Exit() { quit = true; }
public static void Debug(string s) { chat.AddLine(Color.White, "Debug", s); }
public static void Disconnect()
{
var shellmap = new Manifest(LobbyInfo.GlobalSettings.Mods).ShellmapUid;
LobbyInfo = new Session();
LobbyInfo.GlobalSettings.Mods = Settings.InitialMods;
JoinLocal();
LoadShellMap(shellmap);
Chrome.rootWidget.CloseWindow();
Chrome.rootWidget.OpenWindow("MAINMENU_BG");
}
internal static int GetGameId()
{
try
{
string s = File.ReadAllText(Log.LogPathPrefix + "openra.gameid");
return int.Parse(s);
}
catch (Exception)
{
return 0;
}
}
internal static void SetGameId(int id)
{
var file = File.CreateText(Log.LogPathPrefix + "openra.gameid");
file.Write(id);
file.Flush();
file.Close();
}
}
}
}

View File

@@ -84,10 +84,11 @@ namespace OpenRA.GameRules
while( t.Count != 0 )
{
if( index >= t.Count )
throw new InvalidOperationException( "Trait prerequisites not satisfied (or prerequisite loop)" );
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().IsSubclassOf( n ) ) ) )
if( prereqs.Count == 0 || prereqs.All( n => ret.Any( x => x.GetType() == n || x.GetType().IsSubclassOf( n ) ) ) )
{
ret.Add( t[ index ] );
t.RemoveAt( index );

View File

@@ -25,7 +25,7 @@ using OpenRA.Traits;
namespace OpenRA.GameRules
{
static class Footprint
public static class Footprint
{
public static IEnumerable<int2> Tiles( string name, BuildingInfo buildingInfo, int2 topLeft )
{

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class MusicInfo
{
public readonly MusicPool Pool;
public readonly string[] Music = { };
public MusicInfo( MiniYaml y )
{
FieldLoader.Load(this, y);
Pool = new MusicPool(Music);
}
}
public class MusicPool
{
readonly string[] clips;
int playing = 0;
public MusicPool(params string[] clips)
{
this.clips = clips;
}
public string GetNext()
{
playing = (playing + 1) % clips.Length;
return clips[playing];
}
public string GetPrev()
{
playing = (playing + clips.Length - 1) % clips.Length;
return clips[playing];
}
public string GetCurrent(){ return clips[playing];}
}
}

View File

@@ -33,42 +33,29 @@ namespace OpenRA
public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<TerrainType, TerrainCost> TerrainTypes;
public static Dictionary<string, MusicInfo> Music;
public static Dictionary<string, TileSet> TileSets;
public static void LoadRules(Manifest m)
{
Log.Write("Using rules files: ");
foreach (var y in m.Rules)
Log.Write(" -- {0}", y);
Info = LoadYamlRules(m.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, (k, _) => new VoiceInfo(k.Value));
TerrainTypes = LoadYamlRules(m.Terrain, (k, _) => new TerrainCost(k.Value))
.ToDictionary(kv => (TerrainType)Enum.Parse(typeof(TerrainType), kv.Key, true), kv => kv.Value);
TechTree = new TechTree();
}
static Dictionary<string, T> LoadYamlRules<T>(string[] files, Func<KeyValuePair<string, MiniYaml>, Dictionary<string, MiniYaml>, T> f)
{
var y = files.Select(a => MiniYaml.FromFile(a)).Aggregate(MiniYaml.Merge);
return y.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => f(kv, y));
}
public static void LoadRules(Manifest m, Map map)
{
Log.Write("Using rules files: ");
Log.Write("debug", "Using rules files: ");
foreach (var y in m.Rules)
Log.Write(" -- {0}", y);
Log.Write("debug", " -- {0}", y);
Log.Write("Using Map: {0}",map.Uid);
Log.Write("debug", "Using Map: {0}",map.Uid);
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
TerrainTypes = LoadYamlRules(m.Terrain, map.Terrain, (k, _) => new TerrainCost(k.Value))
.ToDictionary(kv => (TerrainType)Enum.Parse(typeof(TerrainType), kv.Key, true), kv => kv.Value);
Music = LoadYamlRules(m.Music, map.Music, (k, _) => new MusicInfo(k.Value));
TileSets = new Dictionary<string, TileSet>();
foreach (var file in m.TileSets)
{
var t = new TileSet(file);
TileSets.Add(t.Id,t);
}
TechTree = new TechTree();
}

View File

@@ -1,72 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.GameRules
{
public enum UnitMovementType : byte
{
Foot = 0,
Track = 1,
Wheel = 2,
Float = 3,
Fly = 4,
}
public class TerrainCost
{
public readonly bool Buildable = true;
public readonly float Foot = 0, Track = 0, Wheel = 0, Float = 0;
public readonly bool AcceptSmudge = true;
public TerrainCost(MiniYaml y) { FieldLoader.Load(this, y); }
public float GetSpeedModifier(UnitMovementType umt)
{
switch (umt) /* todo: make this nice */
{
case UnitMovementType.Fly: return 1;
case UnitMovementType.Foot: return Foot;
case UnitMovementType.Wheel: return Wheel;
case UnitMovementType.Track: return Track;
case UnitMovementType.Float: return Float;
default:
throw new InvalidOperationException("wtf?");
}
}
public float GetCost(UnitMovementType umt)
{
switch (umt) /* todo: make this nice */
{
case UnitMovementType.Fly: return 1;
case UnitMovementType.Foot: return 1 / Foot;
case UnitMovementType.Wheel: return 1 / Wheel;
case UnitMovementType.Track: return 1 / Track;
case UnitMovementType.Float: return 1 / Float;
default:
throw new InvalidOperationException("wtf?");
}
}
}
}

View File

@@ -24,14 +24,16 @@ namespace OpenRA.GameRules
{
// Debug settings
public bool UnitDebug = false;
public bool PathDebug = false;
public bool PathDebug = true;
public bool PerfDebug = true;
public bool IndexDebug = false;
public bool RecordSyncReports = true;
// Window settings
public readonly int Width = 0;
public readonly int Height = 0;
public readonly bool Fullscreen = false;
public bool MusicPlayer = true;
// Internal game settings
public readonly int Timestep = 40;
@@ -50,5 +52,12 @@ namespace OpenRA.GameRules
public readonly int ExternalPort = 1234;
public readonly bool InternetServer = true;
public readonly string MasterServer = "http://open-ra.org/master/";
public void AddSettings(Settings settings)
{
foreach (var f in this.GetType().GetFields())
if (settings.Contains(f.Name))
OpenRA.FileFormats.FieldLoader.LoadField( this, f.Name, settings.GetValue(f.Name, "") );
}
}
}

View File

@@ -29,10 +29,9 @@ namespace OpenRA.GameRules
{
public readonly int Spread = 1; // distance (in pixels) from the explosion center at which damage is 1/2.
public readonly float[] Verses = { 1, 1, 1, 1, 1 }; // damage vs each armortype
public readonly bool Wall = false; // can this damage walls?
public readonly bool Wood = false; // can this damage wood?
public readonly bool Ore = false; // can this damage ore?
public readonly int Explosion = 0; // explosion effect to use
public readonly string Explosion = null; // explosion effect to use
public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash)
public readonly string SmudgeType = null; // type of smudge to apply
public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner)
public readonly int InfDeath = 0; // infantry death animation to use

View File

@@ -68,6 +68,9 @@ namespace OpenRA.Graphics
public void ReplaceAnim(string sequenceName)
{
if (!HasSequence(sequenceName))
return;
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
}

View File

@@ -30,11 +30,11 @@ namespace OpenRA.Graphics
class Minimap
{
readonly World world;
Sheet sheet, mapOnlySheet;
Sheet sheet;
SpriteRenderer rgbaRenderer;
LineRenderer lineRenderer;
Sprite sprite, mapOnlySprite;
Bitmap terrain, oreLayer;
Sprite sprite;
Bitmap terrain, customLayer;
Rectangle bounds;
Sprite ownedSpawnPoint;
@@ -42,13 +42,10 @@ namespace OpenRA.Graphics
const int alpha = 230;
public void Tick() { }
public Minimap(World world, Renderer r)
{
this.world = world;
sheet = new Sheet(r, new Size(world.Map.MapSize.X, world.Map.MapSize.Y));
mapOnlySheet = new Sheet(r, new Size(world.Map.MapSize.X, world.Map.MapSize.Y));
lineRenderer = new LineRenderer(r);
rgbaRenderer = r.RgbaSpriteRenderer;
@@ -59,8 +56,7 @@ namespace OpenRA.Graphics
bounds = new Rectangle(world.Map.TopLeft.X - dw, world.Map.TopLeft.Y - dh, size, size);
sprite = new Sprite(sheet, bounds, TextureChannel.Alpha);
mapOnlySprite = new Sprite(mapOnlySheet, bounds, TextureChannel.Alpha);
shroudColor = Color.FromArgb(alpha, Color.Black);
ownedSpawnPoint = ChromeProvider.GetImage(r, "spawnpoints", "owned");
@@ -76,59 +72,49 @@ namespace OpenRA.Graphics
return new Rectangle(m.TopLeft.X - dw, m.TopLeft.Y - dh, size, size);
}
static Cache<string, TerrainColorSet> terrainTypeColors = new Cache<string, TerrainColorSet>(
theater =>
{
return new TerrainColorSet(Rules.Info["world"].Traits.WithInterface<TheaterInfo>().FirstOrDefault(t => t.Theater == theater).MapColors);
});
static Color shroudColor;
public void InvalidateOre() { oreLayer = null; }
public void InvalidateCustom() { customLayer = null; }
public static Bitmap RenderTerrainBitmap(Map map, TileSet tileset)
{
var terrain = new Bitmap(map.MapSize.X, map.MapSize.Y);
for (var x = 0; x < map.MapSize.X; x++)
for (var y = 0; y < map.MapSize.Y; y++)
{
var type = tileset.GetTerrainType(map.MapTiles[x, y]);
terrain.SetPixel(x, y, map.IsInMap(x, y)
? Color.FromArgb(alpha, terrainTypeColors[map.Theater].ColorForTerrainType(tileset.GetTerrainType(map.MapTiles[x, y])))
? Color.FromArgb(alpha, tileset.Terrain[type].Color)
: shroudColor);
}
return terrain;
}
public static Bitmap RenderTerrainBitmapWithSpawnPoints(Map map, TileSet tileset)
{
/* todo: do this a bit nicer */
var terrain = RenderTerrainBitmap(map, tileset);
foreach (var sp in map.SpawnPoints)
terrain.SetPixel(sp.X, sp.Y, Color.White);
return terrain;
}
public void Update()
{
{
if (terrain == null)
terrain = RenderTerrainBitmap(world.Map, world.TileSet);
if (oreLayer == null)
// Custom terrain layer
if (customLayer == null)
{
var res = world.WorldActor.traits.Get<ResourceLayer>();
oreLayer = new Bitmap(terrain);
customLayer = new Bitmap(terrain);
for (var x = world.Map.TopLeft.X; x < world.Map.BottomRight.X; x++)
for (var y = world.Map.TopLeft.Y; y < world.Map.BottomRight.Y; y++)
if (res.GetResource(new int2(x,y)) != null)
oreLayer.SetPixel(x, y, Color.FromArgb(alpha, terrainTypeColors[world.Map.Theater].ColorForTerrainType(TerrainType.Ore)));
{
var customTerrain = world.WorldActor.traits.WithInterface<ITerrainTypeModifier>()
.Select( t => t.GetTerrainType(new int2(x,y)) )
.FirstOrDefault( t => t != null );
if (customTerrain == null) continue;
customLayer.SetPixel(x, y, Color.FromArgb(alpha, world.TileSet.Terrain[customTerrain].Color));
}
}
mapOnlySheet.Texture.SetData(oreLayer);
if (!world.GameHasStarted || !world.Queries.OwnedBy[world.LocalPlayer].WithTrait<ProvidesRadar>().Any())
return;
var bitmap = new Bitmap(oreLayer);
var bitmap = new Bitmap(customLayer);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
@@ -136,7 +122,7 @@ namespace OpenRA.Graphics
{
int* c = (int*)bitmapData.Scan0;
foreach (var a in world.Queries.WithTrait<Unit>().Where( a => a.Actor.Owner != null ))
foreach (var a in world.Queries.WithTrait<Unit>().Where(a => a.Actor.Owner != null && a.Actor.IsVisible()))
*(c + (a.Actor.Location.Y * bitmapData.Stride >> 2) + a.Actor.Location.X) =
Color.FromArgb(alpha, a.Actor.Owner.Color).ToArgb();
@@ -149,9 +135,9 @@ namespace OpenRA.Graphics
continue;
}
var b = world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(new int2(x, y));
if (b != null)
*(c + (y * bitmapData.Stride >> 2) + x) =
(b.Owner != null ? Color.FromArgb(alpha, b.Owner.Color) : Color.FromArgb(alpha, terrainTypeColors[world.Map.Theater].ColorForTerrainType(TerrainType.Tree))).ToArgb();
*(c + (y * bitmapData.Stride >> 2) + x) = Color.FromArgb(alpha, b.Owner.Color).ToArgb();
}
}
@@ -159,21 +145,31 @@ namespace OpenRA.Graphics
sheet.Texture.SetData(bitmap);
}
public void Draw(RectangleF rect, bool mapOnly)
public void Draw(RectangleF rect)
{
rgbaRenderer.DrawSprite(mapOnly ? mapOnlySprite : sprite,
rgbaRenderer.DrawSprite(sprite,
new float2(rect.X, rect.Y), "chrome", new float2(rect.Width, rect.Height));
rgbaRenderer.Flush();
}
int2 TransformCellToMinimapPixel(RectangleF viewRect, int2 p)
int2 CellToMinimapPixel(RectangleF viewRect, int2 p)
{
var fx = (float)(p.X - bounds.X) / bounds.Width;
var fy = (float)(p.Y - bounds.Y) / bounds.Height;
return new int2(
(int)(viewRect.Width * fx + viewRect.Left) - 8,
(int)(viewRect.Height * fy + viewRect.Top) - 8);
(int)(viewRect.Width * fx + viewRect.Left),
(int)(viewRect.Height * fy + viewRect.Top));
}
public int2 MinimapPixelToCell(RectangleF viewRect, int2 p)
{
var fx = (float)(p.X - viewRect.Left) / viewRect.Width;
var fy = (float)(p.Y - viewRect.Top) / viewRect.Height;
return new int2(
(int)(bounds.Width * fx + bounds.Left),
(int)(bounds.Height * fy + bounds.Top));
}
public void DrawSpawnPoints(RectangleF rect)
@@ -185,7 +181,7 @@ namespace OpenRA.Graphics
foreach (var p in points)
{
var pos = TransformCellToMinimapPixel(rect, p.First);
var pos = CellToMinimapPixel(rect, p.First) - new int2(8, 8);
if (p.Second == null)
rgbaRenderer.DrawSprite(unownedSpawnPoint, pos, "chrome");
@@ -194,7 +190,7 @@ namespace OpenRA.Graphics
lineRenderer.FillRect(new RectangleF(
Game.viewport.Location.X + pos.X + 2,
Game.viewport.Location.Y + pos.Y + 2,
12, 12), Player.PlayerColors(world)[ p.Second.PaletteIndex % Player.PlayerColors(world).Count() ].c);
12, 12), Game.world.PlayerColors()[p.Second.PaletteIndex % Game.world.PlayerColors().Count()].Color);
rgbaRenderer.DrawSprite(ownedSpawnPoint, pos, "chrome");
}

View File

@@ -31,12 +31,14 @@ namespace OpenRA.Graphics
{
static Dictionary<string, Dictionary<string, Sequence>> units;
static Dictionary<string, CursorSequence> cursors;
static string currentTheater;
public static void Initialize(params string[] sequenceFiles)
public static void Initialize(string[] sequenceFiles, string theater)
{
units = new Dictionary<string, Dictionary<string, Sequence>>();
cursors = new Dictionary<string, CursorSequence>();
currentTheater = theater;
foreach (var f in sequenceFiles)
LoadSequenceSource(f);
}

View File

@@ -22,15 +22,15 @@ using System.Drawing;
namespace OpenRA.Graphics
{
class SheetBuilder
public class SheetBuilder
{
public static SheetBuilder SharedInstance;
public static void Initialize(Renderer r)
internal static void Initialize(Renderer r)
{
SharedInstance = new SheetBuilder(r, TextureChannel.Red);
}
public SheetBuilder(Renderer r, TextureChannel ch)
internal SheetBuilder(Renderer r, TextureChannel ch)
{
renderer = r;
current = null;

View File

@@ -21,14 +21,20 @@ namespace OpenRA.Graphics
throw new InvalidOperationException("FT_New_Face failed");
FT.FT_Set_Pixel_Sizes(face, 0, (uint)size);
glyphs = new Cache<char, GlyphInfo>(CreateGlyph);
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph);
// setup a 1-channel SheetBuilder for our private use
if (builder == null) builder = new SheetBuilder(r, TextureChannel.Alpha);
PrecacheColor(Color.White);
PrecacheColor(Color.Red);
}
void PrecacheColor(Color c)
{
// precache glyphs for U+0020 - U+007f
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[n] == null)
if (glyphs[Pair.New(n, c)] == null)
throw new InvalidOperationException();
}
@@ -45,8 +51,8 @@ namespace OpenRA.Graphics
p = location;
continue;
}
var g = glyphs[s];
var g = glyphs[Pair.New(s, c)];
renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X + g.Offset.X, 0),
@@ -60,15 +66,15 @@ namespace OpenRA.Graphics
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[a].Advance)), text.Split('\n').Count()*size);
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size);
}
Cache<char, GlyphInfo> glyphs;
Cache<Pair<char,Color>, GlyphInfo> glyphs;
IntPtr face;
GlyphInfo CreateGlyph(char c)
GlyphInfo CreateGlyph(Pair<char,Color> c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c);
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
@@ -92,7 +98,7 @@ namespace OpenRA.Graphics
for (var i = 0; i < s.size.X; i++)
if (p[i] != 0)
s.sheet.Bitmap.SetPixel(i + s.bounds.Left, j + s.bounds.Top,
Color.FromArgb(p[i], 0xff, 0xff, 0xff));
Color.FromArgb(p[i], c.Second.R, c.Second.G, c.Second.B));
p += _glyph.bitmap.pitch;
}

View File

@@ -20,19 +20,16 @@
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
static class SpriteSheetBuilder
{
public static void Initialize( Map map )
public static void Initialize( TileSet tileset )
{
exts = new[] {
"." + map.Theater.Substring( 0, 3 ).ToLowerInvariant(),
".shp",
".tem",
".sno",
".int" };
/* .tem: hack to allow incomplete theaters (interior) to work, falling back to temperate for the missing art */
exts = tileset.Extensions;
sprites = new Cache<string, Sprite[]>( LoadSprites );
}

View File

@@ -27,7 +27,7 @@ using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
static class Util
public static class Util
{
public static string[] ReadAllLines(Stream s)
{

View File

@@ -88,6 +88,7 @@ namespace OpenRA.Graphics
}
Game.chrome.Draw( world );
Timer.Time( "chromedraw: {0}" );
}
else
{
@@ -128,6 +129,7 @@ namespace OpenRA.Graphics
lastConnectionState = state;
Timer.Time( "connectionState: {0}" );
}
Game.chrome.DrawWidgets(world);
if (Chrome.rootWidget.GetWidget("SERVER_LOBBY").Visible)
@@ -202,6 +204,7 @@ namespace OpenRA.Graphics
{
var localPlayer = Game.world.LocalPlayer;
if (localPlayer == null) return null;
if (localPlayer.Shroud.Disabled) return null;
return localPlayer.Shroud.Bounds;
}
}

View File

@@ -48,6 +48,11 @@ namespace OpenRA.Graphics
palette = new HardwarePalette(renderer, world.Map);
}
public void DrawLine(float2 start, float2 end, Color startColor, Color endColor)
{
lineRenderer.DrawLine(start,end,startColor,endColor);
}
public int GetPaletteIndex(string name)
{
return palette.GetPaletteIndex(name);
@@ -230,21 +235,27 @@ namespace OpenRA.Graphics
}
if (Game.Settings.PathDebug)
{
var mobile = selectedUnit.traits.GetOrDefault<Mobile>();
if (mobile != null)
{
var path = mobile.GetCurrentPath();
var start = selectedUnit.Location;
DrawUnitPath(selectedUnit);
}
foreach (var step in path)
{
lineRenderer.DrawLine(
Game.CellSize * start + new float2(12, 12),
Game.CellSize * step + new float2(12, 12),
Color.Red, Color.Red);
start = step;
}
void DrawUnitPath(Actor selectedUnit)
{
var mobile = selectedUnit.traits.WithInterface<IMove>().FirstOrDefault();
if (mobile != null)
{
var path = mobile.GetCurrentPath(selectedUnit);
var start = selectedUnit.CenterLocation;
var c = Color.Green;
foreach (var step in path)
{
lineRenderer.DrawLine(step + new float2(-1, -1), step + new float2(-1, 1), c, c);
lineRenderer.DrawLine(step + new float2(-1, 1), step + new float2(1, 1), c, c);
lineRenderer.DrawLine(step + new float2(1, 1), step + new float2(1, -1), c, c);
lineRenderer.DrawLine(step + new float2(1, -1), step + new float2(-1, -1), c, c);
lineRenderer.DrawLine(start, step, c, c);
start = step;
}
}
}
@@ -301,16 +312,15 @@ namespace OpenRA.Graphics
{
foreach (var pip in pips.GetPips(selectedUnit))
{
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
spriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
if (pipxyOffset.X+5 > selectedUnit.GetBounds(false).Width)
{
pipxyOffset.X = 0;
pipxyOffset.Y -= 4;
}
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
spriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
}
// Increment row
pipxyOffset.X = 0;
@@ -341,30 +351,34 @@ namespace OpenRA.Graphics
}
}
public void DrawRangeCircle(Actor selectedUnit)
public void DrawLocus(Color c, int2[] cells)
{
if (selectedUnit.Owner != world.LocalPlayer)
return;
var range = (int)selectedUnit.GetPrimaryWeapon().Range;
var r2 = range * range;
var c = Color.FromArgb(128, Color.Yellow);
foreach (var t in world.FindTilesInCircle(selectedUnit.Location, range))
var dict = cells.ToDictionary(a => a, a => 0);
foreach (var t in dict.Keys)
{
if ((selectedUnit.Location - t - new int2(-1, 0)).LengthSquared > r2)
if (!dict.ContainsKey(t + new int2(-1, 0)))
lineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)),
c,c);
if ((selectedUnit.Location - t - new int2(1, 0)).LengthSquared > r2)
lineRenderer.DrawLine(Game.CellSize * (t + new int2(1,0)), Game.CellSize * (t + new int2(1, 1)),
c,c);
if ((selectedUnit.Location - t - new int2(0,-1)).LengthSquared > r2)
lineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1,0)),
c,c);
if ((selectedUnit.Location - t - new int2(0,1)).LengthSquared > r2)
lineRenderer.DrawLine(Game.CellSize * (t + new int2(0,1)), Game.CellSize * (t + new int2(1, 1)),
c,c);
c, c);
if (!dict.ContainsKey(t + new int2(1, 0)))
lineRenderer.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)),
c, c);
if (!dict.ContainsKey(t + new int2(0, -1)))
lineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)),
c, c);
if (!dict.ContainsKey(t + new int2(0, 1)))
lineRenderer.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)),
c, c);
}
}
public void DrawRangeCircle(Color c, float2 location, int range)
{
var prev = location + Game.CellSize * range * float2.FromAngle(0);
for (var i = 1; i <= 32; i++)
{
var pos = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 8);
lineRenderer.DrawLine(prev, pos, c, c);
prev = pos;
}
}
}

View File

@@ -19,31 +19,36 @@
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Traits
namespace OpenRA
{
class GeneratesGapInfo : ITraitInfo
public class Group
{
public readonly int Range = 10;
public object Create(Actor self) { return new GeneratesGap(self); }
}
List<Actor> actors;
int id;
class GeneratesGap
{
Actor self;
public GeneratesGap(Actor self)
static int nextGroup;
public IEnumerable<Actor> Actors { get { return actors; } }
public Group(IEnumerable<Actor> actors)
{
this.self = self;
this.actors = actors.ToList();
foreach (var a in actors)
a.Group = this;
id = nextGroup++;
}
public IEnumerable<int2> GetShroudedTiles()
public void Dump()
{
int range = self.Info.Traits.Get<GeneratesGapInfo>().Range;
// Gap Generator building; powered down
return (self.traits.Contains<Building>() && self.traits.Get<Building>().Disabled)
? new int2[] {}
: self.World.FindTilesInCircle(self.Location, range);
/* debug crap */
Game.Debug("Group #{0}: {1}".F(
id, string.Join(",", actors.Select(a => "#{0} {1}".F(a.ActorID, a.Info.Name)).ToArray())));
}
/* todo: add lazy group path crap, groupleader, pruning, etc */
}
}

View File

@@ -135,10 +135,16 @@ namespace OpenRA.Network
{
base.Send( packet );
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( (int)packet.Length ) );
ms.Write( packet );
ms.WriteTo( socket.GetStream() );
try
{
var ms = new MemoryStream();
ms.Write(BitConverter.GetBytes((int)packet.Length));
ms.Write(packet);
ms.WriteTo(socket.GetStream());
}
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
}
}

View File

@@ -31,34 +31,38 @@ namespace OpenRA
public readonly Actor TargetActor;
public readonly int2 TargetLocation;
public readonly string TargetString;
public readonly bool Queued;
public bool IsImmediate;
public Player Player { get { return Subject.Owner; } }
public Order(string orderString, Actor subject,
Actor targetActor, int2 targetLocation, string targetString)
Actor targetActor, int2 targetLocation, string targetString, bool queued)
{
this.OrderString = orderString;
this.Subject = subject;
this.TargetActor = targetActor;
this.TargetLocation = targetLocation;
this.TargetString = targetString;
this.Queued = queued;
}
public Order(string orderString, Actor subject)
: this(orderString, subject, null, int2.Zero, null) { }
: this(orderString, subject, null, int2.Zero, null, false) { }
public Order(string orderString, Actor subject, Actor targetActor)
: this(orderString, subject, targetActor, int2.Zero, null) { }
: this(orderString, subject, targetActor, int2.Zero, null, false) { }
public Order(string orderString, Actor subject, int2 targetLocation)
: this(orderString, subject, null, targetLocation, null) { }
: 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) { }
: this(orderString, subject, null, int2.Zero, targetString, false) { }
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation)
: this(orderString, subject, targetActor, targetLocation, null) { }
: this(orderString, subject, targetActor, targetLocation, null, false) { }
public Order(string orderString, Actor subject, Actor targetActor, string targetString)
: this(orderString, subject, targetActor, int2.Zero, 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) { }
: this(orderString, subject, null, targetLocation, targetString, false) { }
public byte[] Serialize()
{
@@ -92,6 +96,7 @@ namespace OpenRA
w.Write(TargetString != null);
if (TargetString != null)
w.Write(TargetString);
w.Write(Queued);
return ret.ToArray();
}
}
@@ -111,12 +116,13 @@ namespace OpenRA
var targetString = null as string;
if (r.ReadBoolean())
targetString = r.ReadString();
var queued = r.ReadBoolean();
Actor subject, targetActor;
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
return null;
return new Order( order, subject, targetActor, targetLocation, targetString);
return new Order( order, subject, targetActor, targetLocation, targetString, queued);
}
case 0xfe:
@@ -171,6 +177,11 @@ namespace OpenRA
return new Order("Chat", null, text) { IsImmediate = true };
}
public static Order TeamChat(string text)
{
return new Order("TeamChat", null, text) { IsImmediate = true };
}
public static Order StartProduction(Player subject, string item, int count)
{
return new Order("StartProduction", subject.PlayerActor, new int2( count, 0 ), item );

View File

@@ -23,11 +23,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Network
{
class OrderManager
class OrderManager : IDisposable
{
public int FrameNumber { get; private set; }
@@ -63,7 +62,10 @@ namespace OpenRA.Network
public OrderManager( IConnection conn, string replayFilename )
: this( conn )
{
replaySaveFile = File.Create( replayFilename );
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + ".openra";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
replaySaveFile = File.Create( path + Path.DirectorySeparatorChar + replayFilename );
}
public void IssueOrders( Order[] orders )
@@ -110,46 +112,35 @@ namespace OpenRA.Network
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
void CheckSync( byte[] packet )
void CheckSync(byte[] packet)
{
var frame = BitConverter.ToInt32( packet, 0 );
var frame = BitConverter.ToInt32(packet, 0);
byte[] existingSync;
if( syncForFrame.TryGetValue( frame, out existingSync ) )
if (syncForFrame.TryGetValue(frame, out existingSync))
{
if( packet.Length != existingSync.Length )
if (packet.Length != existingSync.Length)
{
DumpActors();
OutOfSync( frame );
Game.DumpSyncReport(frame);
OutOfSync(frame);
}
else
{
for( int i = 0 ; i < packet.Length ; i++ )
for (int i = 0; i < packet.Length; i++)
{
if( packet[ i ] != existingSync[ i ] )
if (packet[i] != existingSync[i])
{
DumpActors();
Game.DumpSyncReport(frame);
if ( i < SyncHeaderSize )
if (i < SyncHeaderSize)
OutOfSync(frame, "Tick");
else
OutOfSync( frame , (i - SyncHeaderSize) / 4);
OutOfSync(frame, (i - SyncHeaderSize) / 4);
}
}
}
}
else
syncForFrame.Add( frame, packet );
}
static void DumpActors()
{
Log.Write( "Actors:" );
foreach( var a in Game.world.Actors )
Log.Write( "\t {0} {1} {2} ({3})", a.ActorID, a.Info.Name, ( a.Owner == null ) ? "null" : a.Owner.InternalName, Sync.CalculateSyncHash( a ) );
Log.Write( "Tick Actors:" );
foreach( var a in Game.world.Queries.WithTraitMultiple<ITick>() )
Log.Write( "\t {0} {1} {2} {3} ({4})", a.Actor.ActorID, a.Actor.Info.Name, ( a.Actor.Owner == null ) ? "null" : a.Actor.Owner.InternalName, a.Trait.GetType().Name, Sync.CalculateSyncHash( a.Trait ) );
syncForFrame.Add(frame, packet);
}
void OutOfSync( int frame , int index)
@@ -209,6 +200,8 @@ namespace OpenRA.Network
Connection.Send( ss );
WriteToReplay( frameData, ss );
Game.UpdateSyncReport();
CheckSync( ss );
++FrameNumber;
@@ -240,5 +233,22 @@ namespace OpenRA.Network
replaySaveFile.Write( i.Second );
}
}
bool disposed;
public void Dispose()
{
if (disposed) return;
if (replaySaveFile != null)
replaySaveFile.Dispose();
var disposableConnection = Connection as IDisposable;
if (disposableConnection != null) disposableConnection.Dispose();
disposed = true;
GC.SuppressFinalize(this);
}
~OrderManager() { Dispose(); }
}
}

View File

@@ -37,6 +37,20 @@ namespace OpenRA.Network
Game.chat.AddLine(client, order.TargetString);
break;
}
case "TeamChat":
{
var client = Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == clientId);
if (client != null)
{
var player = Game.world.players.Values.FirstOrDefault(p => p.Index == client.Index);
var isAlly = player != null && Game.world.LocalPlayer != null
&& player.Stances[Game.world.LocalPlayer] == Stance.Ally;
if (isAlly)
Game.chat.AddLine(client, "(Team) " + order.TargetString);
}
break;
}
case "StartGame":
{
Game.chat.AddLine(Color.White, "Server", "The game has started.");

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -35,8 +35,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;SANITY_CHECKS</DefineConstants>
<OutputPath>..\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
@@ -79,13 +79,19 @@
<Compile Include="Chrome.cs" />
<Compile Include="Effects\GravityBomb.cs" />
<Compile Include="GameRules\WeaponInfo.cs" />
<Compile Include="Group.cs" />
<Compile Include="Orders\GenericSelectTarget.cs" />
<Compile Include="Traits\AI\EmitInfantryOnSell.cs" />
<Compile Include="Traits\AI\ReturnOnIdle.cs" />
<Compile Include="Traits\RevealsShroud.cs" />
<Compile Include="Traits\Player\VictoryConditions.cs" />
<Compile Include="Traits\Activities\UndeployMcv.cs" />
<Compile Include="Traits\DetectCloaked.cs" />
<Compile Include="Traits\LintAttributes.cs" />
<Compile Include="Traits\Modifiers\FrozenUnderFog.cs" />
<Compile Include="Traits\Player\ActorGroupProxy.cs" />
<Compile Include="Traits\Player\PlayerResources.cs" />
<Compile Include="Traits\Player\TechTreeCache.cs" />
<Compile Include="Traits\Modifiers\HiddenUnderFog.cs" />
<Compile Include="Traits\Render\RenderFlare.cs" />
<Compile Include="Traits\Render\RenderBuilding.cs" />
<Compile Include="Traits\Render\RenderBuildingTurreted.cs" />
<Compile Include="Traits\Render\RenderUnitTurreted.cs" />
<Compile Include="Traits\World\Shroud.cs" />
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
<Compile Include="Widgets\Delegates\CreateServerMenuDelegate.cs" />
@@ -99,7 +105,6 @@
<Compile Include="Widgets\PostGameWidget.cs" />
<Compile Include="Widgets\WidgetUtils.cs" />
<Compile Include="Combat.cs" />
<Compile Include="Effects\Corpse.cs" />
<Compile Include="Effects\DelayedAction.cs" />
<Compile Include="Effects\FlashTarget.cs" />
<Compile Include="Effects\LaserZap.cs" />
@@ -118,12 +123,9 @@
<Compile Include="Graphics\Minimap.cs" />
<Compile Include="Graphics\SpriteFont.cs" />
<Compile Include="Network\Connection.cs" />
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
<Compile Include="Effects\Missile.cs" />
<Compile Include="Network\OrderIO.cs" />
<Compile Include="Network\OrderManager.cs" />
<Compile Include="Orders\RepairOrderGenerator.cs" />
<Compile Include="Orders\SellOrderGenerator.cs" />
<Compile Include="PathSearch.cs" />
<Compile Include="Selection.cs" />
<Compile Include="Server\Connection.cs" />
@@ -135,25 +137,11 @@
<Compile Include="Sound.cs" />
<Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" />
<Compile Include="Traits\Attack\AttackOmni.cs" />
<Compile Include="Traits\Attack\AttackTesla.cs" />
<Compile Include="Traits\Chrome\PowerDownButton.cs" />
<Compile Include="Traits\CustomSellValue.cs" />
<Compile Include="Traits\World\SpatialBins.cs" />
<Compile Include="Traits\World\SpawnDefaultUnits.cs" />
<Compile Include="Traits\World\ChoosePaletteOnSelect.cs" />
<Compile Include="Traits\World\Country.cs" />
<Compile Include="Traits\World\CrateSpawner.cs" />
<Compile Include="Traits\Activities\Attack.cs" />
<Compile Include="Traits\Activities\CallFunc.cs" />
<Compile Include="Traits\Activities\EnterTransport.cs" />
<Compile Include="Traits\Activities\Fly.cs" />
<Compile Include="Traits\Activities\FlyAttack.cs" />
<Compile Include="Traits\Activities\FlyTimed.cs" />
<Compile Include="Traits\Activities\HeliAttack.cs" />
<Compile Include="Traits\Activities\HeliFly.cs" />
<Compile Include="Traits\Activities\HeliLand.cs" />
<Compile Include="Traits\Activities\HeliReturn.cs" />
<Compile Include="Traits\Activities\TransformIntoActor.cs" />
<Compile Include="Actor.cs" />
<Compile Include="Effects\Bullet.cs" />
@@ -169,11 +157,7 @@
<Compile Include="Graphics\LineRenderer.cs" />
<Compile Include="Graphics\WorldRenderer.cs" />
<Compile Include="Traits\Activities\Idle.cs" />
<Compile Include="Traits\Activities\Land.cs" />
<Compile Include="Traits\Activities\Rearm.cs" />
<Compile Include="Traits\Activities\RemoveSelf.cs" />
<Compile Include="Traits\Activities\Repair.cs" />
<Compile Include="Traits\Activities\ReturnToBase.cs" />
<Compile Include="Traits\Activities\Sell.cs" />
<Compile Include="Orders\IOrderGenerator.cs" />
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
@@ -194,83 +178,35 @@
<Compile Include="Graphics\Sprite.cs" />
<Compile Include="Graphics\SpriteRenderer.cs" />
<Compile Include="Graphics\SpriteSheetBuilder.cs" />
<Compile Include="GameRules\TerrainCost.cs" />
<Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Follow.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\Activities\UndeployMcv.cs" />
<Compile Include="Traits\Activities\UnloadCargo.cs" />
<Compile Include="Traits\Attack\AttackBase.cs" />
<Compile Include="Traits\Attack\AttackFrontal.cs" />
<Compile Include="Traits\Attack\AttackHeli.cs" />
<Compile Include="Traits\Attack\AttackInfo.cs" />
<Compile Include="Traits\Attack\AttackPlane.cs" />
<Compile Include="Traits\Attack\AttackTurreted.cs" />
<Compile Include="Traits\AI\AutoHeal.cs" />
<Compile Include="Traits\AI\AutoTarget.cs" />
<Compile Include="Traits\Modifiers\BelowUnits.cs" />
<Compile Include="Traits\Bridge.cs" />
<Compile Include="Traits\AttackBase.cs" />
<Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\World\BuildingInfluence.cs" />
<Compile Include="Traits\CanPowerDown.cs" />
<Compile Include="Traits\Cargo.cs" />
<Compile Include="Traits\Crate.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\Fake.cs" />
<Compile Include="Traits\GeneratesGap.cs" />
<Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\Modifiers\InvisibleToOthers.cs" />
<Compile Include="Traits\ConstructionYard.cs" />
<Compile Include="Traits\World\LightPaletteRotator.cs" />
<Compile Include="Traits\LimitedAmmo.cs" />
<Compile Include="Traits\World\PaletteFromFile.cs" />
<Compile Include="Traits\World\PaletteFromRGBA.cs" />
<Compile Include="Traits\Passenger.cs" />
<Compile Include="Traits\Player\PlaceBuilding.cs" />
<Compile Include="Traits\World\PlayerColorPalette.cs" />
<Compile Include="Traits\World\ResourceLayer.cs" />
<Compile Include="Traits\World\ResourceType.cs" />
<Compile Include="Traits\World\ShroudPalette.cs" />
<Compile Include="Traits\SupportPowers\SupportPower.cs" />
<Compile Include="Traits\SupportPower.cs" />
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="Traits\Repairable.cs" />
<Compile Include="Traits\Reservable.cs" />
<Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\AI\SelfHealing.cs" />
<Compile Include="Traits\SquishByTank.cs" />
<Compile Include="Traits\Plane.cs" />
<Compile Include="Traits\Player\ProductionQueue.cs" />
<Compile Include="Traits\ProductionSurround.cs" />
<Compile Include="Traits\Render\RenderBuildingCharge.cs" />
<Compile Include="Traits\Render\RenderInfantry.cs" />
<Compile Include="Traits\TransformsOnDeploy.cs" />
<Compile Include="Traits\Mobile.cs" />
<Compile Include="Traits\Production.cs" />
<Compile Include="Traits\RallyPoint.cs" />
<Compile Include="Traits\Render\RenderBuilding.cs" />
<Compile Include="Traits\Render\RenderBuildingOre.cs" />
<Compile Include="Traits\Render\RenderBuildingTurreted.cs" />
<Compile Include="Traits\Render\RenderBuildingWarFactory.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\Render\RenderUnit.cs" />
<Compile Include="Traits\Modifiers\WithMuzzleFlash.cs" />
<Compile Include="Traits\Render\RenderUnitReload.cs" />
<Compile Include="Traits\Render\RenderUnitRotor.cs" />
<Compile Include="Traits\Render\RenderUnitSpinner.cs" />
<Compile Include="Traits\Render\RenderUnitTurreted.cs" />
<Compile Include="Traits\SeedsResource.cs" />
<Compile Include="Traits\StoresOre.cs" />
<Compile Include="Traits\Submarine.cs" />
<Compile Include="Traits\AI\TakeCover.cs" />
<Compile Include="Traits\Cloak.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Turreted.cs" />
<Compile Include="Traits\Unit.cs" />
<Compile Include="Traits\World\SpawnMapActors.cs" />
<Compile Include="Traits\World\UnitInfluence.cs" />
<Compile Include="Traits\World\WaterPaletteRotation.cs" />
<Compile Include="Traits\Modifiers\WithShadow.cs" />
<Compile Include="Network\UnitOrders.cs" />
<Compile Include="Traits\Util.cs" />
<Compile Include="UiOverlay.cs" />
@@ -280,25 +216,16 @@
<Compile Include="Widgets\WorldTooltipWidget.cs" />
<Compile Include="World.cs" />
<Compile Include="WorldUtils.cs" />
<Compile Include="Traits\Wall.cs" />
<Compile Include="Traits\Render\RenderBuildingWall.cs" />
<Compile Include="Traits\Player\EvaAlerts.cs" />
<Compile Include="Traits\World\ScreenShaker.cs" />
<Compile Include="Traits\LineBuild.cs" />
<Compile Include="Traits\World\Theater.cs" />
<Compile Include="Traits\Cloak.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="Traits\HasUnitOnBuild.cs" />
<Compile Include="Traits\Activities\Wait.cs" />
<Compile Include="Traits\CrateAction.cs" />
<Compile Include="Effects\CrateEffect.cs" />
<Compile Include="Traits\World\GlobalDefaults.cs" />
<Compile Include="Traits\RepairsUnits.cs" />
<Compile Include="Traits\World\BibLayer.cs" />
<Compile Include="Traits\World\SmudgeLayer.cs" />
<Compile Include="Widgets\Delegates\IngameChromeDelegate.cs" />
@@ -307,9 +234,15 @@
<Compile Include="Widgets\PerfGraphWidget.cs" />
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
<Compile Include="Widgets\BuildPaletteWidget.cs" />
<Compile Include="Traits\World\BridgeLayer.cs" />
<Compile Include="Widgets\Delegates\LobbyDelegate.cs" />
<Compile Include="Widgets\ColorBlockWidget.cs" />
<Compile Include="GameRules\MusicInfo.cs" />
<Compile Include="Widgets\PowerBinWidget.cs" />
<Compile Include="Widgets\ImageWidget.cs" />
<Compile Include="Traits\SharesCell.cs" />
<Compile Include="Traits\World\AircraftInfluence.cs" />
<Compile Include="Traits\World\HazardLayer.cs" />
<Compile Include="Traits\Hazardous.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -22,7 +22,6 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Support;
namespace OpenRA.Orders
{
@@ -30,12 +29,18 @@ namespace OpenRA.Orders
{
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
{
foreach( var unit in Game.controller.selection.Actors )
{
var ret = unit.Order( xy, mi );
if( ret != null )
yield return ret;
}
var orders = Game.controller.selection.Actors
.Select(a => a.Order(xy, mi))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.Subject).Distinct();
if (actorsInvolved.Any())
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
foreach (var o in orders)
yield return o;
}
public void Tick( World world ) {}
@@ -45,8 +50,16 @@ namespace OpenRA.Orders
foreach (var a in Game.controller.selection.Actors)
{
world.WorldRenderer.DrawSelectionBox(a, Color.White, true);
if (a.traits.Contains<RenderRangeCircle>())
world.WorldRenderer.DrawRangeCircle(a);
if (a.Owner == world.LocalPlayer)
{
if (a.traits.Contains<RenderRangeCircle>())
world.WorldRenderer.DrawRangeCircle(Color.FromArgb(128, Color.Yellow),
a.CenterLocation, (int)a.GetPrimaryWeapon().Range);
if (a.traits.Contains<DetectCloaked>())
world.WorldRenderer.DrawRangeCircle(Color.FromArgb(128, Color.LimeGreen),
a.CenterLocation, a.Info.Traits.Get<DetectCloakedInfo>().Range);
}
}
}
@@ -79,7 +92,7 @@ namespace OpenRA.Orders
case "Heal": return "heal";
case "C4": return "c4";
case "Move":
if (a.traits.GetOrDefault<IMovement>().CanEnterCell(location))
if (a.traits.GetOrDefault<IMove>().CanEnterCell(location))
return "move";
else
return "move-blocked";
@@ -102,6 +115,7 @@ namespace OpenRA.Orders
case "Capture": return "capture";
case "Harvest": return "attackmove";
case "Steal" : return "enter";
case "BeginMinefield": return "ability";
default:
return null;
}

View File

@@ -31,82 +31,73 @@ namespace OpenRA
public class PathFinder
{
readonly World world;
float[][,] passableCost = new float[4][,];
public PathFinder( World world )
{
this.world = world;
var map = world.Map;
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++)
passableCost[(int)umt] = new float[map.MapSize.X, map.MapSize.Y];
for( int x = 0 ; x < map.MapSize.X ; x++ )
for( int y = 0 ; y < map.MapSize.Y ; y++ )
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ )
passableCost[(int)umt][ x, y ] = ( world.Map.IsInMap( x, y ) )
? (float)Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[x, y])]
.GetCost(umt)
: float.PositiveInfinity;
}
class CachedPath
{
public int2 from;
public int2 to;
public UnitMovementType umt;
public List<int2> result;
public int tick;
public Actor actor;
}
List<CachedPath> CachedPaths = new List<CachedPath>();
const int MaxPathAge = 50; /* x 40ms ticks */
public List<int2> FindUnitPath(int2 from, int2 target, UnitMovementType umt)
public List<int2> FindUnitPath(int2 from, int2 target, Actor self)
{
using (new PerfSample("find_unit_path"))
{
var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.umt == umt);
var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self);
if (cached != null)
{
Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, Game.LocalTick - cached.tick);
cached.tick = Game.LocalTick;
return new List<int2>(cached.result);
}
var pb = FindBidiPath(
PathSearch.FromPoint(world, target, from, umt, true)
.WithCustomBlocker(AvoidUnitsNear(from, 4)),
PathSearch.FromPoint(world, from, target, umt, true)
.WithCustomBlocker(AvoidUnitsNear(from, 4))
PathSearch.FromPoint(self, target, from, true)
.WithCustomBlocker(AvoidUnitsNear(from, 4, self)),
PathSearch.FromPoint(self, from, target, true)
.WithCustomBlocker(AvoidUnitsNear(from, 4, self))
.InReverse());
CheckSanePath2(pb, from, target);
CachedPaths.RemoveAll(p => Game.LocalTick - p.tick > MaxPathAge);
CachedPaths.Add(new CachedPath { from = from, to = target, umt = umt, result = pb, tick = Game.LocalTick });
CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = Game.LocalTick });
return new List<int2>(pb);
}
}
public List<int2> FindUnitPathToRange( int2 src, int2 target, UnitMovementType umt, int range )
public List<int2> FindUnitPathToRange( int2 src, int2 target, int range, Actor self )
{
using( new PerfSample( "find_unit_path_multiple_src" ) )
{
var mobile = self.traits.Get<Mobile>();
var tilesInRange = world.FindTilesInCircle(target, range)
.Where( t => world.IsPathableCell( t, umt ) );
.Where( t => mobile.CanEnterCell(t));
var path = FindPath( PathSearch.FromPoints( world, tilesInRange, src, umt, false )
.WithCustomBlocker(AvoidUnitsNear(src, 4))
var path = FindPath( PathSearch.FromPoints( self, tilesInRange, src, false )
.WithCustomBlocker(AvoidUnitsNear(src, 4, self))
.InReverse());
path.Reverse();
return path;
}
}
public Func<int2, bool> AvoidUnitsNear(int2 p, int dist)
public Func<int2, bool> AvoidUnitsNear(int2 p, int dist, Actor self)
{
return q =>
p != q &&
((p - q).LengthSquared < dist * dist) &&
(world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(q).Any());
(world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(q).Any(a => a.Group != self.Group));
}
public List<int2> FindPath( PathSearch search )
@@ -115,7 +106,7 @@ namespace OpenRA
{
while (!search.queue.Empty)
{
var p = search.Expand( world, passableCost );
var p = search.Expand( world );
PerfHistory.Increment("nodes_expanded", .01);
if (search.heuristic(p) == 0)
@@ -152,13 +143,13 @@ namespace OpenRA
while (!fromSrc.queue.Empty && !fromDest.queue.Empty)
{
/* make some progress on the first search */
var p = fromSrc.Expand( world, passableCost );
var p = fromSrc.Expand( world );
if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity)
return MakeBidiPath(fromSrc, fromDest, p);
/* make some progress on the second search */
var q = fromDest.Expand( world, passableCost );
var q = fromDest.Expand( world );
if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity)
return MakeBidiPath(fromSrc, fromDest, q);

View File

@@ -30,28 +30,21 @@ namespace OpenRA
public class PathSearch
{
World world;
ResourceLayer resources;
public CellInfo[ , ] cellInfo;
public PriorityQueue<PathDistance> queue;
public Func<int2, float> heuristic;
public UnitMovementType umt;
Func<int2, bool> customBlock;
public bool checkForBlocked;
public Actor ignoreBuilding;
Actor self;
public bool inReverse;
BuildingInfluence buildingInfluence;
UnitInfluence unitInfluence;
public PathSearch(World world)
public PathSearch(Actor self)
{
this.world = world;
this.self = self;
world = self.World;
cellInfo = InitCellInfo();
queue = new PriorityQueue<PathDistance>();
buildingInfluence = world.WorldActor.traits.Get<BuildingInfluence>();
unitInfluence = world.WorldActor.traits.Get<UnitInfluence>();
resources = world.WorldActor.traits.Get<ResourceLayer>();
}
public PathSearch InReverse()
@@ -72,16 +65,28 @@ namespace OpenRA
return this;
}
public PathSearch WithHeuristic(Func<int2, float> h)
{
heuristic = h;
return this;
}
public PathSearch FromPoint(int2 from)
{
AddInitialCell( self.World, from );
return this;
}
const float LaneBias = .5f;
public int2 Expand( World world, float[][ , ] passableCost )
public int2 Expand( World world )
{
var p = queue.Pop();
cellInfo[ p.Location.X, p.Location.Y ].Seen = true;
var thisCost = passableCost[(int)umt][p.Location.X, p.Location.Y]*
world.WorldActor.traits.WithInterface<ICustomTerrain>().Aggregate(1f, (a, x) => a * x.GetCost(p.Location,umt));
var mobile = self.traits.Get<Mobile>();
var thisCost = mobile.MovementCostForCell(self, p.Location);
if (thisCost == float.PositiveInfinity)
return p.Location;
@@ -93,18 +98,12 @@ namespace OpenRA
if( cellInfo[ newHere.X, newHere.Y ].Seen )
continue;
var costHere = passableCost[(int)umt][newHere.X, newHere.Y]*
world.WorldActor.traits.WithInterface<ICustomTerrain>()
.Aggregate(1f, (a, x) => a * x.GetCost(newHere,umt));
var costHere = mobile.MovementCostForCell(self, newHere);
if (costHere == float.PositiveInfinity)
continue;
if (!buildingInfluence.CanMoveHere(newHere, ignoreBuilding))
continue;
// Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units
if (checkForBlocked && (unitInfluence.GetUnitsAt(newHere).Any(a => !world.IsActorPathableToCrush(a, umt))))
if (checkForBlocked && !mobile.CanEnterCell(newHere, ignoreBuilding, checkForBlocked))
continue;
if (customBlock != null && customBlock(newHere))
@@ -159,29 +158,34 @@ namespace OpenRA
cellInfo[ location.X, location.Y ] = new CellInfo( 0, location, false );
queue.Add( new PathDistance( heuristic( location ), location ) );
}
public static PathSearch FromPoint( World world, int2 from, int2 target, UnitMovementType umt, bool checkForBlocked )
public static PathSearch Search( Actor self, bool checkForBlocked )
{
var search = new PathSearch(world) {
var search = new PathSearch(self) {
checkForBlocked = checkForBlocked };
return search;
}
public static PathSearch FromPoint( Actor self, int2 from, int2 target, bool checkForBlocked )
{
var search = new PathSearch(self) {
heuristic = DefaultEstimator( target ),
umt = umt,
checkForBlocked = checkForBlocked };
search.AddInitialCell( world, from );
search.AddInitialCell( self.World, from );
return search;
}
public static PathSearch FromPoints(World world, IEnumerable<int2> froms, int2 target, UnitMovementType umt, bool checkForBlocked)
public static PathSearch FromPoints(Actor self, IEnumerable<int2> froms, int2 target, bool checkForBlocked)
{
var search = new PathSearch(world)
var search = new PathSearch(self)
{
heuristic = DefaultEstimator(target),
umt = umt,
checkForBlocked = checkForBlocked
};
foreach (var sl in froms)
search.AddInitialCell(world, sl);
search.AddInitialCell(self.World, sl);
return search;
}

View File

@@ -1,197 +1,91 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public enum PowerState { Normal, Low, Critical };
public class Player
{
public Actor PlayerActor;
public int Kills;
public readonly string Palette;
public readonly Color Color;
public readonly string PlayerName;
public readonly string InternalName;
public readonly CountryInfo Country;
public readonly int Index;
public int Cash = 10000;
public int Ore = 0;
public int OreCapacity;
public int DisplayCash = 0;
public int PowerProvided = 0;
public int PowerDrained = 0;
public ShroudRenderer Shroud;
public World World { get; private set; }
public static List<Tuple<string, string, Color>> PlayerColors( World world )
{
return world.WorldActor.Info.Traits.WithInterface<PlayerColorPaletteInfo>()
.Where(p => p.Playable)
.Select(p => Tuple.New(p.Name, p.DisplayName, p.Color))
.ToList();
}
public Player( World world, Session.Client client )
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
if (client != null)
{
Index = client.Index;
Palette = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].a;
Color = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].c;
PlayerName = client.Name;
InternalName = "Multi{0}".F(client.Index);
}
else
{
Index = -1;
PlayerName = InternalName = "Neutral";
Palette = "neutral";
Color = Color.Gray; // HACK HACK
}
Country = world.GetCountries()
.FirstOrDefault(c => client != null && client.Country == c.Name)
?? world.GetCountries().Random(world.SharedRandom);
}
void UpdatePower()
{
var oldBalance = PowerProvided - PowerDrained;
PowerProvided = 0;
PowerDrained = 0;
var myBuildings = World.Queries.OwnedBy[this]
.WithTrait<Building>();
foreach (var a in myBuildings)
{
var p = a.Trait.GetPowerUsage();
if (p > 0)
PowerProvided += p;
else
PowerDrained -= p;
}
if (PowerProvided - PowerDrained < 0)
if (PowerProvided - PowerDrained != oldBalance)
GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().LowPower);
}
public float GetSiloFullness()
{
return (float)Ore / OreCapacity;
}
public PowerState GetPowerState()
{
if (PowerProvided >= PowerDrained) return PowerState.Normal;
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
return PowerState.Critical;
}
void UpdateOreCapacity()
{
OreCapacity = World.Queries.OwnedBy[this]
.Where(a => a.traits.Contains<StoresOre>())
.Select(a => a.Info.Traits.Get<StoresOreInfo>())
.Sum(b => b.Capacity);
}
void GiveAdvice(string advice)
{
// todo: store the condition or something.
// repeat after World.Defaults.SpeakDelay, as long as the condition holds.
Sound.PlayToPlayer(this, advice);
}
public void GiveCash( int num ) { Cash += num; }
public void GiveOre(int num)
{
Ore += num;
if (Ore > OreCapacity)
Ore = OreCapacity; // trim off the overflow.
if (Ore > .8 * OreCapacity)
GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().SilosNeeded);
}
public bool TakeCash( int num )
{
if (Cash + Ore < num) return false;
if (Ore <= num)
{
num -= Ore;
Ore = 0;
Cash -= num;
}
else
Ore -= num;
return true;
}
const float displayCashFracPerFrame = .07f;
const int displayCashDeltaPerFrame = 37;
public void Tick()
{
UpdatePower();
UpdateOreCapacity();
var totalMoney = Cash + Ore;
var diff = Math.Abs(totalMoney - DisplayCash);
var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame),
displayCashDeltaPerFrame), diff);
var eva = World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if (DisplayCash < totalMoney)
{
DisplayCash += move;
Sound.PlayToPlayer(this, eva.CashTickUp);
}
else if (DisplayCash > totalMoney)
{
DisplayCash -= move;
Sound.PlayToPlayer(this, eva.CashTickDown);
}
}
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
}
}
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public enum PowerState { Normal, Low, Critical };
public class Player
{
public Actor PlayerActor;
public int Kills;
public int Deaths;
public readonly string Palette;
public readonly Color Color;
public readonly string PlayerName;
public readonly string InternalName;
public readonly CountryInfo Country;
public readonly int Index;
public readonly bool NonCombatant = false;
public ShroudRenderer Shroud;
public World World { get; private set; }
public Player( World world, PlayerReference pr, int index )
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
Index = index;
Palette = pr.Palette;
Color = world.PlayerColors().Where(c => c.Name == pr.Palette).FirstOrDefault().Color;
PlayerName = InternalName = pr.Name;
NonCombatant = pr.NonCombatant;
Country = world.GetCountries()
.FirstOrDefault(c => pr.Race == c.Race);
}
public Player( World world, Session.Client client )
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
Index = client.Index;
Palette = world.PlayerColors()[client.PaletteIndex % world.PlayerColors().Count()].Name;
Color = world.PlayerColors()[client.PaletteIndex % world.PlayerColors().Count()].Color;
PlayerName = client.Name;
InternalName = "Multi{0}".F(client.Index);
Country = world.GetCountries()
.FirstOrDefault(c => client != null && client.Country == c.Race)
?? world.GetCountries().Random(world.SharedRandom);
}
public void GiveAdvice(string advice)
{
// todo: store the condition or something.
// repeat after World.Defaults.SpeakDelay, as long as the condition holds.
Sound.PlayToPlayer(this, advice);
}
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
}
}

View File

@@ -48,6 +48,7 @@ namespace OpenRA.Server
class GameServer
{
public readonly int Id = 0;
public readonly string Name = null;
public readonly string Address = null;
public readonly int State = 0;

View File

@@ -28,6 +28,7 @@ using System.Net.Sockets;
using System.Security.Cryptography;
using System.Threading;
using OpenRA.FileFormats;
using System.Text;
namespace OpenRA.Server
{
@@ -53,9 +54,11 @@ namespace OpenRA.Server
static int lastPing = 0;
static bool isInternetServer;
static string masterServerUrl;
static bool isInitialPing;
public static void ServerMain(bool internetServer, string masterServerUrl, string name, int port, int extport, string[] mods, string map)
{
isInitialPing = true;
Server.masterServerUrl = masterServerUrl;
isInternetServer = internetServer;
listener = new TcpListener(IPAddress.Any, port);
@@ -92,7 +95,6 @@ namespace OpenRA.Server
checkRead.Add( listener.Server );
foreach( var c in conns ) checkRead.Add( c.socket );
/* msdn lies, -1 doesnt work. this is ~1h instead. */
Socket.Select( checkRead, null, null, MasterPingInterval * 1000000 );
foreach( Socket s in checkRead )
@@ -148,7 +150,7 @@ namespace OpenRA.Server
Index = newConn.PlayerIndex,
PaletteIndex = ChooseFreePalette(),
Name = "Player {0}".F(1 + newConn.PlayerIndex),
Country = "Random",
Country = "random",
State = Session.ClientState.NotReady,
SpawnPoint = 0,
Team = 0,
@@ -221,6 +223,7 @@ namespace OpenRA.Server
}
}
catch (EndOfStreamException) { }
catch (NotImplementedException) { }
}
static bool InterpretCommand(Connection conn, string cmd)
@@ -262,18 +265,17 @@ namespace OpenRA.Server
}},
{ "name",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change your name after the game has started" );
return true;
}
{
if (s.Trim() == "")
{
SendChatTo( conn, "Blank names are not permitted." );
return true;
}
if (s.Length > 10)
{
s = s.Substring(0,10);
}
Console.WriteLine("Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
GetClient(conn).Name = s;
@@ -294,13 +296,7 @@ namespace OpenRA.Server
}},
{ "race",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change your race after the game has started" );
return true;
}
{
GetClient(conn).Country = s;
SyncLobbyInfo();
return true;
@@ -308,12 +304,6 @@ namespace OpenRA.Server
{ "team",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change your team after the game has started" );
return true;
}
int team;
if (!int.TryParse(s, out team)) { Console.WriteLine("Invalid team: {0}", s ); return false; }
@@ -324,12 +314,6 @@ namespace OpenRA.Server
{ "spawn",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change your spawn point after the game has started" );
return true;
}
int spawnPoint;
if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > 8) //TODO: SET properly!
{
@@ -350,11 +334,6 @@ namespace OpenRA.Server
{ "pal",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change your color after the game has started" );
return true;
}
int pali;
if (!int.TryParse(s, out pali))
@@ -381,16 +360,12 @@ namespace OpenRA.Server
SendChatTo( conn, "Only the host can change the map" );
return true;
}
if (GameStarted)
{
SendChatTo( conn, "You can't change the map after the game has started" );
return true;
}
lobbyInfo.GlobalSettings.Map = s;
foreach(var client in lobbyInfo.Clients)
{
client.SpawnPoint = 0;
client.State = Session.ClientState.NotReady;
}
SyncLobbyInfo();
return true;
@@ -398,12 +373,6 @@ namespace OpenRA.Server
{ "addpkg",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change packages after the game has started" );
return true;
}
Console.WriteLine("** Added package: `{0}`", s);
try
{
@@ -423,11 +392,6 @@ namespace OpenRA.Server
{ "mods",
s =>
{
if (GameStarted)
{
SendChatTo( conn, "You can't change mods after the game has started" );
return true;
}
var args = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
lobbyInfo.GlobalSettings.Mods = args.GetRange(0,args.Count - 1).ToArray();
lobbyInfo.GlobalSettings.Map = args.Last();
@@ -463,20 +427,35 @@ namespace OpenRA.Server
switch (so.Name)
{
case "Chat":
if (so.Data.StartsWith("/"))
{
if (!InterpretCommand(conn, so.Data.Substring(1)))
{
Console.WriteLine("Bad server command: {0}", so.Data.Substring(1));
SendChatTo(conn, "Bad server command.");
}
}
else
if (!HandleAsCommand(conn, so))
foreach (var c in conns.Except(conn).ToArray())
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
break;
//TODO: send to those with the same team
case "TeamChat":
if (!HandleAsCommand(conn, so))
foreach (var c in conns.Except(conn).ToArray())
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
break;
}
}
static bool HandleAsCommand(Connection conn, ServerOrder so)
{
if (!so.Data.StartsWith("/")) return false;
var cmd = so.Data.Substring(1);
if(GameStarted)
SendChatTo(conn, "Cannot change state when game started.");
else if (GetClient(conn).State == Session.ClientState.Ready && cmd != "ready")
SendChatTo(conn, "Cannot change state when marked as ready.");
else if (!InterpretCommand(conn, cmd))
{
Console.WriteLine("Bad server command: {0}", cmd);
SendChatTo(conn, "Bad server command.");
}
return true;
}
static Session.Client GetClient(Connection conn)
{
@@ -538,8 +517,18 @@ namespace OpenRA.Server
{
if (wc.IsBusy || !isInternetServer) return;
var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}";
wc.DownloadDataCompleted += PingMasterServerResponse;
if (isInitialPing)
{
url += "&new=1";
isInitialPing = false;
}
else
wc.DownloadDataCompleted -= PingMasterServerResponse;
wc.DownloadDataAsync(new Uri(
masterServerUrl + "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}".F(
masterServerUrl + url.F(
ExternalPort, Uri.EscapeUriString(Name),
GameStarted ? 2 : 1, // todo: post-game states, etc.
lobbyInfo.Clients.Count,
@@ -548,5 +537,14 @@ namespace OpenRA.Server
lastPing = Environment.TickCount;
}
static void PingMasterServerResponse(object sender, DownloadDataCompletedEventArgs e)
{
string s = Encoding.UTF8.GetString(e.Result);
int gameId;
if (int.TryParse(s.Trim(), out gameId))
Game.SetGameId(gameId);
Log.Write("debug", "Game ID: {0}", gameId);
}
}
}

View File

@@ -21,7 +21,6 @@
using System;
using System.Collections.Generic;
using OpenRA.FileFormats;
using OpenRA.Support;
using OpenRA.Traits;
using Tao.OpenAl;
@@ -58,14 +57,24 @@ namespace OpenRA
stopped = false;
}
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
public static void Play(string name)
{
if (name == "" || name == null)
return;
var sound = sounds[name];
soundEngine.Play2D(sound, false, true, float2.Zero);
}
public static void Play(string name, float2 pos)
{
if (name == "" || name == null)
return;
var sound = sounds[name];
// todo: positioning
soundEngine.Play2D(sound, false);
soundEngine.Play2D(sound, false, false, pos);
}
public static void PlayToPlayer(Player player, string name)
@@ -74,13 +83,22 @@ namespace OpenRA
Play( name );
}
public static void PlayToPlayer(Player player, string name, float2 pos)
{
if (player == player.World.LocalPlayer)
Play(name, pos);
}
public static void PlayMusic(string name)
{
if (name == "" || name == null)
return;
if (music != null)
soundEngine.StopSound(music);
var sound = sounds[name];
music = soundEngine.Play2D(sound, true);
music = soundEngine.Play2D(sound, true, true, float2.Zero);
music.Volume = musicVolume;
}
@@ -157,12 +175,13 @@ namespace OpenRA
interface ISoundEngine
{
ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate);
ISound Play2D(ISoundSource sound, bool loop);
ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos);
float Volume { get; set; }
void PauseSound(ISound sound, bool paused);
void StopSound(ISound sound);
void SetAllSoundsPaused(bool paused);
void StopAllSounds();
void SetListenerPosition(float2 position);
}
interface ISoundSource {}
@@ -194,7 +213,7 @@ namespace OpenRA
Al.alGenSources(1, out source);
if (0 != Al.alGetError())
{
Log.Write("Failed generating OpenAL source {0}", i);
Log.Write("debug", "Failed generating OpenAL source {0}", i);
return;
}
@@ -238,10 +257,10 @@ namespace OpenRA
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
}
public ISound Play2D(ISoundSource sound, bool loop)
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos)
{
int source = GetSourceFromPool();
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop);
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos);
}
public float Volume
@@ -294,7 +313,15 @@ namespace OpenRA
Al.alSourceStop(key);
}
}
public void SetListenerPosition(float2 position)
{
var orientation = new [] { 0f, 0f, 1f, 0f, -1f, 0f };
Al.alListener3f(Al.AL_POSITION, position.X, position.Y, 50);
Al.alListenerfv(Al.AL_ORIENTATION, ref orientation[0]);
Al.alListenerf(Al.AL_METERS_PER_UNIT, .01f);
}
}
class OpenAlSoundSource : ISoundSource
@@ -321,16 +348,20 @@ namespace OpenRA
public readonly int source = -1;
float volume = 1f;
public OpenAlSound(int source, int buffer, bool looping)
public OpenAlSound(int source, int buffer, bool looping, bool relative, float2 pos)
{
if (source == -1) return;
this.source = source;
Al.alSourcef(source, Al.AL_PITCH, 1f);
Al.alSourcef(source, Al.AL_GAIN, 1f);
Al.alSource3f(source, Al.AL_POSITION, 0f, 0f, 0f);
Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f);
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
Al.alSourcei(source, Al.AL_BUFFER, buffer);
Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE);
Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0);
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200);
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500);
Al.alSourcePlay(source);
}

View File

@@ -22,6 +22,7 @@ using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using System.Linq;
namespace OpenRA
{
@@ -32,10 +33,11 @@ namespace OpenRA
{
// brutal hack
Application.CurrentCulture = CultureInfo.InvariantCulture;
Log.AddChannel("perf", "openra.perf.txt", false, false);
if( Debugger.IsAttached )
if (Debugger.IsAttached || args.Contains("--just-die"))
{
Run( args );
Run(args);
return;
}
@@ -45,7 +47,9 @@ namespace OpenRA
}
catch( Exception e )
{
Log.Write( "{0}", e.ToString() );
Log.AddChannel("exception", "openra.exception.txt", true, false);
Log.Write("exception", "{0}", e.ToString());
Log.Upload(Game.GetGameId());
throw;
}
}

View File

@@ -37,62 +37,80 @@ namespace OpenRA
return hashFuncCache[ obj.GetType() ]( obj );
}
public static Func<object,int> GenerateHashFunc( Type t )
static void EmitSyncOpcodes(Type type, ILGenerator il)
{
var d = new DynamicMethod( "hash_{0}".F( t.Name ), typeof( int ), new Type[] { typeof( object ) }, t );
if (type == typeof(int))
{
il.Emit(OpCodes.Xor);
}
else if (type == typeof(bool))
{
var l = il.DefineLabel();
il.Emit(OpCodes.Ldc_I4, 0xaaa);
il.Emit(OpCodes.Brtrue, l);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldc_I4, 0x555);
il.MarkLabel(l);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(int2))
{
il.EmitCall(OpCodes.Call, ((Func<int2, int>)hash_int2).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(TypeDictionary))
{
il.EmitCall(OpCodes.Call, ((Func<TypeDictionary, int>)hash_tdict).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(Actor))
{
il.EmitCall(OpCodes.Call, ((Func<Actor, int>)hash_actor).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(Player))
{
il.EmitCall(OpCodes.Call, ((Func<Player, int>)hash_player).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type.HasAttribute<SyncAttribute>())
{
il.EmitCall(OpCodes.Call, ((Func<object, int>)CalculateSyncHash).Method, null);
il.Emit(OpCodes.Xor);
}
else
throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName));
}
public static Func<object, int> GenerateHashFunc(Type t)
{
var d = new DynamicMethod("hash_{0}".F(t.Name), typeof(int), new Type[] { typeof(object) }, t);
var il = d.GetILGenerator();
var this_ = il.DeclareLocal( t ).LocalIndex;
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Castclass, t );
il.Emit( OpCodes.Stloc, this_ );
il.Emit( OpCodes.Ldc_I4_0 );
var this_ = il.DeclareLocal(t).LocalIndex;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, t);
il.Emit(OpCodes.Stloc, this_);
il.Emit(OpCodes.Ldc_I4_0);
const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
foreach( var field in t.GetFields( bf ).Where( x => x.GetCustomAttributes( typeof( SyncAttribute ), true ).Length != 0 ) )
foreach (var field in t.GetFields(bf).Where(x => x.HasAttribute<SyncAttribute>()))
{
il.Emit( OpCodes.Ldloc, this_ );
il.Emit( OpCodes.Ldfld, field );
il.Emit(OpCodes.Ldloc, this_);
il.Emit(OpCodes.Ldfld, field);
if( field.FieldType == typeof( int ) )
{
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( bool ) )
{
var l = il.DefineLabel();
il.Emit( OpCodes.Ldc_I4, 0xaaa );
il.Emit( OpCodes.Brtrue, l );
il.Emit( OpCodes.Pop );
il.Emit( OpCodes.Ldc_I4, 0x555 );
il.MarkLabel( l );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( int2 ) )
{
il.EmitCall( OpCodes.Call, ( (Func<int2, int>)hash_int2 ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( TypeDictionary ) )
{
il.EmitCall( OpCodes.Call, ( (Func<TypeDictionary, int>)hash_tdict ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( Actor ) )
{
il.EmitCall( OpCodes.Call, ( (Func<Actor, int>)hash_actor ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( Player ) )
{
il.EmitCall( OpCodes.Call, ( (Func<Player, int>)hash_player ).Method, null );
il.Emit( OpCodes.Xor );
}
else
throw new NotImplementedException( "SyncAttribute on unhashable field" );
EmitSyncOpcodes(field.FieldType, il);
}
il.Emit( OpCodes.Ret );
return (Func<object,int>)d.CreateDelegate( typeof( Func<object,int> ) );
foreach (var prop in t.GetProperties(bf).Where(x => x.HasAttribute<SyncAttribute>()))
{
il.Emit(OpCodes.Ldloc, this_);
il.EmitCall(OpCodes.Call, prop.GetGetMethod(), null);
EmitSyncOpcodes(prop.PropertyType, il);
}
il.Emit(OpCodes.Ret);
return (Func<object, int>)d.CreateDelegate(typeof(Func<object, int>));
}
public static int hash_int2( int2 i2 )
@@ -121,5 +139,10 @@ namespace OpenRA
return p.Index * 0x567;
return 0;
}
static bool HasAttribute<T>( this MemberInfo mi )
{
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
}
}
}

View File

@@ -21,7 +21,7 @@
namespace OpenRA.Traits.Activities
{
/* non-turreted attack */
class Attack : IActivity
public class Attack : IActivity
{
Actor Target;
int Range;

View File

@@ -22,8 +22,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Drawing;
using OpenRA.GameRules;
namespace OpenRA.Traits.Activities
{
@@ -34,7 +32,7 @@ namespace OpenRA.Traits.Activities
int2? destination;
int nearEnough;
public List<int2> path;
Func<Actor, Mobile, List<int2>> getPath;
Func<Actor, List<int2>> getPath;
public Actor ignoreBuilding;
MovePart move;
@@ -52,9 +50,8 @@ namespace OpenRA.Traits.Activities
public Move( int2 destination, int nearEnough )
: this()
{
this.getPath = ( self, mobile ) => self.World.PathFinder.FindUnitPath(
self.Location, destination,
mobile.GetMovementType() );
this.getPath = self => self.World.PathFinder.FindUnitPath(
self.Location, destination, self );
this.destination = destination;
this.nearEnough = nearEnough;
}
@@ -62,10 +59,10 @@ namespace OpenRA.Traits.Activities
public Move(int2 destination, Actor ignoreBuilding)
: this()
{
this.getPath = (self, mobile) =>
this.getPath = self =>
self.World.PathFinder.FindPath(
PathSearch.FromPoint( self.World, self.Location, destination, mobile.GetMovementType(), false )
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( self.Location, 4 ))
PathSearch.FromPoint( self, self.Location, destination, false )
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( self.Location, 4, self ))
.WithIgnoredBuilding( ignoreBuilding ));
this.destination = destination;
@@ -76,9 +73,9 @@ namespace OpenRA.Traits.Activities
public Move( Actor target, int range )
: this()
{
this.getPath = ( self, mobile ) => self.World.PathFinder.FindUnitPathToRange(
this.getPath = self => self.World.PathFinder.FindUnitPathToRange(
self.Location, target.Location,
mobile.GetMovementType(), range );
range, self );
this.destination = null;
this.nearEnough = range;
}
@@ -86,22 +83,11 @@ namespace OpenRA.Traits.Activities
public Move(Func<List<int2>> getPath)
: this()
{
this.getPath = (_, _2) => getPath();
this.getPath = _ => getPath();
this.destination = null;
this.nearEnough = 0;
}
bool CanEnterCell( int2 c, Actor self )
{
if (!self.World.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(c)
&& self.World.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(c) != ignoreBuilding)
return false;
// Cannot enter a cell if any unit inside is uncrushable
// This will need to be updated for multiple-infantry-in-a-cell
return (!self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(c).Any(a => a != self && !self.World.IsActorCrushableByActor(a, self)));
}
public IActivity Tick( Actor self )
{
var unit = self.traits.Get<Unit>();
@@ -124,7 +110,7 @@ namespace OpenRA.Traits.Activities
return this;
}
path = getPath( self, mobile ).TakeWhile( a => a != self.Location ).ToList();
path = getPath( self ).TakeWhile( a => a != self.Location ).ToList();
SanityCheckPath( mobile );
}
@@ -181,7 +167,7 @@ namespace OpenRA.Traits.Activities
{
if( path.Count == 0 ) return null;
var nextCell = path[ path.Count - 1 ];
if( !CanEnterCell( nextCell, self ) )
if( !mobile.CanEnterCell( nextCell, ignoreBuilding, true ) )
{
if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough )
{
@@ -199,10 +185,13 @@ namespace OpenRA.Traits.Activities
if (--waitTicksRemaining >= 0)
return null;
self.World.WorldActor.traits.Get<UnitInfluence>().Remove( self, mobile );
var newPath = getPath(self, mobile).TakeWhile(a => a != self.Location).ToList();
//self.World.WorldActor.traits.Get<UnitInfluence>().Remove( self, mobile );
mobile.RemoveInfluence();
var newPath = getPath(self).TakeWhile(a => a != self.Location).ToList();
self.World.WorldActor.traits.Get<UnitInfluence>().Add( self, mobile );
//self.World.WorldActor.traits.Get<UnitInfluence>().Add( self, mobile );
mobile.AddInfluence();
if (newPath.Count != 0)
path = newPath;
@@ -238,8 +227,7 @@ namespace OpenRA.Traits.Activities
public void TickMove( Actor self, Mobile mobile, Move parent )
{
var umt = self.Info.Traits.Get<MobileInfo>().MovementType;
moveFraction += (int)Util.GetEffectiveSpeed(self, umt);
moveFraction += (int)mobile.MovementSpeedForCell(self, self.Location);
if( moveFraction >= moveFractionTotal )
moveFraction = moveFractionTotal;
UpdateCenterLocation( self, mobile );
@@ -257,6 +245,7 @@ namespace OpenRA.Traits.Activities
var frac = (float)moveFraction / moveFractionTotal;
self.CenterLocation = float2.Lerp( from, to, frac );
if( moveFraction >= moveFractionTotal )
unit.Facing = toFacing & 0xFF;
else
@@ -317,6 +306,7 @@ namespace OpenRA.Traits.Activities
{
self.CenterLocation = Util.CenterOfCell( mobile.toCell );
mobile.fromCell = mobile.toCell;
mobile.FinishedMoving(self);
return null;
}
}

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Traits.Activities
var hp = self.Info.Traits.Get<OwnedActorInfo>().HP;
var refund = self.World.Defaults.RefundPercent * self.Health * cost / hp;
self.Owner.GiveCash((int)refund);
self.Owner.PlayerActor.traits.Get<PlayerResources>().GiveCash((int)refund);
self.Health = 0;
foreach (var ns in self.traits.WithInterface<INotifySold>())
ns.Sold(self);
@@ -48,7 +48,9 @@ namespace OpenRA.Traits.Activities
{
if( !started )
{
framesRemaining = (self.Info.Traits.Get<RenderBuildingInfo>().HasMakeAnimation) ? self.traits.Get<RenderSimple>().anim.GetSequence( "make" ).Length : 0;
framesRemaining = self.traits.Get<RenderSimple>().anim.HasSequence("make")
? self.traits.Get<RenderSimple>().anim.GetSequence( "make" ).Length : 0;
foreach( var ns in self.traits.WithInterface<INotifySold>() )
ns.Selling( self );

View File

@@ -54,7 +54,7 @@ namespace OpenRA.Traits.Activities
self.Health = 0;
self.World.Remove( self );
foreach (var s in sounds)
Sound.PlayToPlayer(self.Owner, s);
Sound.PlayToPlayer(self.Owner, s, self.CenterLocation);
var a = self.World.CreateActor( actor, self.Location + offset, self.Owner );
a.Health = newHealth;

View File

@@ -18,9 +18,6 @@
*/
#endregion
using System;
using OpenRA.Traits;
namespace OpenRA.Traits.Activities
{
class UndeployMcv : IActivity
@@ -45,7 +42,7 @@ namespace OpenRA.Traits.Activities
() => self.World.AddFrameEndTask(w => DoUndeploy(w,self)));
foreach (var s in self.Info.Traits.Get<BuildingInfo>().SellSounds)
Sound.PlayToPlayer(self.Owner, s);
Sound.PlayToPlayer(self.Owner, s, self.CenterLocation);
started = true;
}

View File

@@ -1,32 +0,0 @@
using System;
namespace OpenRA.Traits.Activities
{
public class Wait: IActivity
{
int remainingTicks;
public Wait (int period)
{
remainingTicks = period;
}
public IActivity Tick (Actor self)
{
if (remainingTicks-- == 0) return NextActivity;
return this;
}
public void Cancel (Actor self)
{
remainingTicks = 0; NextActivity = null;
}
public IActivity NextActivity { get; set; }
}
}

View File

@@ -20,7 +20,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Effects;
using OpenRA.FileFormats;
@@ -30,7 +29,9 @@ namespace OpenRA.Traits
{
public class AttackBaseInfo : ITraitInfo
{
[WeaponReference]
public readonly string PrimaryWeapon = null;
[WeaponReference]
public readonly string SecondaryWeapon = null;
public readonly int Recoil = 0;
public readonly int[] PrimaryLocalOffset = { };
@@ -40,10 +41,10 @@ namespace OpenRA.Traits
public readonly bool MuzzleFlash = false;
public readonly int FireDelay = 0;
public virtual object Create(Actor self) { return new AttackBase(self); }
public virtual object Create(ActorInitializer init) { return new AttackBase(init.self); }
}
class AttackBase : IIssueOrder, IResolveOrder, ITick
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier
{
[Sync] public Actor target;
@@ -69,12 +70,15 @@ namespace OpenRA.Traits
protected virtual bool CanAttack(Actor self)
{
if( target == null ) return false;
if( ( primaryFireDelay > 0 ) && ( secondaryFireDelay > 0 ) ) return false;
if (target == null) return false;
if ((primaryFireDelay > 0) && (secondaryFireDelay > 0)) return false;
if (self.traits.WithInterface<IDisable>().Any(d => d.Disabled)) return false;
return true;
}
public bool ShouldExplode(Actor self) { return !IsReloading(); }
public bool IsReloading()
{
return (primaryFireDelay > 0) || (secondaryFireDelay > 0);
@@ -186,12 +190,15 @@ namespace OpenRA.Traits
ScheduleDelayedAction( FireDelay( self, self.Info.Traits.Get<AttackBaseInfo>() ), () =>
{
var projectile = args.weapon.Projectile.Create(args);
if (projectile != null)
self.World.Add(projectile);
if (args.weapon.Projectile != null)
{
var projectile = args.weapon.Projectile.Create(args);
if (projectile != null)
self.World.Add(projectile);
if (!string.IsNullOrEmpty(args.weapon.Report))
Sound.Play(args.weapon.Report + ".aud");
if (!string.IsNullOrEmpty(args.weapon.Report))
Sound.Play(args.weapon.Report + ".aud", self.CenterLocation);
}
});
foreach (var na in self.traits.WithInterface<INotifyAttack>())

View File

@@ -1,175 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.GameRules;
namespace OpenRA.Traits
{
class BridgeInfo : ITraitInfo
{
public readonly bool Long = false;
public readonly bool UseAlternateNames = false;
public readonly int[] NorthOffset = null;
public readonly int[] SouthOffset = null;
public object Create(Actor self) { return new Bridge(self); }
}
class Bridge: IRender, INotifyDamage
{
Dictionary<int2, int> Tiles;
List<Dictionary<int2, Sprite>> TileSprites = new List<Dictionary<int2,Sprite>>();
List<TileTemplate> Templates = new List<TileTemplate>();
Actor self;
int state;
Bridge northNeighbour, southNeighbour;
public Bridge(Actor self) { this.self = self; self.RemoveOnDeath = false; }
static string cachedTileset;
static Cache<TileReference<ushort,byte>, Sprite> sprites;
public IEnumerable<Renderable> Render(Actor self)
{
foreach (var t in TileSprites[state])
yield return new Renderable(t.Value, Game.CellSize * t.Key, "terrain");
}
public void FinalizeBridges(World world, Bridge[,] bridges)
{
// go looking for our neighbors, if this is a long bridge.
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.NorthOffset != null)
northNeighbour = GetNeighbor(world, info.NorthOffset, bridges);
if (info.SouthOffset != null)
southNeighbour = GetNeighbor(world, info.SouthOffset, bridges);
}
public Bridge GetNeighbor(World world, int[] offset, Bridge[,] bridges)
{
if (offset == null) return null;
var pos = self.Location + new int2(offset[0], offset[1]);
if (!world.Map.IsInMap(pos.X, pos.Y)) return null;
return bridges[pos.X, pos.Y];
}
public int StateFromTemplate(TileTemplate t)
{
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.UseAlternateNames)
{
if (t.Name.EndsWith("d")) return 2;
if (t.Name.EndsWith("h")) return 1;
return 0;
}
else
return t.Name[t.Name.Length - 1] - 'a';
}
public string NameFromState(TileTemplate t, int state)
{
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.UseAlternateNames)
return t.Bridge + new[] { "", "h", "d" }[state];
else
return t.Bridge + (char)(state + 'a');
}
public void SetTiles(World world, TileTemplate template, Dictionary<int2, int> replacedTiles)
{
Tiles = replacedTiles;
state = StateFromTemplate(template);
if (cachedTileset != world.Map.Tileset)
{
cachedTileset = world.Map.Tileset;
sprites = new Cache<TileReference<ushort,byte>, Sprite>(
x => SheetBuilder.SharedInstance.Add(world.TileSet.GetBytes(x),
new Size(Game.CellSize, Game.CellSize)));
}
var numStates = self.Info.Traits.Get<BridgeInfo>().Long ? 6 : 3;
for (var n = 0; n < numStates; n++)
{
var stateTemplate = world.TileSet.Walkability.GetTileTemplate(NameFromState(template, n));
Templates.Add( stateTemplate );
TileSprites.Add(replacedTiles.ToDictionary(
a => a.Key,
a => sprites[new TileReference<ushort,byte>((ushort)stateTemplate.Index, (byte)a.Value)]));
}
self.Health = (int)(self.GetMaxHP() * template.HP);
}
public float GetCost(int2 p, UnitMovementType umt)
{
return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetCost(umt);
}
public float GetSpeedModifier(int2 p, UnitMovementType umt)
{
return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetSpeedModifier(umt);
}
static bool IsIntact(Bridge b)
{
return b != null && b.self.IsInWorld && b.self.Health > 0;
}
static bool IsLong(Bridge b)
{
return b != null && b.self.IsInWorld && b.self.Info.Traits.Get<BridgeInfo>().Long;
}
void UpdateState()
{
var ds = self.GetDamageState();
if (!self.Info.Traits.Get<BridgeInfo>().Long)
{
state = (int)ds;
return;
}
bool waterToSouth = !IsIntact(southNeighbour) && (!IsLong(southNeighbour) || !IsIntact(this));
bool waterToNorth = !IsIntact(northNeighbour) && (!IsLong(northNeighbour) || !IsIntact(this));
if (waterToSouth && waterToNorth) { state = 5; return; }
if (waterToNorth) { state = 4; return; }
if (waterToSouth) { state = 3; return; }
state = (int)ds;
}
public void Damaged(Actor self, AttackInfo e)
{
if (e.DamageStateChanged)
{
UpdateState();
if (northNeighbour != null) northNeighbour.UpdateState();
if (southNeighbour != null) southNeighbour.UpdateState();
}
}
}
}

View File

@@ -1,48 +1,48 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits
{
class ValuedInfo : ITraitInfo
{
public readonly int Cost = 0;
public readonly string Description = "";
public readonly string LongDesc = "";
public virtual object Create(Actor self) { return new Valued(); }
}
class BuildableInfo : ValuedInfo
{
public readonly int TechLevel = -1;
public readonly string[] Prerequisites = { };
public readonly string[] BuiltAt = { };
public readonly string[] Owner = { };
public readonly string Icon = null;
public readonly string[] AlternateName = { };
public readonly int BuildPaletteOrder = 50;
public override object Create(Actor self) { return new Buildable(); }
}
class Valued { } /* halfway to buildable */
class Buildable { }
}
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits
{
public class ValuedInfo : ITraitInfo
{
public readonly int Cost = 0;
public readonly string Description = "";
public readonly string LongDesc = "";
public readonly string[] Owner = { };
public virtual object Create(ActorInitializer init) { return new Valued(); }
}
public class BuildableInfo : ValuedInfo
{
[ActorReference]public readonly string[] Prerequisites = { };
[ActorReference] public readonly string[] BuiltAt = { };
public readonly string Icon = null;
public readonly string[] AlternateName = { };
public readonly int BuildPaletteOrder = 9999;
public readonly string Hotkey = null;
public override object Create(ActorInitializer init) { return new Buildable(); }
}
class Valued { } /* halfway to buildable */
class Buildable { }
}

View File

@@ -53,14 +53,17 @@ namespace OpenRA.Traits
public readonly string[] SellSounds = {"cashturn.aud"};
public readonly string DamagedSound = "kaboom1.aud";
public readonly string DestroyedSound = "kaboom22.aud";
public object Create(Actor self) { return new Building(self); }
public object Create(ActorInitializer init) { return new Building(init); }
}
public class Building : INotifyDamage, IResolveOrder, ITick, IRenderModifier
public class Building : INotifyDamage, IResolveOrder, ITick, IRenderModifier, IOccupySpace
{
readonly Actor self;
public readonly BuildingInfo Info;
[Sync]
readonly int2 topLeft;
[Sync]
bool isRepairing = false;
public bool Disabled
@@ -68,12 +71,13 @@ namespace OpenRA.Traits
get { return self.traits.WithInterface<IDisable>().Any(t => t.Disabled); }
}
public Building(Actor self)
public Building(ActorInitializer init)
{
this.self = self;
this.self = init.self;
this.topLeft = init.location;
Info = self.Info.Traits.Get<BuildingInfo>();
self.CenterLocation = Game.CellSize
* ((float2)self.Location + .5f * (float2)Info.Dimensions);
* ((float2)topLeft + .5f * (float2)Info.Dimensions);
}
public int GetPowerUsage()
@@ -96,7 +100,7 @@ namespace OpenRA.Traits
if (e.DamageState == DamageState.Dead)
{
self.World.WorldActor.traits.Get<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
Sound.Play(Info.DestroyedSound);
Sound.Play(Info.DestroyedSound, self.CenterLocation);
}
}
@@ -123,12 +127,12 @@ namespace OpenRA.Traits
if (remainingTicks == 0)
{
var csv = self.Info.Traits.GetOrDefault<CustomSellValueInfo>();
var buildingValue = csv != null ? csv.Value : self.Info.Traits.Get<BuildableInfo>().Cost;
var buildingValue = csv != null ? csv.Value : self.Info.Traits.Get<ValuedInfo>().Cost;
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
var costPerHp = (self.World.Defaults.RepairPercent * buildingValue) / maxHP;
var hpToRepair = Math.Min(self.World.Defaults.RepairStep, maxHP - self.Health);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.TakeCash(cost))
if (!self.Owner.PlayerActor.traits.Get<PlayerResources>().TakeCash(cost))
{
remainingTicks = 1;
return;
@@ -156,5 +160,15 @@ namespace OpenRA.Traits
yield return a.WithPalette("disabled");
}
}
public int2 TopLeft
{
get { return topLeft; }
}
public IEnumerable<int2> OccupiedCells()
{
return Footprint.UnpathableTiles( self.Info.Name, Info, TopLeft );
}
}
}

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
@@ -20,40 +20,47 @@
using System.Collections.Generic;
using System.Linq;
using System;
namespace OpenRA.Traits
{
class CloakInfo : ITraitInfo
{
public readonly float InitialDelay = .4f; // seconds
public readonly float CloakDelay = 1.2f; // Seconds
public readonly string CloakSound = "appear1.aud";
public readonly string UncloakSound = "appear1.aud";
public object Create(Actor self) { return new Cloak(self); }
public readonly string CloakSound = "subshow1.aud";
public readonly string UncloakSound = "subshow1.aud";
public object Create(ActorInitializer init) { return new Cloak(init.self); }
}
class Cloak : IRenderModifier, INotifyAttack, ITick
public class Cloak : IRenderModifier, INotifyAttack, ITick, INotifyDamage
{
[Sync]
int remainingUncloakTime = 2; /* setup for initial cloak */
int remainingTime;
Actor self;
public Cloak(Actor self)
{
remainingTime = (int)(self.Info.Traits.Get<CloakInfo>().InitialDelay * 25);
this.self = self;
}
public void Attacking(Actor self)
void DoSurface()
{
if (remainingUncloakTime <= 0)
OnCloak();
if (remainingTime <= 0)
OnSurface();
remainingUncloakTime = (int)(self.Info.Traits.Get<CloakInfo>().CloakDelay * 25);
remainingTime = Math.Max(remainingTime, (int)(self.Info.Traits.Get<CloakInfo>().CloakDelay * 25));
}
public void Attacking(Actor self) { DoSurface(); }
public void Damaged(Actor self, AttackInfo e) { DoSurface(); }
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingUncloakTime > 0)
if (remainingTime > 0)
return rs;
if (self.Owner == self.World.LocalPlayer)
@@ -64,19 +71,27 @@ namespace OpenRA.Traits
public void Tick(Actor self)
{
if (remainingUncloakTime > 0)
if (--remainingUncloakTime <= 0)
OnUncloak();
if (remainingTime > 0)
if (--remainingTime <= 0)
OnDive();
}
void OnCloak()
void OnSurface()
{
Sound.Play(self.Info.Traits.Get<CloakInfo>().CloakSound);
Sound.Play(self.Info.Traits.Get<CloakInfo>().UncloakSound, self.CenterLocation);
}
void OnUncloak()
void OnDive()
{
Sound.Play(self.Info.Traits.Get<CloakInfo>().UncloakSound);
Sound.Play(self.Info.Traits.Get<CloakInfo>().CloakSound, self.CenterLocation);
}
public bool Cloaked { get { return remainingTime > 0; } }
public void Decloak(int time)
{
DoSurface();
remainingTime = Math.Max(remainingTime, time);
}
}
}

View File

@@ -19,77 +19,35 @@
#endregion
using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Traits
{
class ConstructionYardInfo : ITraitInfo
class ConstructionYardInfo : TraitInfo<ConstructionYard> { }
public class ConstructionYard : IIssueOrder, IResolveOrder
{
public readonly bool AllowUndeploy = true;
public object Create(Actor self) { return new ConstructionYard(self); }
}
class ConstructionYard : IIssueOrder, IResolveOrder, IMovement
{
readonly Actor self;
public ConstructionYard(Actor self)
{
this.self = self;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (!self.Info.Traits.Get<ConstructionYardInfo>().AllowUndeploy) return null;
if (mi.Button == MouseButton.Left) return null;
if (underCursor != null)
{
// force-move
if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null;
if (!self.World.IsActorCrushableByActor(underCursor, self)) return null;
}
if (self.traits.GetOrDefault<IMovement>().CanEnterCell(xy))
return new Order("Move", self, xy);
else
return null;
if (underCursor == self)
return new Order("Deploy", self);
return null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Move")
if (order.OrderString == "Deploy")
{
self.CancelActivity();
self.QueueActivity(new UndeployMcv());
}
}
// HACK: This should make reference to an MCV actor, and use of its Mobile trait
public UnitMovementType GetMovementType() { return UnitMovementType.Wheel; }
public bool CanEnterCell(int2 a)
{
if (!self.World.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(a)) return false;
var crushable = true;
foreach (Actor actor in self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(a))
{
if (actor == self) continue;
if (!self.World.IsActorCrushableByActor(actor, self))
{
crushable = false;
break;
}
}
if (!crushable) return false;
return self.World.Map.IsInMap(a.X, a.Y) &&
Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])]
.GetCost(GetMovementType()) < float.PositiveInfinity;
}
}
/* tag trait for "bases": mcv/fact */
class BaseBuildingInfo : TraitInfo<BaseBuilding> { }
class BaseBuilding { }
}

View File

@@ -23,10 +23,10 @@ namespace OpenRA.Traits
// allow a nonstandard sell/repair value to avoid
// buy-sell exploits like c&c's PROC.
class CustomSellValueInfo : TraitInfo<CustomSellValue>
public class CustomSellValueInfo : TraitInfo<CustomSellValue>
{
public readonly int Value = 0;
}
class CustomSellValue {}
public class CustomSellValue { }
}

View File

@@ -0,0 +1,58 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits
{
class DetectCloakedInfo : TraitInfo<DetectCloaked>
{
public readonly int Interval = 12; // ~.5s
public readonly float DecloakTime = 2f; // 2s
public readonly int Range = 5;
public readonly bool AffectOwnUnits = true;
}
class DetectCloaked : ITick
{
[Sync] int ticks;
public void Tick(Actor self)
{
if (--ticks <= 0)
{
var info = self.Info.Traits.Get<DetectCloakedInfo>();
ticks = info.Interval;
var toDecloak = self.World.FindUnitsInCircle(self.CenterLocation, info.Range * Game.CellSize)
.Where(a => a.traits.Contains<Cloak>());
if (!info.AffectOwnUnits)
toDecloak = toDecloak.Where(a => self.Owner.Stances[a.Owner] != Stance.Ally);
foreach (var a in toDecloak)
a.traits.Get<Cloak>().Decloak((int)(25 * info.DecloakTime));
}
}
}
class RenderRangeCircleInfo : TraitInfo<RenderRangeCircle> { }
class RenderRangeCircle { }
}

View File

@@ -1,37 +0,0 @@
using System;
namespace OpenRA.Traits
{
class HasUnitOnBuildInfo : ITraitInfo
{
public readonly string Unit = null;
public readonly string InitialActivity = null;
public readonly int2 SpawnOffset = int2.Zero;
public readonly int Facing = 0;
public object Create( Actor self ) { return new HasUnitOnBuild(self); }
}
public class HasUnitOnBuild
{
public HasUnitOnBuild(Actor self)
{
var info = self.Info.Traits.Get<HasUnitOnBuildInfo>();
self.World.AddFrameEndTask(
w =>
{
var unit = w.CreateActor(info.Unit, self.Location
+ info.SpawnOffset, self.Owner);
var unitTrait = unit.traits.Get<Unit>();
unitTrait.Facing = info.Facing;
if (info.InitialActivity != null)
unit.QueueActivity(Game.CreateObject<IActivity>(info.InitialActivity));
});
}
}
}

View File

@@ -0,0 +1,52 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
using System.Collections.Generic;
namespace OpenRA.Traits
{
class AntiAirInfo : ITraitInfo
{
public readonly float Badness = 1000f;
public object Create( ActorInitializer init ) { return new AntiAir( init.self ); }
}
class AntiAir : IProvideHazard
{
public AntiAir(Actor self)
{
self.World.WorldActor.traits.Get<HazardLayer>().Add( self, this );
}
public IEnumerable<HazardLayer.Hazard> HazardCells(Actor self)
{
var info = self.Info.Traits.Get<AntiAirInfo>();
return self.World.FindTilesInCircle(self.Location, (int)self.GetPrimaryWeapon().Range).Select(
t => new HazardLayer.Hazard(){location = t, type = "antiair", intensity = info.Badness});
}
}
class AvoidsAAInfo : TraitInfo<AvoidsAA> {}
class AvoidsAA : IAvoidHazard
{
public string Type { get { return "antiair"; } }
}
}

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