Compare commits
335 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e845a9f3a | ||
|
|
2a3c149769 | ||
|
|
7cfcd94e23 | ||
|
|
247a8c9717 | ||
|
|
4afd8ad783 | ||
|
|
dca77956cb | ||
|
|
22c6c3b3f6 | ||
|
|
1e8e5c8f5c | ||
|
|
c0fcc862d6 | ||
|
|
5a3ccdf0c5 | ||
|
|
1bd802c386 | ||
|
|
3a4e2abedd | ||
|
|
f13343ef2e | ||
|
|
2b1ac6a60f | ||
|
|
8aa180c1f4 | ||
|
|
260e420f85 | ||
|
|
1a203afd89 | ||
|
|
c150fd9475 | ||
|
|
566303a8f1 | ||
|
|
10f8364b99 | ||
|
|
7c31f72db6 | ||
|
|
6b6c9639f9 | ||
|
|
7ca9fcdac9 | ||
|
|
20276291ce | ||
|
|
34fc207a6c | ||
|
|
c974e61680 | ||
|
|
09db76f89f | ||
|
|
6bbf878314 | ||
|
|
4cd3195f9f | ||
|
|
6ea2a06e4b | ||
|
|
597dba8584 | ||
|
|
1c1483377c | ||
|
|
0873741983 | ||
|
|
e0afc08e5f | ||
|
|
cb1deacbb2 | ||
|
|
ab1e930ba3 | ||
|
|
10bf85f57e | ||
|
|
17990ab8b7 | ||
|
|
beecb8aeb1 | ||
|
|
6a25d989a7 | ||
|
|
f8776d773d | ||
|
|
3724f46a3e | ||
|
|
915ad7fb7b | ||
|
|
07023b6c35 | ||
|
|
b78b5b22a3 | ||
|
|
eca098b0b4 | ||
|
|
011a20e8b4 | ||
|
|
9c362f7d41 | ||
|
|
99d92ee095 | ||
|
|
b905d343af | ||
|
|
024b564b8c | ||
|
|
9c0e3ac4c9 | ||
|
|
a2205e9031 | ||
|
|
0df9815d2c | ||
|
|
79d6eb4a2b | ||
|
|
0d8557eadb | ||
|
|
70f6fc7a7a | ||
|
|
11f6a8b945 | ||
|
|
e3d71acb05 | ||
|
|
580f1cfe97 | ||
|
|
3d7434f42e | ||
|
|
ef96604f9e | ||
|
|
465f5d295b | ||
|
|
1feb377d43 | ||
|
|
a065fb464e | ||
|
|
e39917ca19 | ||
|
|
318f496bf9 | ||
|
|
ed8a155249 | ||
|
|
40ac5f7b6e | ||
|
|
517754027e | ||
|
|
ef4f478e10 | ||
|
|
92c30b89f8 | ||
|
|
7331a9c4fb | ||
|
|
d2b9e150f1 | ||
|
|
8ba329f1be | ||
|
|
8868eab247 | ||
|
|
f12889e684 | ||
|
|
5c095bc174 | ||
|
|
0c24a08436 | ||
|
|
9762b540b0 | ||
|
|
fd34f2ba99 | ||
|
|
ad6481c8e8 | ||
|
|
7426d47cd5 | ||
|
|
761f62292f | ||
|
|
63b8555bc9 | ||
|
|
3209da4a4a | ||
|
|
aebef4f1c8 | ||
|
|
d3244184c1 | ||
|
|
39e62354a8 | ||
|
|
f525c3808e | ||
|
|
87a0b52ce5 | ||
|
|
4bc9e01516 | ||
|
|
711d05da98 | ||
|
|
3d805ff40d | ||
|
|
0cd140849b | ||
|
|
d6110b9ef0 | ||
|
|
26d1db778e | ||
|
|
f41aa474aa | ||
|
|
0002e80a19 | ||
|
|
759a52d86e | ||
|
|
44fe0396bb | ||
|
|
dd6d8d916e | ||
|
|
5af8f5e2d9 | ||
|
|
c85503811c | ||
|
|
ab431fe9ee | ||
|
|
7ec9958d47 | ||
|
|
cfc74a6dee | ||
|
|
cecdd73e08 | ||
|
|
381e080b11 | ||
|
|
c6a047cb1a | ||
|
|
4c51733e04 | ||
|
|
8f613b80e8 | ||
|
|
10de282daa | ||
|
|
915e123956 | ||
|
|
8cb7a7b8ce | ||
|
|
ce5cf93077 | ||
|
|
1390bb7428 | ||
|
|
3c5b136216 | ||
|
|
66785e606a | ||
|
|
e2239fa50c | ||
|
|
7f7712aa64 | ||
|
|
b1605e115a | ||
|
|
69b2da86be | ||
|
|
18e965e5aa | ||
|
|
24f0c28f56 | ||
|
|
25af51b4ac | ||
|
|
ecd7064cc3 | ||
|
|
477a21e782 | ||
|
|
899d9af62b | ||
|
|
17eca983ef | ||
|
|
2fc219ecd5 | ||
|
|
49a645cd2d | ||
|
|
7cb8da411d | ||
|
|
4bcdf3cf11 | ||
|
|
1b525ff809 | ||
|
|
cdec3fce26 | ||
|
|
7bdf6a953f | ||
|
|
06b20c8ba5 | ||
|
|
9b484b53ec | ||
|
|
9620b4ed46 | ||
|
|
d8908c44d0 | ||
|
|
cfe705531a | ||
|
|
9a2fd38ab6 | ||
|
|
911e7f62de | ||
|
|
403b81bdc9 | ||
|
|
a0714b00b3 | ||
|
|
d5239ee77a | ||
|
|
03ec97f302 | ||
|
|
3255f95ee9 | ||
|
|
4c8fd5e73d | ||
|
|
7179ef0f45 | ||
|
|
6d5918b11d | ||
|
|
81c484d1c9 | ||
|
|
de1044c24c | ||
|
|
e4c31939d9 | ||
|
|
7f48d6796e | ||
|
|
4fd77aec8e | ||
|
|
92fece01de | ||
|
|
d8d987f844 | ||
|
|
de429a4c62 | ||
|
|
c0ca35a4ff | ||
|
|
1bff8559fb | ||
|
|
de98274165 | ||
|
|
59e2228b2a | ||
|
|
96d1408d45 | ||
|
|
ff45ae2d16 | ||
|
|
47950c9113 | ||
|
|
f402ec7898 | ||
|
|
a3c0448e15 | ||
|
|
699b4b1154 | ||
|
|
911db3feb1 | ||
|
|
c790db8e84 | ||
|
|
d6dd392028 | ||
|
|
636b2a8ea7 | ||
|
|
959d3f8bd7 | ||
|
|
193cb929f1 | ||
|
|
f93e270fe4 | ||
|
|
f19953c39a | ||
|
|
59d5ce1bc8 | ||
|
|
43cf7cd074 | ||
|
|
aba76f4b50 | ||
|
|
8021fc3b20 | ||
|
|
7bf4cb85fa | ||
|
|
6dd03bb339 | ||
|
|
14e517cab5 | ||
|
|
cdcfeb6276 | ||
|
|
c77c63a380 | ||
|
|
9921fe8fad | ||
|
|
f848c5d7d4 | ||
|
|
62c47e3b12 | ||
|
|
094986d066 | ||
|
|
d87e02ab41 | ||
|
|
3f415a8fdf | ||
|
|
846371cf3e | ||
|
|
45c77e64ee | ||
|
|
66493031c8 | ||
|
|
384b26db60 | ||
|
|
d66dbeb312 | ||
|
|
ba9611f544 | ||
|
|
b6e56560d4 | ||
|
|
1f047d439f | ||
|
|
5233ae4770 | ||
|
|
562e07264a | ||
|
|
4dab4ed73f | ||
|
|
a97ddffa53 | ||
|
|
8e589e3c16 | ||
|
|
96f72ce842 | ||
|
|
d8de477edb | ||
|
|
694fb6831a | ||
|
|
c16a515224 | ||
|
|
e2eae7973b | ||
|
|
9e3c938706 | ||
|
|
ef665df2e9 | ||
|
|
271a3eea8d | ||
|
|
2f6315b816 | ||
|
|
ac8d408ba7 | ||
|
|
0fdd49c96a | ||
|
|
e390cf8ab0 | ||
|
|
64d700cd70 | ||
|
|
d3db9d3710 | ||
|
|
9eb05a43f9 | ||
|
|
3165ec5359 | ||
|
|
f4699132d6 | ||
|
|
086bdfb4bd | ||
|
|
61fd12c7da | ||
|
|
9979209c34 | ||
|
|
b0c06d4cd9 | ||
|
|
3a617f8934 | ||
|
|
b35a7d9f8d | ||
|
|
67fa079658 | ||
|
|
c9edbd8a80 | ||
|
|
4b49bf03dc | ||
|
|
6cfad6f2ab | ||
|
|
c0c4e7299b | ||
|
|
afda1647fd | ||
|
|
aff6889995 | ||
|
|
65515d54af | ||
|
|
c5b7c43d23 | ||
|
|
dba5adc91c | ||
|
|
0073a03ca4 | ||
|
|
5509d0d2e9 | ||
|
|
fe52e3722e | ||
|
|
3ddd1581f1 | ||
|
|
56efc3930b | ||
|
|
2f8d81a0f7 | ||
|
|
46486073ab | ||
|
|
3dc11eaa05 | ||
|
|
b62ee4d37c | ||
|
|
532afc3ff8 | ||
|
|
9ddb2beced | ||
|
|
1e758ec3e0 | ||
|
|
aa1d44428d | ||
|
|
23da8a24bd | ||
|
|
fef291a27e | ||
|
|
f49e56d660 | ||
|
|
927ab00f4d | ||
|
|
3f870e7e48 | ||
|
|
f2a321186f | ||
|
|
410daecab6 | ||
|
|
966e3bb71a | ||
|
|
652f06f604 | ||
|
|
2a10af2007 | ||
|
|
4cb26c0e3c | ||
|
|
8455dadb3c | ||
|
|
3c19b3df73 | ||
|
|
c796e155e7 | ||
|
|
ce9caec291 | ||
|
|
0330ef2b9e | ||
|
|
872a304714 | ||
|
|
59cc50df4c | ||
|
|
a1fd84fb15 | ||
|
|
317007f7ce | ||
|
|
387212d9ea | ||
|
|
c9ca5e207b | ||
|
|
ce78944a9e | ||
|
|
1fb336b7da | ||
|
|
e4d05407d9 | ||
|
|
f7eca1157e | ||
|
|
a64245fc10 | ||
|
|
ad8038867d | ||
|
|
fb90400524 | ||
|
|
08b25d10c1 | ||
|
|
ba09bbba8e | ||
|
|
0d2e1d7de5 | ||
|
|
22861fca5a | ||
|
|
692ef539f9 | ||
|
|
d07b0e4400 | ||
|
|
9848d1f403 | ||
|
|
83eae029b7 | ||
|
|
99e225c279 | ||
|
|
1785c4e4a8 | ||
|
|
69753f8a08 | ||
|
|
5593b9ffdd | ||
|
|
1b66635670 | ||
|
|
f1b1f3bd52 | ||
|
|
ff611dac32 | ||
|
|
e0a4cb4763 | ||
|
|
a3246866fb | ||
|
|
b94c2fc7c4 | ||
|
|
d530cf22da | ||
|
|
94e5b02a39 | ||
|
|
40533a50c1 | ||
|
|
d4182b1929 | ||
|
|
482129499d | ||
|
|
366cd02761 | ||
|
|
f549e7e5a8 | ||
|
|
4cab7c7fc4 | ||
|
|
e3939d4805 | ||
|
|
2ae6983bc2 | ||
|
|
ad00193a17 | ||
|
|
810667abbc | ||
|
|
a66efd56f2 | ||
|
|
36ba15e7f9 | ||
|
|
d809fb1e7b | ||
|
|
d0bc834a57 | ||
|
|
483ca8cc4c | ||
|
|
06aba5da46 | ||
|
|
106fbcd5af | ||
|
|
f456e41a45 | ||
|
|
7dc3aee4a2 | ||
|
|
c91bee8091 | ||
|
|
82875e15f9 | ||
|
|
d6f8b7d850 | ||
|
|
72fe873b26 | ||
|
|
e9f34b1e21 | ||
|
|
d15ab79370 | ||
|
|
303613b052 | ||
|
|
051c451867 | ||
|
|
ac8a3526a4 | ||
|
|
be47fb55e8 | ||
|
|
5b8fc75d4a | ||
|
|
629e73ac29 | ||
|
|
7e5b861caf | ||
|
|
f3dcc14fca | ||
|
|
fee68d0231 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -12,20 +12,11 @@ mods/*/*.dll
|
||||
# Red Alert binary files
|
||||
mods/*/packages/*.[mM][iI][xX]
|
||||
|
||||
# Crap generated by OpenRa
|
||||
sheet-*.png
|
||||
log.txt
|
||||
|
||||
*.rep
|
||||
|
||||
#binary stuff
|
||||
/*.dll
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.exe
|
||||
OpenRA
|
||||
OpenRA.app
|
||||
*.vqa
|
||||
|
||||
# backup files by various editors
|
||||
*~
|
||||
@@ -33,10 +24,8 @@ OpenRA.app
|
||||
# dependency DLLs (different for every platform!)
|
||||
cg.dll
|
||||
cgGL.dll
|
||||
glfw.dll
|
||||
|
||||
/OpenRa.Gl.dll
|
||||
settings.ini
|
||||
|
||||
#monodevelop
|
||||
*.pidb
|
||||
|
||||
3
AUTHORS
3
AUTHORS
@@ -6,4 +6,5 @@ The OpenRA developers are:
|
||||
* Matthew Bowra-Dean
|
||||
* Paul Chote
|
||||
* Alli Witheford
|
||||
* Joakim Lindberg
|
||||
* Joakim Lindberg
|
||||
* Andrew Riedi
|
||||
|
||||
75
HACKING
75
HACKING
@@ -5,43 +5,82 @@ There are n main sections to OpenRA: UI, Rendering, unit behaviour, ...
|
||||
All units/structures/most things in the map are Actors. Actors contain a collection of traits.
|
||||
Traits consist of an info class and a class that does stuff
|
||||
|
||||
Actor assembly is done via the mod's yaml files. A section exists for each actor type, and within that section we list the traits the actor should have. These get looked up in the loaded mod DLLs. Each trait can contain properties, which are automatically loaded into the corresponding fields on the trait's ITraitInfo.
|
||||
Actor assembly is done via the mod's yaml files. A section exists for each actor type,
|
||||
and within that section we list the traits the actor should have.
|
||||
These get looked up in the loaded mod DLLs. Each trait can contain properties,
|
||||
which are automatically loaded into the corresponding fields on the trait's ITraitInfo.
|
||||
|
||||
- Traits: look at TraitInterfaces.cs
|
||||
We've tried to make individual traits implement as self-contained a unit of functionality as possible - all cross-trait references should be in terms of an interface from TraitInterfaces.cs.
|
||||
We've tried to make individual traits implement as self-contained a unit of functionality
|
||||
as possible - all cross-trait references should be in terms of an interface from
|
||||
TraitInterfaces.cs.
|
||||
|
||||
- Things an actor can be *doing* are represented as IActivity implementations. Actor has a queue of these. There's a standard set of activities in OpenRa.Game/Traits/Activities, and mods tend to define more as they need them. (RA defines various special-infantry actions as activities).
|
||||
- Things an actor can be *doing* are represented as IActivity implementations.
|
||||
Actor has a queue of these. There's a standard set of activities in
|
||||
OpenRa.Game/Traits/Activities, and mods tend to define more as they need them. (RA
|
||||
defines various special-infantry actions as activities).
|
||||
|
||||
- Units offer orders they can perform (given context) through traits that implement IIssueOrder. Every trait with this interface is given a chance to generate orders for the current context.
|
||||
- Units offer orders they can perform (given context) through traits that implement IIssueOrder.
|
||||
Every trait with this interface is given a chance to generate orders for the current context.
|
||||
|
||||
- For more complex things that require modal UI (like special abilities, RA-style sell/repair buttons, etc) we have IOrderGenerator implementations. This can completely replace the normal actors-provide-orders model temporarily. IOGs wiring is provided through OpenRa.Game/Controller.cs (ToggleInputMode<T>, CancelInputMode)
|
||||
- For more complex things that require modal UI (like special abilities,
|
||||
RA-style sell/repair buttons, etc) we have IOrderGenerator implementations. This can
|
||||
completely replace the normal actors-provide-orders model temporarily. IOGs wiring is
|
||||
provided through OpenRa.Game/Controller.cs (ToggleInputMode<T>, CancelInputMode)
|
||||
|
||||
- Things that don't affect gameplay, or (increasingly) are just transient are implemented as IEffect, rather than real Actors. This is similar to the temp ents mechanism in many other game engines.
|
||||
- Things that don't affect gameplay, or (increasingly) are just transient are implemented as
|
||||
IEffect, rather than real Actors. This is similar to the temp ents mechanism in many other
|
||||
game engines.
|
||||
|
||||
- Most player-level or global-level game behavior is implemented as traits on special Player and World actors. These are accessible via Player.PlayerActor and World.WorldActor. This includes production queue support, ore/tiberium growth, various palette manipulation magic.
|
||||
- Most player-level or global-level game behavior is implemented as traits on special Player
|
||||
and World actors. These are accessible via Player.PlayerActor and World.WorldActor. This
|
||||
includes production queue support, ore/tiberium growth, various palette manipulation magic.
|
||||
|
||||
- Many traits can be modified by adding an appropriate IFooModifier implementation to the unit. This includes rendering, where IRenderModifier allows you to define an arbitrary transform on the Renderables emitted by the actor's IRender implementation(s). Examples are things like cloaking, invisibility to certain players, flying units with shadows, etc. Other modifiers can affect movement speed, damage taken, weapon firepower, etc.
|
||||
- Many traits can be modified by adding an appropriate IFooModifier implementation to the unit.
|
||||
This includes rendering, where IRenderModifier allows you to define an arbitrary transform on
|
||||
the Renderables emitted by the actor's IRender implementation(s). Examples are things like
|
||||
cloaking, invisibility to certain players, flying units with shadows, etc. Other modifiers
|
||||
can affect movement speed, damage taken, weapon firepower, etc.
|
||||
|
||||
Game code is collected into "Mod" units. Mods can be added prior to starting the game. Currently there is no dependancy mechanism, but provided you are doing additions or overrides you can add multiple mods without problem.
|
||||
Game code is collected into "Mod" units. Mods can be added prior to starting the game.
|
||||
Currently there is no dependancy mechanism, but provided you are doing additions or overrides
|
||||
you can add multiple mods without problem.
|
||||
Everything is a mod (including RA - which is loaded by default).
|
||||
|
||||
The contents of the mod is defined in a manifest file mod.yaml. This lists the packages containing art assets (typically .mix files), yaml files defining actor defintions, and ini files containing legacy information that have yet to be ported over to the (relatively new) yaml system.
|
||||
The contents of the mod is defined in a manifest file mod.yaml. This lists the packages
|
||||
containing art assets (typically .mix files), yaml files defining actor defintions,
|
||||
and ini files containing legacy information that have yet to be ported over to
|
||||
the (relatively new) yaml system.
|
||||
|
||||
The unit artwork itself must be defined in a Sequences file (typically Sequences.xml; check mod.yaml for a list of what the mod uses); the format is self explanatory. There is also the SequenceEditor tool to make this easy.
|
||||
The unit artwork itself must be defined in a Sequences file (typically Sequences.xml;
|
||||
check mod.yaml for a list of what the mod uses); the format is self explanatory. There is
|
||||
also the SequenceEditor tool to make this easy.
|
||||
|
||||
Chrome artwork is similarly defined in Chrome.xml. Chrome is already mod dependent. Sortof ;) mod-dependent *behavior* would be nice too, not just skinning. This is a property of the traits however; once we port UI into traits this will become a non-issue.
|
||||
Chrome artwork is similarly defined in Chrome.xml. Chrome is already mod dependent. Sortof ;)
|
||||
mod-dependent *behavior* would be nice too, not just skinning. This is a property of the traits
|
||||
however; once we port UI into traits this will become a non-issue.
|
||||
|
||||
Rendering
|
||||
OpenRa.Game/Chrome.cs is the user interface.
|
||||
Three renderers (SpriteRenderer, LineRenderer, Rgba?Renderer) render most stuff. Don't forget to flush the renderer (if you want to see anything).
|
||||
Three renderers (SpriteRenderer, LineRenderer, Rgba?Renderer) render most stuff. Don't forget
|
||||
to flush the renderer (if you want to see anything).
|
||||
|
||||
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be able to save values changed in game into settings.ini (not yet implemented)
|
||||
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be
|
||||
able to save values changed in game into settings.ini (not yet implemented)
|
||||
|
||||
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA . There's also a few at http://github.com/chrisforbes/OpenRA/issues (which won't be ported over, but no more bugs should be added here).
|
||||
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA .
|
||||
|
||||
We also have a website at http://www.open-ra.org/ .
|
||||
|
||||
As far as using git, get your own repository on github. You probably want to set up the gitbot to spam irc when you make commits (its nice to know). Push your changes into your git repository, and it will/might :P be merged into chrisforbes/OpenRA . Alli: setup howto for this?
|
||||
Our IRC channel is #openra on irc.freenode.net .
|
||||
|
||||
As far as using git, get your own repository on github. You probably want to set up the gitbot
|
||||
to spam irc when you make commits (its nice to know). Push your changes into your git
|
||||
repository, and it will/might :P be merged into chrisforbes/OpenRA .
|
||||
See http://help.github.com/ for working with GitHub and see http://progit.org/ for working
|
||||
with Git.
|
||||
|
||||
|
||||
|
||||
Other things we probably want to put in here:
|
||||
- A guide on how to add a generic unit via yaml using existing traits
|
||||
@@ -50,6 +89,6 @@ Other things we probably want to put in here:
|
||||
- VFS (OpenRa.FileFormats.FileSystem, Package, Folder classes)
|
||||
- Trait inheritance (and the magicness of ^ActorType)
|
||||
- Removing inherited traits (prepend `-` to the trait name)
|
||||
- Multiple instances of a trait (`@` and all subsequent characters are ignored for the purposes
|
||||
of looking up the trait.
|
||||
- Multiple instances of a trait (`@` and all subsequent characters are ignored for
|
||||
the purposes of looking up the trait.
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@@ -58,7 +58,7 @@ editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
@@ -150,9 +150,12 @@ mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
|
||||
mono RALint.exe cnc
|
||||
mods: mod_ra mod_cnc
|
||||
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
|
||||
OpenRA.Editor.Form1.resources:
|
||||
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
|
||||
editor: OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
ralint: $(ralint_TARGET)
|
||||
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
|
||||
SequenceEditor.Form1.resources:
|
||||
|
||||
209
OpenRA.Editor/Form1.Designer.cs
generated
209
OpenRA.Editor/Form1.Designer.cs
generated
@@ -30,8 +30,9 @@
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
|
||||
this.pmMiniMap = new System.Windows.Forms.PictureBox();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.tilePalette = new System.Windows.Forms.FlowLayoutPanel();
|
||||
@@ -50,6 +51,8 @@
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.cCRedAlertMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.bitmapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuExport = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuMinimapToPNG = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.exotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -57,40 +60,29 @@
|
||||
this.resizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.spawnpointsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.layersFloaterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.tt = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
|
||||
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||
this.splitContainer3 = new System.Windows.Forms.SplitContainer();
|
||||
this.surface1 = new OpenRA.Editor.Surface();
|
||||
this.toolStripContainer1.ContentPanel.SuspendLayout();
|
||||
this.toolStripContainer1.TopToolStripPanel.SuspendLayout();
|
||||
this.toolStripContainer1.SuspendLayout();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.splitContainer2.Panel1.SuspendLayout();
|
||||
this.splitContainer2.Panel2.SuspendLayout();
|
||||
this.splitContainer2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).BeginInit();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.tabPage2.SuspendLayout();
|
||||
this.tabPage3.SuspendLayout();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.splitContainer3.Panel1.SuspendLayout();
|
||||
this.splitContainer3.Panel2.SuspendLayout();
|
||||
this.splitContainer3.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// toolStripContainer1
|
||||
//
|
||||
//
|
||||
// toolStripContainer1.ContentPanel
|
||||
//
|
||||
this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1);
|
||||
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 681);
|
||||
this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.toolStripContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolStripContainer1.Name = "toolStripContainer1";
|
||||
this.toolStripContainer1.Size = new System.Drawing.Size(985, 705);
|
||||
this.toolStripContainer1.TabIndex = 1;
|
||||
this.toolStripContainer1.Text = "toolStripContainer1";
|
||||
//
|
||||
// toolStripContainer1.TopToolStripPanel
|
||||
//
|
||||
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip1);
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
@@ -99,15 +91,45 @@
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.tabControl1);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.splitContainer2);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.surface1);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(985, 681);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(985, 744);
|
||||
this.splitContainer1.SplitterDistance = 198;
|
||||
this.splitContainer1.TabIndex = 0;
|
||||
//
|
||||
// splitContainer2
|
||||
//
|
||||
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer2.Name = "splitContainer2";
|
||||
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer2.Panel1
|
||||
//
|
||||
this.splitContainer2.Panel1.Controls.Add(this.pmMiniMap);
|
||||
//
|
||||
// splitContainer2.Panel2
|
||||
//
|
||||
this.splitContainer2.Panel2.Controls.Add(this.tabControl1);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(198, 744);
|
||||
this.splitContainer2.SplitterDistance = 182;
|
||||
this.splitContainer2.TabIndex = 1;
|
||||
//
|
||||
// pmMiniMap
|
||||
//
|
||||
this.pmMiniMap.BackColor = System.Drawing.Color.Black;
|
||||
this.pmMiniMap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.pmMiniMap.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pmMiniMap.Location = new System.Drawing.Point(0, 0);
|
||||
this.pmMiniMap.Name = "pmMiniMap";
|
||||
this.pmMiniMap.Size = new System.Drawing.Size(198, 182);
|
||||
this.pmMiniMap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pmMiniMap.TabIndex = 1;
|
||||
this.pmMiniMap.TabStop = false;
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
@@ -115,19 +137,21 @@
|
||||
this.tabControl1.Controls.Add(this.tabPage3);
|
||||
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
|
||||
this.tabControl1.Multiline = true;
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.Padding = new System.Drawing.Point(6, 0);
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(198, 681);
|
||||
this.tabControl1.Size = new System.Drawing.Size(198, 558);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.tilePalette);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(190, 655);
|
||||
this.tabPage1.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Templates";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
@@ -139,16 +163,16 @@
|
||||
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tilePalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.tilePalette.Name = "tilePalette";
|
||||
this.tilePalette.Size = new System.Drawing.Size(184, 649);
|
||||
this.tilePalette.Size = new System.Drawing.Size(184, 528);
|
||||
this.tilePalette.TabIndex = 1;
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Controls.Add(this.actorPalette);
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(190, 655);
|
||||
this.tabPage2.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Actors";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
@@ -160,15 +184,15 @@
|
||||
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.actorPalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.actorPalette.Name = "actorPalette";
|
||||
this.actorPalette.Size = new System.Drawing.Size(184, 649);
|
||||
this.actorPalette.Size = new System.Drawing.Size(184, 528);
|
||||
this.actorPalette.TabIndex = 2;
|
||||
//
|
||||
// tabPage3
|
||||
//
|
||||
this.tabPage3.Controls.Add(this.resourcePalette);
|
||||
this.tabPage3.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage3.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage3.Name = "tabPage3";
|
||||
this.tabPage3.Size = new System.Drawing.Size(190, 655);
|
||||
this.tabPage3.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage3.TabIndex = 2;
|
||||
this.tabPage3.Text = "Resources";
|
||||
this.tabPage3.UseVisualStyleBackColor = true;
|
||||
@@ -180,15 +204,15 @@
|
||||
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
|
||||
this.resourcePalette.Name = "resourcePalette";
|
||||
this.resourcePalette.Size = new System.Drawing.Size(190, 655);
|
||||
this.resourcePalette.Size = new System.Drawing.Size(190, 534);
|
||||
this.resourcePalette.TabIndex = 3;
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.None;
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem,
|
||||
this.mapToolStripMenuItem});
|
||||
this.mapToolStripMenuItem,
|
||||
this.toolsToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(985, 24);
|
||||
@@ -205,6 +229,7 @@
|
||||
this.saveAsToolStripMenuItem,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripMenuItem1,
|
||||
this.mnuExport,
|
||||
this.toolStripSeparator3,
|
||||
this.exotToolStripMenuItem});
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
@@ -216,20 +241,20 @@
|
||||
this.newToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("newToolStripMenuItem.Image")));
|
||||
this.newToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.Fuchsia;
|
||||
this.newToolStripMenuItem.Name = "newToolStripMenuItem";
|
||||
this.newToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.newToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.newToolStripMenuItem.Text = "&New...";
|
||||
this.newToolStripMenuItem.Click += new System.EventHandler(this.NewClicked);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(120, 6);
|
||||
//
|
||||
// openToolStripMenuItem
|
||||
//
|
||||
this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image")));
|
||||
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
|
||||
this.openToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.openToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.openToolStripMenuItem.Text = "&Open...";
|
||||
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenClicked);
|
||||
//
|
||||
@@ -237,21 +262,21 @@
|
||||
//
|
||||
this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image")));
|
||||
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
|
||||
this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.saveToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.saveToolStripMenuItem.Text = "&Save";
|
||||
this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveClicked);
|
||||
//
|
||||
// saveAsToolStripMenuItem
|
||||
//
|
||||
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
|
||||
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.saveAsToolStripMenuItem.Text = "Save &As...";
|
||||
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsClicked);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(149, 6);
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(120, 6);
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
@@ -259,7 +284,7 @@
|
||||
this.cCRedAlertMapToolStripMenuItem,
|
||||
this.bitmapToolStripMenuItem});
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(123, 22);
|
||||
this.toolStripMenuItem1.Text = "&Import";
|
||||
//
|
||||
// cCRedAlertMapToolStripMenuItem
|
||||
@@ -276,16 +301,33 @@
|
||||
this.bitmapToolStripMenuItem.Name = "bitmapToolStripMenuItem";
|
||||
this.bitmapToolStripMenuItem.Size = new System.Drawing.Size(195, 22);
|
||||
this.bitmapToolStripMenuItem.Text = "&Bitmap...";
|
||||
this.bitmapToolStripMenuItem.Visible = false;
|
||||
//
|
||||
// mnuExport
|
||||
//
|
||||
this.mnuExport.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuMinimapToPNG});
|
||||
this.mnuExport.Name = "mnuExport";
|
||||
this.mnuExport.Size = new System.Drawing.Size(123, 22);
|
||||
this.mnuExport.Text = "&Export";
|
||||
//
|
||||
// mnuMinimapToPNG
|
||||
//
|
||||
this.mnuMinimapToPNG.Image = ((System.Drawing.Image)(resources.GetObject("mnuMinimapToPNG.Image")));
|
||||
this.mnuMinimapToPNG.Name = "mnuMinimapToPNG";
|
||||
this.mnuMinimapToPNG.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuMinimapToPNG.Text = "Minimap to PNG";
|
||||
this.mnuMinimapToPNG.Click += new System.EventHandler(this.mnuMinimapToPNG_Click);
|
||||
//
|
||||
// toolStripSeparator3
|
||||
//
|
||||
this.toolStripSeparator3.Name = "toolStripSeparator3";
|
||||
this.toolStripSeparator3.Size = new System.Drawing.Size(149, 6);
|
||||
this.toolStripSeparator3.Size = new System.Drawing.Size(120, 6);
|
||||
//
|
||||
// exotToolStripMenuItem
|
||||
//
|
||||
this.exotToolStripMenuItem.Name = "exotToolStripMenuItem";
|
||||
this.exotToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.exotToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.exotToolStripMenuItem.Text = "E&xit";
|
||||
this.exotToolStripMenuItem.Click += new System.EventHandler(this.CloseClicked);
|
||||
//
|
||||
@@ -329,17 +371,59 @@
|
||||
this.spawnpointsToolStripMenuItem.Text = "&Spawnpoints";
|
||||
this.spawnpointsToolStripMenuItem.Click += new System.EventHandler(this.SpawnPointsClicked);
|
||||
//
|
||||
// toolsToolStripMenuItem
|
||||
//
|
||||
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.layersFloaterToolStripMenuItem});
|
||||
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
|
||||
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(48, 20);
|
||||
this.toolsToolStripMenuItem.Text = "Tools";
|
||||
this.toolsToolStripMenuItem.Visible = false;
|
||||
//
|
||||
// layersFloaterToolStripMenuItem
|
||||
//
|
||||
this.layersFloaterToolStripMenuItem.Name = "layersFloaterToolStripMenuItem";
|
||||
this.layersFloaterToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
|
||||
this.layersFloaterToolStripMenuItem.Text = "Layers floater";
|
||||
this.layersFloaterToolStripMenuItem.Click += new System.EventHandler(this.layersFloaterToolStripMenuItem_Click);
|
||||
//
|
||||
// tt
|
||||
//
|
||||
this.tt.ShowAlways = true;
|
||||
//
|
||||
// saveFileDialog
|
||||
//
|
||||
this.saveFileDialog.DefaultExt = "*.png";
|
||||
this.saveFileDialog.Filter = "PNG Image (*.png)|";
|
||||
this.saveFileDialog.Title = "Export minimap to PNG";
|
||||
//
|
||||
// splitContainer3
|
||||
//
|
||||
this.splitContainer3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer3.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
|
||||
this.splitContainer3.IsSplitterFixed = true;
|
||||
this.splitContainer3.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer3.Name = "splitContainer3";
|
||||
this.splitContainer3.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer3.Panel1
|
||||
//
|
||||
this.splitContainer3.Panel1.Controls.Add(this.menuStrip1);
|
||||
//
|
||||
// splitContainer3.Panel2
|
||||
//
|
||||
this.splitContainer3.Panel2.Controls.Add(this.splitContainer1);
|
||||
this.splitContainer3.Size = new System.Drawing.Size(985, 773);
|
||||
this.splitContainer3.SplitterDistance = 25;
|
||||
this.splitContainer3.TabIndex = 6;
|
||||
//
|
||||
// surface1
|
||||
//
|
||||
this.surface1.BackColor = System.Drawing.Color.Black;
|
||||
this.surface1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.surface1.Location = new System.Drawing.Point(0, 0);
|
||||
this.surface1.Name = "surface1";
|
||||
this.surface1.Size = new System.Drawing.Size(783, 681);
|
||||
this.surface1.Size = new System.Drawing.Size(783, 744);
|
||||
this.surface1.TabIndex = 5;
|
||||
this.surface1.Text = "surface1";
|
||||
//
|
||||
@@ -347,36 +431,40 @@
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(985, 705);
|
||||
this.Controls.Add(this.toolStripContainer1);
|
||||
this.ClientSize = new System.Drawing.Size(985, 773);
|
||||
this.Controls.Add(this.splitContainer3);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.KeyPreview = true;
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.Name = "Form1";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "OpenRA Editor";
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
|
||||
this.toolStripContainer1.ContentPanel.ResumeLayout(false);
|
||||
this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false);
|
||||
this.toolStripContainer1.TopToolStripPanel.PerformLayout();
|
||||
this.toolStripContainer1.ResumeLayout(false);
|
||||
this.toolStripContainer1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel2.ResumeLayout(false);
|
||||
this.splitContainer2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).EndInit();
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage2.ResumeLayout(false);
|
||||
this.tabPage3.ResumeLayout(false);
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.splitContainer3.Panel1.ResumeLayout(false);
|
||||
this.splitContainer3.Panel1.PerformLayout();
|
||||
this.splitContainer3.Panel2.ResumeLayout(false);
|
||||
this.splitContainer3.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStripContainer toolStripContainer1;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.ToolTip tt;
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
@@ -385,8 +473,7 @@
|
||||
private System.Windows.Forms.TabPage tabPage2;
|
||||
private System.Windows.Forms.FlowLayoutPanel actorPalette;
|
||||
private System.Windows.Forms.TabPage tabPage3;
|
||||
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
|
||||
private System.Windows.Forms.FolderBrowserDialog folderBrowser;
|
||||
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
|
||||
private Surface surface1;
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||
@@ -406,6 +493,14 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem resizeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
|
||||
private System.Windows.Forms.ToolStripMenuItem spawnpointsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem layersFloaterToolStripMenuItem;
|
||||
private System.Windows.Forms.PictureBox pmMiniMap;
|
||||
private System.Windows.Forms.SplitContainer splitContainer2;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuExport;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuMinimapToPNG;
|
||||
private System.Windows.Forms.SaveFileDialog saveFileDialog;
|
||||
private System.Windows.Forms.SplitContainer splitContainer3;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
@@ -32,18 +31,20 @@ namespace OpenRA.Editor
|
||||
|
||||
Text = "OpenRA Editor (mod:{0})".F(currentMod);
|
||||
|
||||
Game.modData = new ModData( currentMod );
|
||||
Game.modData = new ModData(currentMod);
|
||||
|
||||
Rules.LoadRules(Game.modData.Manifest, new Map());
|
||||
|
||||
folderBrowser.SelectedPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
|
||||
.Aggregate(Path.Combine);
|
||||
surface1.AfterChange += OnMapChanged;
|
||||
}
|
||||
|
||||
surface1.AfterChange += MakeDirty;
|
||||
void OnMapChanged()
|
||||
{
|
||||
MakeDirty();
|
||||
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
|
||||
}
|
||||
|
||||
void MakeDirty() { dirty = true; }
|
||||
|
||||
string loadedMapName;
|
||||
string currentMod = "ra";
|
||||
TileSet tileset;
|
||||
@@ -57,7 +58,7 @@ namespace OpenRA.Editor
|
||||
|
||||
loadedMapName = mapname;
|
||||
|
||||
Game.modData = new ModData( currentMod );
|
||||
Game.modData = new ModData(currentMod);
|
||||
|
||||
// load the map
|
||||
var map = new Map(new Folder(mapname));
|
||||
@@ -81,31 +82,31 @@ namespace OpenRA.Editor
|
||||
|
||||
loadedMapName = null;
|
||||
|
||||
Game.modData = new ModData( currentMod );
|
||||
Game.modData = new ModData(currentMod);
|
||||
|
||||
PrepareMapResources(Game.modData.Manifest, map);
|
||||
|
||||
MakeDirty();
|
||||
}
|
||||
|
||||
// this code is insanely stupid, and mostly my fault -- chrisf
|
||||
void PrepareMapResources(Manifest manifest, Map map)
|
||||
{
|
||||
Rules.LoadRules(manifest, map);
|
||||
Rules.LoadRules(manifest, map);
|
||||
tileset = Rules.TileSets[map.Theater];
|
||||
tileset.LoadTiles();
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
|
||||
|
||||
surface1.Bind(map, tileset, palette);
|
||||
|
||||
surface1.Bind(map, tileset, palette);
|
||||
// construct the palette of tiles
|
||||
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
|
||||
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
|
||||
|
||||
foreach (var t in tileset.Templates)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bitmap = RenderTemplate(tileset, (ushort)t.Key, palette);
|
||||
var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = bitmap,
|
||||
@@ -119,7 +120,6 @@ namespace OpenRA.Editor
|
||||
|
||||
var template = t.Value;
|
||||
tilePalette.Controls.Add(ibox);
|
||||
|
||||
tt.SetToolTip(ibox,
|
||||
"{1}:{0} ({2}x{3})".F(
|
||||
template.Image,
|
||||
@@ -137,16 +137,18 @@ namespace OpenRA.Editor
|
||||
try
|
||||
{
|
||||
var info = Rules.Info[a];
|
||||
if( !info.Traits.Contains<RenderSimpleInfo>() ) continue;
|
||||
var template = RenderActor(info, tileset, palette);
|
||||
if (!info.Traits.Contains<RenderSimpleInfo>()) continue;
|
||||
var template = RenderUtils.RenderActor(info, tileset, palette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = template.Bitmap,
|
||||
Width = template.Bitmap.Width / 2,
|
||||
Height = template.Bitmap.Height / 2,
|
||||
SizeMode = PictureBoxSizeMode.StretchImage
|
||||
Width = 32,
|
||||
Height = 32,
|
||||
SizeMode = PictureBoxSizeMode.Zoom,
|
||||
BorderStyle = BorderStyle.FixedSingle
|
||||
};
|
||||
|
||||
|
||||
ibox.Click += (_, e) => surface1.SetActor(template);
|
||||
|
||||
actorPalette.Controls.Add(ibox);
|
||||
@@ -168,15 +170,18 @@ namespace OpenRA.Editor
|
||||
{
|
||||
try
|
||||
{
|
||||
var template = RenderResourceType(a, tileset.Extensions, palette);
|
||||
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = template.Bitmap,
|
||||
Width = template.Bitmap.Width,
|
||||
Height = template.Bitmap.Height,
|
||||
SizeMode = PictureBoxSizeMode.StretchImage
|
||||
Width = 32,
|
||||
Height = 32,
|
||||
SizeMode = PictureBoxSizeMode.Zoom,
|
||||
BorderStyle = BorderStyle.FixedSingle
|
||||
};
|
||||
|
||||
|
||||
|
||||
ibox.Click += (_, e) => surface1.SetResource(template);
|
||||
|
||||
resourcePalette.Controls.Add(ibox);
|
||||
@@ -193,103 +198,12 @@ namespace OpenRA.Editor
|
||||
|
||||
surface1.BindResourceTemplates(resourceTemplates);
|
||||
|
||||
foreach (var p in palettes) { p.Visible = true; p.ResumeLayout(); }
|
||||
}
|
||||
|
||||
static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
|
||||
{
|
||||
var template = ts.Templates[n];
|
||||
var tile = ts.Tiles[n];
|
||||
|
||||
var bitmap = new Bitmap(24 * template.Size.X, 24 * template.Size.Y);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
foreach (var p in palettes)
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
|
||||
{
|
||||
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
|
||||
for (var i = 0; i < 24; i++)
|
||||
for (var j = 0; j < 24; j++)
|
||||
q[(v * 24 + j) * stride + u * 24 + i] = p.GetColor(rawImage[i + 24 * j]).ToArgb();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < 24; i++)
|
||||
for (var j = 0; j < 24; j++)
|
||||
q[(v * 24 + j) * stride + u * 24 + i] = Color.Transparent.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
|
||||
{
|
||||
var ri = info.Traits.Get<RenderSimpleInfo>();
|
||||
string image = null;
|
||||
if (ri.OverrideTheater != null)
|
||||
for (int i = 0; i < ri.OverrideTheater.Length; i++)
|
||||
if (ri.OverrideTheater[i] == tileset.Id)
|
||||
image = ri.OverrideImage[i];
|
||||
|
||||
image = image ?? ri.Image ?? info.Name;
|
||||
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
|
||||
{
|
||||
var shp = new ShpReader(s);
|
||||
var frame = shp[0];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
|
||||
}
|
||||
}
|
||||
|
||||
static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
|
||||
{
|
||||
var image = info.SpriteNames[0];
|
||||
using (var s = FileSystem.OpenWithExts(image, exts))
|
||||
{
|
||||
var shp = new ShpReader(s);
|
||||
var frame = shp[shp.ImageCount - 1];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
|
||||
p.Visible = true;
|
||||
p.ResumeLayout();
|
||||
}
|
||||
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
|
||||
}
|
||||
|
||||
void ResizeClicked(object sender, EventArgs e)
|
||||
@@ -318,7 +232,7 @@ namespace OpenRA.Editor
|
||||
surface1.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SaveClicked(object sender, EventArgs e)
|
||||
{
|
||||
if (loadedMapName == null)
|
||||
@@ -328,28 +242,62 @@ namespace OpenRA.Editor
|
||||
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
|
||||
surface1.Map.Package = new Folder(loadedMapName);
|
||||
surface1.Map.Save(loadedMapName);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SaveAsClicked(object sender, EventArgs e)
|
||||
{
|
||||
folderBrowser.ShowNewFolderButton = true;
|
||||
|
||||
if (DialogResult.OK == folderBrowser.ShowDialog())
|
||||
using (var nms = new MapSelect())
|
||||
{
|
||||
loadedMapName = folderBrowser.SelectedPath;
|
||||
SaveClicked(sender, e);
|
||||
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
nms.txtNew.ReadOnly = false;
|
||||
nms.btnOk.Text = "Save";
|
||||
nms.txtNew.Text = "unnamed";
|
||||
nms.txtPathOut.ReadOnly = false;
|
||||
|
||||
if (DialogResult.OK == nms.ShowDialog())
|
||||
{
|
||||
if (nms.txtNew.Text == "")
|
||||
nms.txtNew.Text = "unnamed";
|
||||
|
||||
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
|
||||
loadedMapName = mapfoldername;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(mapfoldername);
|
||||
}
|
||||
catch (Exception ed)
|
||||
{
|
||||
MessageBox.Show("Directory creation failed: {0}", ed.ToString());
|
||||
}
|
||||
|
||||
SaveClicked(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenClicked(object sender, EventArgs e)
|
||||
{
|
||||
folderBrowser.ShowNewFolderButton = true;
|
||||
using (var nms = new MapSelect())
|
||||
{
|
||||
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
if (DialogResult.OK == folderBrowser.ShowDialog())
|
||||
LoadMap(folderBrowser.SelectedPath);
|
||||
nms.txtNew.ReadOnly = true;
|
||||
nms.txtPathOut.ReadOnly = true;
|
||||
nms.btnOk.Text = "Open";
|
||||
|
||||
if (DialogResult.OK == nms.ShowDialog())
|
||||
{
|
||||
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
|
||||
LoadMap(mapfoldername);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NewClicked(object sender, EventArgs e)
|
||||
@@ -362,13 +310,12 @@ namespace OpenRA.Editor
|
||||
|
||||
if (DialogResult.OK == nmd.ShowDialog())
|
||||
{
|
||||
var map = new Map();
|
||||
var map = new Map(nmd.theater.SelectedItem as string);
|
||||
|
||||
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
|
||||
|
||||
map.TopLeft = new int2((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value);
|
||||
map.BottomRight = new int2((int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
|
||||
map.Tileset = nmd.theater.SelectedItem as string;
|
||||
map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
|
||||
NewMap(map);
|
||||
}
|
||||
@@ -405,9 +352,11 @@ namespace OpenRA.Editor
|
||||
|
||||
void ImportLegacyMapClicked(object sender, EventArgs e)
|
||||
{
|
||||
var currentDirectory = Directory.GetCurrentDirectory();
|
||||
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
|
||||
if (DialogResult.OK == ofd.ShowDialog())
|
||||
{
|
||||
Directory.SetCurrentDirectory( currentDirectory );
|
||||
/* massive hack: we should be able to call NewMap() with the imported Map object,
|
||||
* but something's not right internally in it, unless loaded via the real maploader */
|
||||
|
||||
@@ -416,9 +365,9 @@ namespace OpenRA.Editor
|
||||
|
||||
var map = LegacyMapImporter.Import(ofd.FileName);
|
||||
map.Package = new Folder(savePath);
|
||||
map.Players.Add("Neutral", new PlayerReference("Neutral",
|
||||
map.Players.Add("Neutral", new PlayerReference("Neutral",
|
||||
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
|
||||
|
||||
|
||||
map.Save(savePath);
|
||||
LoadMap(savePath);
|
||||
loadedMapName = null; /* editor needs to think this hasnt been saved */
|
||||
@@ -432,7 +381,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
if (!dirty) return;
|
||||
|
||||
switch (MessageBox.Show("The map has been modified since it was last saved. Save changes now?",
|
||||
switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?",
|
||||
"Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
|
||||
{
|
||||
case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
|
||||
@@ -440,5 +389,38 @@ namespace OpenRA.Editor
|
||||
case DialogResult.Cancel: e.Cancel = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var pb = new PaletteBox();
|
||||
pb.Show();
|
||||
}
|
||||
|
||||
private void mnuMinimapToPNG_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
saveFileDialog.InitialDirectory = new string[] { Environment.CurrentDirectory, "maps" }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
FileInfo file = new FileInfo(loadedMapName + ".png");
|
||||
string name = file.Name;
|
||||
saveFileDialog.FileName = name;
|
||||
|
||||
saveFileDialog.ShowDialog();
|
||||
if (saveFileDialog.FileName == "")
|
||||
{
|
||||
saveFileDialog.FileName = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Bitmap png = new Bitmap(pmMiniMap.Image);
|
||||
|
||||
png.Save(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Png);
|
||||
}
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>309, 17</value>
|
||||
<value>198, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="newToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -237,6 +237,23 @@
|
||||
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
|
||||
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
|
||||
gg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="mnuMinimapToPNG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACR0lE
|
||||
QVQ4T6WTXUiTARSGdxkRRBdB0IUREV1EKRFEYYuQAklL8sKQfphUoJSUWJbLxAVZWqyBio5WajorM1PL
|
||||
xExUlLQfbU5n0lygRerMP/qxOZ92vpjfCKLAi3P5Puc957xHA2gWUoo49147gWUqbSPrdjOXChrQm56S
|
||||
lFVFvKEcXaqV2OQiohMt7Esw+6Ro5gGeWfhbff0BY9NzDI3N0f/JS6fLy7rd6f8HcNsdOI6EYD8cjK3V
|
||||
roiLawdYu+vivwHSWcQM1THz/DQv96+ixeHlVvU71oQFAGTmP+37bdsPBf8WZ4fRFhVEXdcsBQ9srN6Z
|
||||
pjqQhQUCAmcW29JZxA8fvaWyY5YcawdBOy6oANm2H9A3MMypDLNS7b1flJnFtnQWcVmrB2NhMytD9SpA
|
||||
TiUA5+CYInQOjWPrH2V7RBzmijdo9x5VKr+yj6ImD9nmelZsS1UBcme/+OPIJIOfv/Gi201ZXQ/hMfFU
|
||||
Peuktqnbd3QN+U/cXM6tYfmW8ypAQiKdh91TTE7PYHNOYKl6z916F3m+eSNjT1B4vxHjzWoFYrhRwbLN
|
||||
51SAJOynx8vo5Ay9rimKHzu5XtJDpuU1WZY2Eg1WgrXRJOpNxKdcUyBLN6WoAInnyPh3XvW6KW/4MC9O
|
||||
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
|
||||
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
|
||||
gg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="propertiesToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -291,7 +308,247 @@
|
||||
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="folderBrowser.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>182, 17</value>
|
||||
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>76, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>45</value>
|
||||
</metadata>
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAIAMDAAAAEAIACoJQAAJgAAACAgAAABACAAqBAAAM4lAAAoAAAAMAAAAGAAAAABACAAAAAAAAAk
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQAAAAQAAAAJQAA
|
||||
ADcAAAA+AAAAOAAAACoAAAAYAAAACwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAUAAAApAAAAVAAAAGIBAQFNAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAASAAAAOgAA
|
||||
AFkAAAA6AAAAMQEBAUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA
|
||||
AAoAAAAkAAAAUQAAAHkAAACJAAAAhQAAAHMAAABTAAAAMAAAABUAAAAGAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAIAAAAkAAAAaQEBAZYCAgLaAAAAWgAAAAsAAAABAAAAAAAAAAAAAAAAAAAABwAA
|
||||
AB8AAABMAAAAfwAAAHkAAAA8AgIAwgEBAWkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAQAAAA8AAAA9AAAAgwAAALMAAADFHRcU3QAAAMMAAACgAAAAdwAAAEUAAAAeAAAABwAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAUgAAAJgDBATpAgIG/wEAAI8AAAAYAAAABAAA
|
||||
AAIAAAAOAAAALgAAAGIAAACVAAAApgEAAJUEBADsAwQK/wAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABYAAABPAAAAngAAAMx3YFX3jXZv/5RuY/9mT0X2GxENygcG
|
||||
BYsAAABKAAAAGgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAKAAAAQAAAAJMBAQHRBApN/wQK
|
||||
U/8CAADQAQEARwAAACkAAABIAAAAeQAAAKMAAAC5AgAA1QQGJf8FC1v/AQEHrAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABwAAACEAAABcAAAApQICAtOFc2z8hnJt/5h6
|
||||
cf+hfXL/mHty/3VkXewZExGLAAAAOQAAAAwAAAABAAAAAQAAAAIAAAAFAAAACAAAABAAAAAqAAAAYwAA
|
||||
AKABAAC8AwAV+QUWxv8ED4P/BgcX/AEAALAAAACWAAAAsQAAAMkEBArzBAli/wMOtf8CCVD/AwIAbAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAEAAAADQAAAB1AAAAsgcE
|
||||
BNmHcGj8mYiB/6GMhf+lkIj/moiB/5qIgP9dTUfqAgICYAAAACAAAAAGAAAABAAAAAoAAAAZAAAAKgAA
|
||||
AEEAAABqAQEBmgEBAbkHCw7dBgcH+QEAi/8FHf//AgG0/wIABP8GFRntBiIw6wcYHf8BAET/AgR6/wMF
|
||||
X/8DACD5AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAAGwAA
|
||||
AE8AAACXAAAAxQwLCuGSfHX9momC/5yLg/+cjIX/mYaA/5aGf/+MdWv/GhUSoQAAAEAAAAAXAAAAEAAA
|
||||
AB8AAAA+AAAAZgAAAIwAAACtCQkJx0A5N+UYdqT/JsXu/wgdZ/8AAIr/Cyx0/x6Rwf8luf3/Jbv//yCd
|
||||
3P8TYIj/FWaB/xdtjf8EDhfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAEAAAAIAAAAKQAAAG4AAACxBwYD1HdiWPmcioL/mYiA/56Nhf+ejoX/lYV//5WGf/+Wgnv/U0M96AAA
|
||||
AHUAAAA4AAAALwAAAEYAAABzAAAApAAAAMIkGRHhIBkT6F1WVfYqPUb/KM3//yOt5f8NN0b/J8r+/ybE
|
||||
+P8ZfqT/G4ay/x6Tz/8hpej/IKTl/xuLwf8FExmmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAIAAAANAAAANwAAAIQAAAC+IhoW5Jt2av+Qfnf/no6G/5WHgP+vnpb/koJ7/5iG
|
||||
f/+Zh4D/k4B6/kU4M8UAAABvAAAAagAAAIcAAACsAAAAzAMDAt+FW0z8fV5R/VtQS/2PgHn/UUhH/yKV
|
||||
tf8z////I62//wcXX/8CBMz/AABw/w9HXv8muv3/Iq30/xh0p/8BAABfAAAABAAAAAIAAAABAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAYAAAAWAAAASAAAAJQAAADESzkz86CCd/+mlI3/rJyT/4Z5
|
||||
cf+djIX/m4qD/5CAef9xZF7/jHx1/3BiWe0GBQSzAAAAsAAAAMQBAQDWCgUE5U83KfaCa2D/lH11/3hp
|
||||
Y/+QgHn/noyF/xQODf8SU4X/CBuY/wUK//8BAOn/Cypv/yfC5v8luvf/IJvN/yKx+f8MKzrlAAAAIgAA
|
||||
ABAAAAAHAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAwAAAAqAAAAZgAAAKgAAADMVEdA+LKg
|
||||
mP+pmZH/rp+U/4Z3b/9+cGr/joB5/4R3cf9zZ1//dmhi/4p5cv8fHRjlAAAA3AYEBOQgGhfzV0U4/pqA
|
||||
df+wnpX/no6F/4V1bv9yZF7/ERIX/wUNzf8AAJ//AgK+/wAA8v8LJlr/K9bh/y/w//8NO0r/EEh+/ynZ
|
||||
//8SVHj/AAAAywAAAEgAAAAnAAAAEgAAAAQAAAABAAAAAAAAAAAAAAABAAAABAAAABcAAABIAAAAjwAA
|
||||
AMAAAADZZlxV+rSkmv+4qZ//oZGJ/419dv+QgHn/eGlh/35waP+Nf3b/emxl/5KCe/9kVEr+GxQO+Ug9
|
||||
OP2Mf3j+loZ+/52LhP+qmpH/oZGI/15STf8ICTL/CB30/wUTzv8il4j/HYac/wgcRf8qz93/NP///xZg
|
||||
av8AAJb/D0W8/y3h/f8TWZ7/AQBY/wYEAPABAQCJAAAAQwAAAB0AAAAIAAAAAAAAAAAAAAABAAAACQAA
|
||||
ACgAAABoAAAArQAAANCCaV74pJSN/8i4rf+omY//koF6/4t7dP9+b2j/koB5/5uJgv+UhHz/iXlx/3Bh
|
||||
XP9lW1f/UEM8/4F0bf+jk4r/m4qC/52Nhf+gj4f/OjIs/wgUf/8KKv//AgDw/xlhU/87////L+b//y3g
|
||||
8P8w7v//F2N//wAAqP8BAP//E1SY/y7n//8PPn//AADr/wYWv/8GCCv/AQMEuQAAAEkAAAAWAAAAAAAA
|
||||
AAAAAAAEAAAAEQAAADwAAACCAAAAvCUbGOKhjoT+sKCW/7ionf+Yh4D/gHBp/3hoYP+KeHH/kYF4/5+P
|
||||
h/+Xhn//h3hx/3hoYf+XhoD/cF5V/5WEff+ejYX/nYyF/21hWv8LCQz/ChmV/wop//8IJPr/Ch/z/wcS
|
||||
of8eiZD/Nv///zP///8jrKD/AABe/wYZ//8CAJ3/H4+m/yrT/v8IGoz/BAzS/wUWy/8GFKX/BQYm/wUG
|
||||
BOUBAQFBAAAAAAAAAAEAAAAHAAAAHgAAAFUAAACbAAAAyUc/Ou6ejYX/pJOL/6WUjP+ejoX/iXpz/4t7
|
||||
cv+Xh37/mId//5+Ohv+pmI//koJ5/5GBeP+cjIP/dGNb/4t7dP+bioP/iHx2/zEtKf8hHyT/KipE/yYk
|
||||
Jv8lIiX/ISEp/xkSPP8REA7/Gnh5/zb//f86//D/IqGV/wAAlf8NMYr/Nv///xhkgf8eKzT/KDg//xca
|
||||
Hf8lLDP/ERUd/wYHCu0BAQFxAAAAAAAAAAEAAAAMAAAAMAAAAHQAAAC0AwMD1WleWfidjYT/pZSL/5yK
|
||||
g/+OfHX/hnly/5CBef+Pfnb/m4uA/6aTiP+di4P/moqC/5mJgf+VhX3/lIN7/5eFfv+gjof/nIqE/5iH
|
||||
gP+djYT/kIF4/5CAeP+Le3P/hnZv/4x9df+UhX3/SD04/xA6bf8XW6z/EESi/wYMPv8y+f//JKu7/1uA
|
||||
kv+Nx+P/kcvn/1d4jv9KVmr/LD9N/xIfKacAAAAUAAAAAAAAAAIAAAAQAAAARAAAAJMAAADGKSYj5KWV
|
||||
jP+woJb/pZSM/4V0b/+MfXb/nYyE/5iJgf+UhHv/pI+G/6GRh/+Qf3j/lYR9/6CRiv+ZiID/mYeA/5mI
|
||||
gf+ci4P/n46G/5iIf/+KenP/gXBo/31tZf+GdG3/iHdv/4d1b/+LhYP/WGRm/wYASP8AAP//BAmf/zHr
|
||||
4f8jrK3/WH6O/3y71P+JxeH/jcjj/4292f9FWWj+JC86+QkPE3EAAAANAAAAAAAAAAIAAAATAAAAUAAA
|
||||
AKIAAADNh3p0/K2dk/+snZL/no2F/4N0bf+RgXr/jXx1/5yLg/+YiID/mYiA/5ODfP+NfHX/mYiB/56M
|
||||
hf+Yh4D/nY2E/5CBeP+Sgnr/loZ+/5qJgf+nl47/nY2E/5SEe/+PfXb/e3Rx/1Zocv9fg5L/Pml+/x4s
|
||||
Pf8OKmv/Ip6E/xhrdf9kjqD/i8zm/4HC3P+Fwdz/iL7X/32xyv8xPkn/Hiw28wUIClcAAAAMAAAAAAAA
|
||||
AAIAAAARAAAATQAAAKEAAADWqZqR/6STi/+ikon/b2Nd/3xqZP9wYlr/fm5n/4p5cv+OfXb/i3t0/4V1
|
||||
bv+MfHX/loR9/5qJgf+WhX3/jn53/4h3b/+Id2//mYmA/6OSiv+hkYn/qJiP/5uNhP9zdnj/T2h6/0uO
|
||||
rf9UlbP/Z7LP/052hv8RMD3/CSPV/woMIf+GxOD/gsbf/3+/3P+Dvdf/erDJ/3epwv9jla//HTxM6wAD
|
||||
BEQAAAAFAAAAAAAAAAMAAAAQAAAASgAAAJ4AAADQopOK/56Mhf+gj4f/kX95/4NzbP+DdG3/fGxl/35u
|
||||
Z/96a2P/dGZf/4R0bf+Nfnb/i3pz/5B/d/+TgXj/nY2E/5+Ohv+di4T/o5KK/6CPiP+fjof/oJGJ/2Vw
|
||||
dv8/X3T/Y6XF/1WiyP9cosb/drzY/3e51P8JD3b/Ch/e/z1WXv9/wNr/gL3W/4C92v+GxN3/baK9/4G8
|
||||
1P9/wuH/ETJIlwAAABQAAAACAAAAAQAAAAYAAAAXAAAAUAAAAKIAAADMjoJ5/6iYj/+qmpH/oI+H/5GB
|
||||
ev+SgXr/lYN8/5GBev+RgXn/koF6/41+dv+Le3L/jXdt/4x6c/+XhX3/mYeA/5iHgP+ejYX/opKJ/5qK
|
||||
gf+NfnX/a3By/zhhdv9orsv/YKvP/0uZv/9krc3/c7zZ/3u72P8sP1P/Cg8t/2qbrv9zrsf/e7TN/4W/
|
||||
2P+FwNv/erbR/3Oiwv9pqsf/AwkOUgAAAAgAAAABAAAAAwAAAA0AAAAoAAAAZQAAAKwAAADQm4yE/7Sl
|
||||
mv+klIv/oI+H/5iGgP+Le3T/lIN8/5ODfP+Ug33/lIJ7/5iHf/+ch3//kX54/3JjXf+Ugnz/loV+/5WE
|
||||
ff+ai4L/jHx0/4NzbP+HhYP/R2p//1iny/+Iyeb/O3Wo/0+fwv9vvNv/eL/c/3m72P9LcH7/DAoA/4jG
|
||||
3v93uNH/fL3X/4zD2/9/udX/f8De/4y+1/87cJDxAQIDLgAAAAcAAAAAAAAABwAAABwAAABKAAAAiQAA
|
||||
AL4AAADap5iP/66elf+hkIj/oI+I/5SDfP+Qf3j/koB5/5KAef+aioL/lYR8/56Ohf+ci4T/mIZ//4Ry
|
||||
bP+RgXr/momC/458df97bmX/gGRU/4l2bP9Qh6b/XqrO/2Oozf9hp8v/Ya3O/2q72v94vdz/gcbi/3y9
|
||||
2/9nnbD/U3OB/4zN5/+Bw9z/gL7a/32zyf92sMn/iMfg/3251f8pUWjIAQEBIQAAAAIAAAAAAAAADQAA
|
||||
ADQAAAB1AAAAsAAAAM8pIyDsrJuS/56Nhf+ejIX/k4J7/4Z1bv+Pfnf/kYF6/4d1b/+cjIP/mouD/5qI
|
||||
gf+UhH3/i3pz/4t5cv+XhX7/koB5/2teVf94fH//dK/I/2e42P9RkL7/YrDR/1qoyf9eqsv/WqbJ/3bB
|
||||
3v97w9//fcTh/32+3P+DxN//g8Db/4TJ4/9/v93/gbzX/3Kmv/9qqMD/i7/b/1N/p/8ZLjp9AgQEFgAA
|
||||
AAAAAAAAAAAAGAAAAEwAAACWAAAAxickIemAcWj/loV+/4t5cv9/bmf/fW1m/3BjW/96aGL/bmBZ/31t
|
||||
Zv+Ne3X/koF6/4x8df+FdW7/i3t0/5SCe/+Qf3j/gnFq/2trav9rtdT/bLTU/2KjyP9tt9f/X6XI/2Ow
|
||||
zf9Zp8r/Z7DQ/3m/3v+Axd//fL3b/3/B3v+IzOb/h8nk/4rL5P+ExeP/hMXe/2qeuf92scb/oc7q/0yC
|
||||
pv8OHihoAQEBDQAAAAAAAAAAAAAAJwAAAGMAAACqBwYG03FjXvqTgnv/bl9Y/3dnYP91Z2D/d2dg/3Bg
|
||||
W/98bGX/gnNs/3trZP+BcGj/fGxk/3NlXv+EdG3/lIV9/6COh/+NfHX/ZF5a/0p5nP9ajar/WJO9/3K+
|
||||
2v9/vdz/YKPG/2muzv9cqcn/ZbHR/3K72P9+wN3/hcXi/4fI5P+Jy+T/f8Dc/4fF3/+NzOX/iMbf/3m3
|
||||
0f9nlrT/b5uz/yhVb+YFCw5KAAEBCQAAAAAAAAAAAAAAQAAAAIMAAAC7CAUF21BEPv5uYFj/hndw/4l6
|
||||
cv+KenT/momB/5KBev+RgXr/k4F6/5mJgv+Tgnr/iHdw/4p5c/+ThH3/m4yF/6CPiP+CdXH/TnKL/0tv
|
||||
k/8hITb/M0Zh/2OjyP90u9j/abHO/2etzf9cqMn/Z7HR/3e92f95u9j/eb7b/5PV8P+Mzeb/fsPd/3/D
|
||||
3f+Szeb/h8Lf/3/A3v+Mu9T/RnGF/hEiMcwAAABAAAAABwAAAAAAAAAAAAAAXgAAAKQAAADMKCUj6ZmH
|
||||
gP+ejIX/lIN8/5iHf/+YiH//mYeA/5OCe/+UhH3/hXRu/4x6dP+SgHn/mYeA/5qJgf+bioP/loV+/4h3
|
||||
cf9bXl//bLrc/3S/4P9LdJj/KiNI/z1ehf9mr9L/d77b/1uoy/9Vo8b/bLDN/3q/3P97vdr/hMrj/5LQ
|
||||
7P+Oz+v/iMzm/4TF3/+Gwdz/hMbh/4rO6P+Oxd7/PGyF/hocHNUCAwNeAAABEQAAAAEAAAAAAAAAdQAA
|
||||
ALUAAADekIB7/pODev+ejob/mIeA/6iXj/+jkor/mIZ//5KAef+RgHn/jn12/5qIgf+cioP/no2F/6OR
|
||||
iv+hkYj/iHdw/2JVTf9NfJX/YqrR/3O31/93weH/VoKj/2+y0f9ppM3/ebvb/1Kfxf9nsdD/YKPG/3G3
|
||||
1v96vNn/gsTg/4rL5/+FyuT/gsTh/4jK5v+Fw93/d7/b/5zT7/97r8//Y6vF/zVZaNwRGx5dAAABEgAA
|
||||
AAIAAAAAAAAAiQAAAL8jHxzoq5yR/56Nhf+hkIj/rJyT/6mZkP+qmpH/m4uD/5KBev+WhX3/kH55/5WD
|
||||
fP+VhH3/oo+J/6iXj/+cjIP/c2Ja/3xwaP9WncX/abLS/3O62f9qtNT/d8Hd/3vD4P+MxuP/Y6bM/1up
|
||||
yv9qtdT/ZK3M/3jA3f95wN//hMrl/4rM5/+Ky+X/hcbk/4rO6P98u9v/hMni/6zZ9f9km77/K1V37gkQ
|
||||
FGoBAQEHAAAAAAAAAAAAAAAAAAAAngAAAMlZUEzxoI+H/6uckv+omI//oZCJ/6STi/+ikIr/nImD/5aE
|
||||
ff+aiIH/j313/4x7dP+UhH3/m4mC/6SUi/+Ugnv/cVxO/3ymuv9KibL/dLnZ/3rB3v9fpsj/b73b/3G5
|
||||
1v99x+P/ZLLQ/02Xwf9rtNj/fMXh/3O52P91vt3/eb7b/37A3f+HyOL/js/p/4/Q6v+Dx+T/erPX/5XL
|
||||
5/9Jl7v+GjJBrgEBAQoAAAAAAAAAAAAAAAAAAAAAAAAApw0NDdaIeHD9kX95/6qbkf+unpX/j395/459
|
||||
dv+pmJD/n46H/56Ohf+gkIj/kH95/4x8dv+JeXL/kIB4/5WFfP9yZmH/b36H/2aqzv9nr8//esLe/3m/
|
||||
3v9rtdT/arbW/2iz0P9rvdr/UqbG/2q41P9gqs3/crjX/2Spzf+AyeT/f8Hd/3m+2/+Cx+H/k9Ht/4rH
|
||||
5P+Fx+T/mc7p/2amxP8nSF36AAAAawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqBUSEN2Ug3r9lYV8/6OT
|
||||
iv+klIv/l4V+/4p6dP+omI//p5aO/56Ohf+WhX3/j394/3hoZP9uXFb/emtk/3NnXv9ydXn/bLXV/2Sp
|
||||
zv92vdz/fcbh/3zE4f9xu9v/Z67Q/16kx/9QnMD/Xq/O/2Wy0f94wN3/c7jV/3q83P9encj/gsrj/33C
|
||||
3v+CxN//jMjk/4bI4/+Lz+n/lM/q/0d+nf8sLiv3BQYHTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArg8P
|
||||
DdqSgX38qZiQ/6WVjP+ci4P/lYR9/419d/+KeHH/opGJ/5WFfP91YlX/hGpX/2ZkY/9HUlj/OFVn/1eQ
|
||||
tf9fpcj/Y6jP/3W+3f96wt7/drrX/36/3f9+x+L/bbjV/2241f9hsc7/ZrTS/2u41P92udX/h83o/4fI
|
||||
5f97wd3/dr3a/3K72/+DxuL/hsfj/3jA3P+c0+//fLPT/2avyf5HfZLyHzI3SwAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAux0aGuGWhH39rp6V/6qbkf+Yh3//koB6/5B/ef+Rf3j/fWtk/4huXf+jrK//d7jX/2Ow
|
||||
1v9kstb/Up3I/2Wlyv9krdD/Y6/S/2y52f9ut9b/er3Z/4PG4v99wt7/f8Xh/3jE4P91wd7/bbrW/3W9
|
||||
2v99w97/hMnl/4jL5/+BxuD/i8/p/3m+3v+Izef/fbzc/4XK4/+s2fX/ZZ7C/y1dhOwTJzK9FxobTQAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAxzo0Muqbi4T/saKY/7Cgl/+fjYb/kIB6/49+d/+Bcmn/fGxg/3u7
|
||||
1P9sqc3/Z6vP/2Kny/9vuNf/abfW/3O72P95w9//cLjV/3C+2v9wuNX/gsTh/33A3/9wudb/db7b/2i1
|
||||
0v9uutf/cLzY/4HG4v+P0er/icvk/4XH4v+Ozej/itDr/43S7P+O0Ov/hcnm/3q02P+TyeX+SZu//yNH
|
||||
XKEHBwcnCgkITAAAAAEAAAAAAAAAAAAAAAAAAAABCwsNtZKEfPicjIX/sqKY/66elP+hj4n/opGJ/5GC
|
||||
ef+OfnP/icbj/1qdw/9ZmL//f8Xh/3fA3f91wd3/eb7d/4PL5f+EyuP/fsbg/3e+3f93vNv/gMHe/3u9
|
||||
3P9wt9T/dbnW/2m21f9rtNP/cbnW/3693f9dh7T/Ypa8/4bH4f9zp8f/gsLf/47M6P+R0On/jtDs/5jP
|
||||
6v9mp8X/GTJFrgAAACYCAgISAgMDEwYGBxAAAAAAAAAAAAAAAAAAAAABExMTgJCGffWdj4f/t6ee/6iX
|
||||
jv+tnJT/pZWM/5KBc/+WtML/ZqbL/2Gkyv9xvt3/fMXh/3rB3v93vdz/g8nl/37E4P90vdn/ecDd/3nA
|
||||
3f97vdz/d7jV/3a71/96wd7/fr/d/3G41f9zuNX/hcfk/1yMtP9Fa5n/LUd8/2yhxP9RcJj/cqPG/4nC
|
||||
3/+MyuP/hc3n/5PO6v9Hf5//AwUFYgAAAB8AAAAHBAMDCAsLDBoEBAQHAAAAAAAAAAAAAAAAAAAADwcH
|
||||
BzMPDg1MPTk2ro6EevKbjYT/o5SK/6GKev95vNn/aqrO/3O61/99xOP/esLe/37E3/96xd//e8Pf/3i9
|
||||
2v9qstL/a7bT/3W+2v9wtNH/dLnV/2+20/9yvdf/eLnW/36+2/+Mzur/i9Pt/16cxP85XpP/Q1mD/2CV
|
||||
vf9roMP/jMfi/4nF4f+DyOL/hMnm/2yfwv5lvNn/TImj2wAAABMAAAADAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAABAAAABgAAABYAAAA4FBIQlIKCgux4qsn3dKvM/H/A3f+Ky+j/i8nl/4HG
|
||||
4v94vdz/gsLf/4TI4v90u9j/dbva/3W51v9xuNf/bbXS/3O82f99vtz/ervZ/4jK5f+T1fL/iMvn/3m8
|
||||
3v98vt3/TnWg/1qQvP96ttf/h8jk/1aErf9qs9P/n9Tv/2ufv/8lUoL+ECQ0jwAAAAwAAAABAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAEAAAACgAAAB4OEBFRHiktejZN
|
||||
WKdagZTVaY2i4GiRpPF+ssv/kdPv/5DV8f+Fy+f/hMPf/4bI5P9/xuP/ebzb/3m92v94vNn/fMHd/4/Q
|
||||
6v+W1PD/l9jy/4fF4f9HcqH/aqHI/3Ot0f9Mf6v/h8Xi/3y93f8lTIL/iL/f/3Cx1P8mTG3QAAAAHwAA
|
||||
AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAABAAAAAwAAAAcDBAQYBQYHJQYICTsNEhVlJTM8w1Buf/9Zeo7/i87q/4PE4P+SzOn/icbj/3e4
|
||||
1f97wt//isbi/5PR7f+b2PX/ldPp/4S72v9hmcL/ZqHI/1mMuv+Gw+D/aaPK/1CLuf9hibj/ic3n/kh4
|
||||
qf8OGCV2AAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAADgAAADIAAAByJzlD0Xmz
|
||||
zvx/vNn/gb/e/3W20/+Exd//k8vn/5nU7/+V0Oz/mNTw/5/a8v9xrtL/UIW0/1WBsP80YJn/h8Pi/4fN
|
||||
6P9nmsb/SYqz/1+WsvIHCw4+AAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAQAAAAPAAAAHxAVGmwxSVajUHqN00Jkdsg8WWW2NlFewXOftfSc1PD/kc7r/4O72/9zrtH/bpzE/2OL
|
||||
u/9Zi73/ib3d/2WSvf9oiLf/TYCr/z9phdIDBQcsAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAHAwQFFAEBARUAAAAUAAAAJQYHCFUyQkquUnmO7m+i
|
||||
yf9oosb/cKPC/1N4rP9ZgKz/isPg/2SXwv9Yibf/OnGf/xkoSawAAAAbAAAAAQAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAA
|
||||
AAcAAAAPAAAAGwUGB2UGBgiAIC40vHGbv/pnm8H+jcfg/1yJvf+Bt9f/T4Op+Q8bInUAAAANAAAAAQAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAALAAAAGgkLD1UfLDWMITVCrT1ced93pMf/c6bE/BMd
|
||||
IVUAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAAIAAAAFgID
|
||||
AysUHSFgHC02gQAAAAoAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AB/gfgP
|
||||
AAD8AD+AcA8AAPwAH8AADwAA/AAPgAAfAAD4AAAAAB8AAPgAAAAAHwAA8AAAAAA/AADwAAAAAD8AAPAA
|
||||
AAAABwAA4AAAAAABAADgAAAAAAAAAMAAAAAAAAAAwAAAAAAAAADAAAAAAAAAAIAAAAAAAAAAgAAAAAAA
|
||||
AACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA
|
||||
AAAAAwAAAAAAAAADAAAAAAAAAAMAAAAAAAAAAwAAAAAAAAABAAAAAAAAAAEAAAAAAAAABwAAAAAAAAAP
|
||||
AAAAAAAAAB8AAAAAAAAAHwAAAAAAAAAfAAAAAAAAAB8AAAAAAAAADgAAAAAAAAAOAAAAAAAAAAcAAAAA
|
||||
AAAAPwAAwAAAAAA/AADwAAAAAH8AAP8AAAAA/wAA//gAAAD/AAD//wAAAP8AAP//wAAA/wAA///+AAD/
|
||||
AAD////wAf8AAP////wB/wAAKAAAACAAAABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAABAAAAEQAAADsAAABeAAAAXwAAAEIAAAAeAAAACAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAFQAAAF8CAgKIAAAAMAAAAAMAAAAAAAAAAAAAAAQAAAAhAAAAXQAAAFMBAQB6AQEBLAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAmAAAAgwAAALwdFxTdAAAAsgAAAHcAAAAyAAAABwAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAJAAAAUgICAsECAgb/AQAAVAAAAAQAAAAIAAAALgAAAHwAAACmAgIAwQME
|
||||
Cv8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABgAAADkAAACiQTYw5Yp0bv+ObWP9WkVA5SYg
|
||||
HJQAAAAqAAAABQAAAAEAAAACAAAABAAAABIAAABSAQEBsAQFMPwEC2f0BAQLogEAAG4AAACVAQECxgMF
|
||||
MeoEC2L/AwIEjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAQAAAAVQAAALJIOzbrmYiB/6OO
|
||||
h/+aiIH/fGtk9QICAmAAAAATAAAABAAAABIAAAAqAAAAVgEBAZoFBgjLBgcH+QMPxf8CAbT/BAsO9gYi
|
||||
MOsEDDH/AgR6/wMDP/wAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAACIAAACCAwICzWxd
|
||||
V/aaiYH/nY2F/5eGgP+UgXn/Ny0nxQAAAEIAAAAgAAAARgAAAIUJBgS4FBEO2DdQXvcnyff/DkGI/xl7
|
||||
uf8ho9f/IKHZ/x2Ox/8bhbP/DkZf4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAANwAA
|
||||
AKEiGhbklnpx/56Ohv+ik4v/koJ7/5mHgP+TgHr+Ih0amgAAAGoAAACaAAAAzEQvJ+59XlH9dmlj/lFI
|
||||
R/8rytr/I62//wUOlv8AAHD/G4Gu/yKt9P8MOlSvAAAABAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
|
||||
ABUAAABXAAAAs09BOvaplIz/rZ6U/4p8dP+VhX7/f3Fq/4FybP9IQDrhAAAAxgoJB90wJh3yh29k/ZmG
|
||||
ff+AcWr/WE9O/wscgP8FD6v/BQzN/xuAqP8iqsr/GHKm/xqDq/kAAAB3AAAAIgAAAAsAAAACAAAAAAAA
|
||||
AAEAAAAEAAAAMAAAAI8AAADNZlxV+rannf+hkYn/j394/3hpYf+GeG//emxl/3trY/8bFA75a15Y/paG
|
||||
fv+kk4v/oZGI/zMuQP8IHfT/FFWr/x2GnP8ZdpH/NP///wswgP8PRbz/IJ3O/wEAWP8EAwC9AAAAQwAA
|
||||
ABMAAAAAAAAAAgAAAA0AAABUAAAAtVNGP+qqmpL/sKGX/4l5cv+Dc2z/koF5/5qJgf+IeXH/emtm/2BR
|
||||
Sf+Wh3//nIuE/25iXf8iJmH/CSPe/wYQ8v8ff6H/M/P//y3f5P8MMm//AwfR/xlyn/8chcL/Agbf/wYS
|
||||
l/8DBBXcAgICYgAAAAAAAAAEAAAAHgAAAHgAAADJcmZg96STi/+ikYn/iXpz/5GBeP+Yh3//pJOL/5KC
|
||||
ef+Xh37/dGNb/5ODfP+IfHb/KSYn/yoqRP8mIyb/ISEp/xURJf8aeHn/OP/3/yKhlf8HGZD/Nv///xtI
|
||||
W/8oOD//HiMo/xEVHf8DBQWvAAAAAAAAAAgAAAA6AAAAoRcVEt2XiH/+pZSM/49+eP+Sg3v/k4R7/6CN
|
||||
g/+ejIP/mIeA/5qKgv+XhX7/nIqD/56Mhf+Whn7/iXlw/4h4cP+Hd2//jX95/1BRT/8MJpn/Cieh/yOo
|
||||
s/8+laX/fLLL/4/K5f9deY//KTZD/AcMEE8AAAAAAAAACwAAAFAAAAC4h3p0/K2dk/+ejYX/int0/418
|
||||
df+aioL/mYiA/5CAef+ZiIH/m4qD/52NhP+Rgnn/loZ+/6GQiP+djYT/koF5/3t0cf9bdoL/Pml+/xYr
|
||||
VP8inoT/Pn2L/4vM5v+Dwtz/iL7X/1d4iv8eLDbzAwQFMgAAAAAAAAAKAAAATAAAALqml47/oZGI/4Bx
|
||||
a/99bWb/fW1m/4R0bf+AcWr/iXly/5F/eP+VhHz/loZ+/5OCev+ejoX/oZGJ/6SVjP9tdXr/WYeg/1Wa
|
||||
vP9vt9T/OFyE/woh2v9Teo//gcLb/4LA2/90qcP/d6/K/xc2S8EAAQEYAAAAAQAAAA8AAABQAAAAt46C
|
||||
ef+pmZD/oI+H/5KBev+Vg3z/kYF6/5KBev+MfXT/jXdt/5KAeP+Zh4D/m4qD/6KSif+UhHv/a3By/1CI
|
||||
of9gq8//WKPG/3O82f9UfZb/Cg8t/2+lu/97tM3/hcDa/3q20f9upsX/AwkOUgAAAAUAAAAFAAAAJwAA
|
||||
AHcAAADFoZKK/6qakf+gj4j/koF6/5OCe/+VhH7/lYN8/5yKgv+Vgnz/h3dw/5iHgP+Pf3f/hnBk/3l+
|
||||
gf9Tiqf/abDT/06Ru/9otdX/fcPf/2qiuf8wP0H/hMTd/36+2f+AuNH/hMTf/1uPqu4BAgIoAAAAAwAA
|
||||
AA0AAABVAAAAsBUREd6sm5L/no2F/5OCe/+LenP/kYF6/5KBef+ai4P/l4Z//4t6c/+Rf3j/koB5/3Jt
|
||||
av90r8j/XKTL/2Kw0f9cqcr/WqbJ/3nC3/99xOH/gMHe/4PA2/+CxOD/gbzX/26nwP+Lv9v/NlZxvgIE
|
||||
BBYAAAAAAAAAIAAAAHwDAgLNal9Z+YJya/9+bmf/empj/3ZmYP94amP/gnFq/4d3b/+Dc2z/kIB5/5WD
|
||||
fP9zaGL/X4qh/2Kkyf9xttb/YKTH/2GszP9msdH/e8Dd/4HB3/+GyeP/g8Xg/4nJ4/+Gxt//cKjC/4i1
|
||||
z/8iQFOmAQEBCwAAAAAAAABAAAAAnwgFBdtfUkv/hndw/4p6c/+aiYH/koF6/5OBev+Whn7/iHdw/49/
|
||||
eP+bjIX/kYJ9/05yi/82SGX/M0Zh/2yv0P9psc7/YqvL/2ex0f94vNn/eb7b/5DR6/9+w93/icji/4fC
|
||||
3/+Gvtn/RnGF/gkRGYYAAAAHAAAAAAAAAGoAAADBXVJO9JuKgv+WhX7/n4+G/5mHgP+Tgnv/inly/5WD
|
||||
ff+cioP/n46G/49+d/9lam3/Z7LX/2urzP9AU3b/X5m+/3i92/9bp8r/ZqrK/3m82v+Dx+L/jM7p/4XI
|
||||
5P+GxeD/fsPe/4zG4f9QjKb/GCUqnAAAARIAAAABAAAAiREQD9SrnJH/oI+H/6yck/+qmpH/m4uD/5SD
|
||||
fP+Qfnn/lYR9/6KPif+ikon/c2Ja/2mHl/9pstL/b7fX/3fB3f+ExeL/Y6bM/2Ovz/9krcz/ecDe/4TK
|
||||
5f+KzOb/hcbk/4PF4v+EyeL/iLra/ytVd+4FCQs5AAAAAAAAAAAAAACjPDYz5JmHgP+rnJL/mIiB/6CP
|
||||
h/+ejIX/nIuD/5B+eP+Ofnf/loV9/5CBef9wbWv/ZaPD/3e+3P9wt9b/bbrZ/3G82f9brMv/YazP/3e/
|
||||
3P9zu9r/fMDc/4HE3/+R0Ov/icrm/4rB4P9blLH+DRohjQEBAQMAAAAAAAAAAAAAAKhVSkbtlYV8/6SU
|
||||
i/+XhX7/mYmC/6eWjv+aioH/j394/3NiXf96a2T/c25s/2y11f9ts9X/fcbh/3fA3v9nrtD/V6DE/16v
|
||||
zv9vudf/c7jV/2yt0v+CyuP/gMPf/4zI5P+JzOb/lM/q/zlWY/sFBgdPAAAAAAAAAAAAAAAAAAAAtVZM
|
||||
SO2sm5P/oZGI/5SCfP+PfXf/kH53/46BeP9+kZf/Xoaa/0V5mP9gosb/Y6zR/3O82/94vNj/f8Tg/3a/
|
||||
2/9vvNn/arfU/3W92f+Gy+f/g8fj/4HG4v9+xOH/gsLg/5LO6f9xqcv/PG2F5xsmKUwAAAAAAAAAAAAA
|
||||
AAAAAADHa19a9bGimP+ol4//kIB6/4h4cP98bGD/dLLR/2erz/9psNH/abfW/3a/3P9wuNX/cLvY/4LE
|
||||
4f93vdv/db7b/2u41f9wvNj/iMzm/4nL5P+KyuX/itDr/47R7P+Fyeb/h7/f/0mbv/8VJzJkCgkITAAA
|
||||
AAEAAAAAAAAAARAQEJuXioL7taWb/6qZkP+kk4v/ko6J/3i21/9ipsv/fsXh/3jA3f9+xOH/f8bh/3zD
|
||||
3/95vt3/fL3a/3e82v96vNr/brfV/3vA3f9gj7j/SG+c/26gwf96s9P/jsrl/4rP6v92sc//DhwliAEB
|
||||
ARgDAwMOBgYGDQAAAAAAAAABAAAADwsLCkA9OTaulImA+aOUiv+No6r/aqrO/3i/3f96wt7/fMXf/3vD
|
||||
3/9xuNb/a7bT/3O51v90udX/cbrV/3i51v+FxuP/i9Pt/0x9rP9DWYP/ZpvA/4zH4v+Gx+L/hMnm/2mu
|
||||
zv9MiaPbAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAVCgkIT0NPWJVJan27Zpas33mq
|
||||
xPB4ssz8isvn/4TJ5f99v93/e8De/3O51/95vdv/e77b/5HR7f+Q0u3/ca3Q/1yLtP9lncT/h8fj/1mR
|
||||
uP+Uyuf/Snuh9AgSGlcAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA
|
||||
AAMCAgIQBQYHJQoND1AlMzzDVXSH/4vO6v+LyOX/icbj/3m92v+KxuL/l9Xx/5XT6f9zqs7/ZqHI/3Co
|
||||
zf9po8r/WYq5/4nN5/4rSGe7AAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAcAAAAuFB0ieE9zhsNonLbpXo+k32SNo+CQxeD9ldHu/4K9
|
||||
3P9fkbz/Un6x/4jA4P9vocn/S4Wv/ypEU4wAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQMEBRQBAQEVAAAAJRwl
|
||||
KoJSeY7ubKLI/3Cjwv9WfKz/isPg/16Qvf86cZ//DRQlZAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAEAAAABAAAABgAAAA4DAwQ+ERcaa0BccbdWfpDWZY+092GVtvsJDxE3AAAAAQAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQAAABYLEBJGHC02gQAAAAYAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADwD4MD8AeAA+AAAAfgAAAH4AAAD+AAAAPAAAAAgAAAAIAAAACAAAAAgAAAAIAA
|
||||
AACAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAAAAAAAAwAAAAMAAAAHAAAABwAAAAIAAAACAAAAD4AA
|
||||
AA/4AAAf/4AAH//wAB///gAf///wPw==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -17,6 +17,7 @@ using OpenRA;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
@@ -401,7 +402,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
|
||||
new OwnerInit(parts[0]),
|
||||
new HealthInit(float.Parse(parts[2])/256),
|
||||
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
|
||||
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
|
||||
new ActorStanceInit(stance),
|
||||
};
|
||||
|
||||
375
OpenRA.Editor/MapSelect.Designer.cs
generated
Normal file
375
OpenRA.Editor/MapSelect.Designer.cs
generated
Normal file
@@ -0,0 +1,375 @@
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
partial class MapSelect
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
/// <param name="disposing">TODO</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Код, автоматически созданный конструктором форм Windows
|
||||
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MapSelect));
|
||||
this.MapList = new System.Windows.Forms.ListView();
|
||||
this.colMapName = new System.Windows.Forms.ColumnHeader("(отсутствует)");
|
||||
this.MapIconsList = new System.Windows.Forms.ImageList(this.components);
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.lblNew = new System.Windows.Forms.Label();
|
||||
this.txtNew = new System.Windows.Forms.TextBox();
|
||||
this.pbMinimap = new System.Windows.Forms.PictureBox();
|
||||
this.pnlBottom = new System.Windows.Forms.Panel();
|
||||
this.txtPathOut = new System.Windows.Forms.TextBox();
|
||||
this.lblPathOut = new System.Windows.Forms.Label();
|
||||
this.lblPath = new System.Windows.Forms.Label();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.lblMapList = new System.Windows.Forms.Label();
|
||||
this.txtDesc = new System.Windows.Forms.TextBox();
|
||||
this.lblDesc = new System.Windows.Forms.Label();
|
||||
this.txtTheater = new System.Windows.Forms.TextBox();
|
||||
this.lblTheater = new System.Windows.Forms.Label();
|
||||
this.txtAuthor = new System.Windows.Forms.TextBox();
|
||||
this.lblAuthor = new System.Windows.Forms.Label();
|
||||
this.txtTitle = new System.Windows.Forms.TextBox();
|
||||
this.lblMapName = new System.Windows.Forms.Label();
|
||||
this.lblMinimap = new System.Windows.Forms.Label();
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).BeginInit();
|
||||
this.pnlBottom.SuspendLayout();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// MapList
|
||||
//
|
||||
this.MapList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.MapList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.colMapName});
|
||||
this.MapList.FullRowSelect = true;
|
||||
this.MapList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
|
||||
this.MapList.LargeImageList = this.MapIconsList;
|
||||
this.MapList.Location = new System.Drawing.Point(15, 25);
|
||||
this.MapList.MultiSelect = false;
|
||||
this.MapList.Name = "MapList";
|
||||
this.MapList.Size = new System.Drawing.Size(273, 294);
|
||||
this.MapList.SmallImageList = this.MapIconsList;
|
||||
this.MapList.StateImageList = this.MapIconsList;
|
||||
this.MapList.TabIndex = 0;
|
||||
this.MapList.UseCompatibleStateImageBehavior = false;
|
||||
this.MapList.View = System.Windows.Forms.View.Details;
|
||||
this.MapList.SelectedIndexChanged += new System.EventHandler(this.MapList_SelectedIndexChanged);
|
||||
//
|
||||
// colMapName
|
||||
//
|
||||
this.colMapName.Text = "Map name";
|
||||
this.colMapName.Width = 240;
|
||||
//
|
||||
// MapIconsList
|
||||
//
|
||||
this.MapIconsList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
|
||||
this.MapIconsList.ImageSize = new System.Drawing.Size(24, 24);
|
||||
this.MapIconsList.TransparentColor = System.Drawing.Color.Transparent;
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(407, 35);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 3;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnOk.Location = new System.Drawing.Point(326, 35);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 2;
|
||||
this.btnOk.Text = "Open";
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// lblNew
|
||||
//
|
||||
this.lblNew.AutoSize = true;
|
||||
this.lblNew.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
this.lblNew.Location = new System.Drawing.Point(12, 40);
|
||||
this.lblNew.Name = "lblNew";
|
||||
this.lblNew.Size = new System.Drawing.Size(69, 13);
|
||||
this.lblNew.TabIndex = 3;
|
||||
this.lblNew.Text = "Map name:";
|
||||
//
|
||||
// txtNew
|
||||
//
|
||||
this.txtNew.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.txtNew.Location = new System.Drawing.Point(88, 37);
|
||||
this.txtNew.Name = "txtNew";
|
||||
this.txtNew.ReadOnly = true;
|
||||
this.txtNew.Size = new System.Drawing.Size(232, 20);
|
||||
this.txtNew.TabIndex = 1;
|
||||
//
|
||||
// pbMinimap
|
||||
//
|
||||
this.pbMinimap.BackColor = System.Drawing.Color.Black;
|
||||
this.pbMinimap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.pbMinimap.Location = new System.Drawing.Point(32, 25);
|
||||
this.pbMinimap.Name = "pbMinimap";
|
||||
this.pbMinimap.Size = new System.Drawing.Size(124, 124);
|
||||
this.pbMinimap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pbMinimap.TabIndex = 5;
|
||||
this.pbMinimap.TabStop = false;
|
||||
//
|
||||
// pnlBottom
|
||||
//
|
||||
this.pnlBottom.Controls.Add(this.pictureBox1);
|
||||
this.pnlBottom.Controls.Add(this.txtPathOut);
|
||||
this.pnlBottom.Controls.Add(this.lblPathOut);
|
||||
this.pnlBottom.Controls.Add(this.lblPath);
|
||||
this.pnlBottom.Controls.Add(this.btnCancel);
|
||||
this.pnlBottom.Controls.Add(this.btnOk);
|
||||
this.pnlBottom.Controls.Add(this.txtNew);
|
||||
this.pnlBottom.Controls.Add(this.lblNew);
|
||||
this.pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.pnlBottom.Location = new System.Drawing.Point(0, 332);
|
||||
this.pnlBottom.MaximumSize = new System.Drawing.Size(0, 70);
|
||||
this.pnlBottom.Name = "pnlBottom";
|
||||
this.pnlBottom.Size = new System.Drawing.Size(494, 70);
|
||||
this.pnlBottom.TabIndex = 6;
|
||||
//
|
||||
// txtPathOut
|
||||
//
|
||||
this.txtPathOut.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.txtPathOut.Location = new System.Drawing.Point(55, 10);
|
||||
this.txtPathOut.Name = "txtPathOut";
|
||||
this.txtPathOut.ReadOnly = true;
|
||||
this.txtPathOut.Size = new System.Drawing.Size(265, 20);
|
||||
this.txtPathOut.TabIndex = 0;
|
||||
this.txtPathOut.TextChanged += new System.EventHandler(this.txtPathOut_TextChanged);
|
||||
//
|
||||
// lblPathOut
|
||||
//
|
||||
this.lblPathOut.AutoSize = true;
|
||||
this.lblPathOut.Location = new System.Drawing.Point(55, 13);
|
||||
this.lblPathOut.Name = "lblPathOut";
|
||||
this.lblPathOut.Size = new System.Drawing.Size(0, 13);
|
||||
this.lblPathOut.TabIndex = 6;
|
||||
//
|
||||
// lblPath
|
||||
//
|
||||
this.lblPath.AutoSize = true;
|
||||
this.lblPath.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
this.lblPath.Location = new System.Drawing.Point(12, 13);
|
||||
this.lblPath.Name = "lblPath";
|
||||
this.lblPath.Size = new System.Drawing.Size(37, 13);
|
||||
this.lblPath.TabIndex = 5;
|
||||
this.lblPath.Text = "Path:";
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.lblMapList);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.MapList);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.txtDesc);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lblDesc);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.txtTheater);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lblTheater);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.txtAuthor);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lblAuthor);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.txtTitle);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lblMapName);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lblMinimap);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.pbMinimap);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(494, 332);
|
||||
this.splitContainer1.SplitterDistance = 300;
|
||||
this.splitContainer1.TabIndex = 7;
|
||||
//
|
||||
// lblMapList
|
||||
//
|
||||
this.lblMapList.AutoSize = true;
|
||||
this.lblMapList.Location = new System.Drawing.Point(12, 9);
|
||||
this.lblMapList.Name = "lblMapList";
|
||||
this.lblMapList.Size = new System.Drawing.Size(81, 13);
|
||||
this.lblMapList.TabIndex = 1;
|
||||
this.lblMapList.Text = "Available maps:";
|
||||
//
|
||||
// txtDesc
|
||||
//
|
||||
this.txtDesc.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.txtDesc.Location = new System.Drawing.Point(16, 289);
|
||||
this.txtDesc.Name = "txtDesc";
|
||||
this.txtDesc.ReadOnly = true;
|
||||
this.txtDesc.Size = new System.Drawing.Size(162, 20);
|
||||
this.txtDesc.TabIndex = 14;
|
||||
//
|
||||
// lblDesc
|
||||
//
|
||||
this.lblDesc.AutoSize = true;
|
||||
this.lblDesc.Location = new System.Drawing.Point(13, 273);
|
||||
this.lblDesc.Name = "lblDesc";
|
||||
this.lblDesc.Size = new System.Drawing.Size(63, 13);
|
||||
this.lblDesc.TabIndex = 13;
|
||||
this.lblDesc.Text = "Description:";
|
||||
//
|
||||
// txtTheater
|
||||
//
|
||||
this.txtTheater.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.txtTheater.Location = new System.Drawing.Point(16, 252);
|
||||
this.txtTheater.Name = "txtTheater";
|
||||
this.txtTheater.ReadOnly = true;
|
||||
this.txtTheater.Size = new System.Drawing.Size(162, 20);
|
||||
this.txtTheater.TabIndex = 12;
|
||||
//
|
||||
// lblTheater
|
||||
//
|
||||
this.lblTheater.AutoSize = true;
|
||||
this.lblTheater.Location = new System.Drawing.Point(13, 236);
|
||||
this.lblTheater.Name = "lblTheater";
|
||||
this.lblTheater.Size = new System.Drawing.Size(47, 13);
|
||||
this.lblTheater.TabIndex = 11;
|
||||
this.lblTheater.Text = "Theater:";
|
||||
//
|
||||
// txtAuthor
|
||||
//
|
||||
this.txtAuthor.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.txtAuthor.Location = new System.Drawing.Point(16, 214);
|
||||
this.txtAuthor.Name = "txtAuthor";
|
||||
this.txtAuthor.ReadOnly = true;
|
||||
this.txtAuthor.Size = new System.Drawing.Size(162, 20);
|
||||
this.txtAuthor.TabIndex = 10;
|
||||
//
|
||||
// lblAuthor
|
||||
//
|
||||
this.lblAuthor.AutoSize = true;
|
||||
this.lblAuthor.Location = new System.Drawing.Point(13, 198);
|
||||
this.lblAuthor.Name = "lblAuthor";
|
||||
this.lblAuthor.Size = new System.Drawing.Size(41, 13);
|
||||
this.lblAuthor.TabIndex = 9;
|
||||
this.lblAuthor.Text = "Author:";
|
||||
//
|
||||
// txtTitle
|
||||
//
|
||||
this.txtTitle.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.txtTitle.Location = new System.Drawing.Point(16, 177);
|
||||
this.txtTitle.Name = "txtTitle";
|
||||
this.txtTitle.ReadOnly = true;
|
||||
this.txtTitle.Size = new System.Drawing.Size(162, 20);
|
||||
this.txtTitle.TabIndex = 8;
|
||||
//
|
||||
// lblMapName
|
||||
//
|
||||
this.lblMapName.AutoSize = true;
|
||||
this.lblMapName.Location = new System.Drawing.Point(13, 161);
|
||||
this.lblMapName.Name = "lblMapName";
|
||||
this.lblMapName.Size = new System.Drawing.Size(30, 13);
|
||||
this.lblMapName.TabIndex = 7;
|
||||
this.lblMapName.Text = "Title:";
|
||||
//
|
||||
// lblMinimap
|
||||
//
|
||||
this.lblMinimap.AutoSize = true;
|
||||
this.lblMinimap.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
this.lblMinimap.Location = new System.Drawing.Point(29, 9);
|
||||
this.lblMinimap.Name = "lblMinimap";
|
||||
this.lblMinimap.Size = new System.Drawing.Size(71, 13);
|
||||
this.lblMinimap.TabIndex = 6;
|
||||
this.lblMinimap.Text = "Map preview:";
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
|
||||
this.pictureBox1.Location = new System.Drawing.Point(336, -9);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(54, 35);
|
||||
this.pictureBox1.TabIndex = 7;
|
||||
this.pictureBox1.TabStop = false;
|
||||
this.pictureBox1.Visible = false;
|
||||
//
|
||||
// MapSelect
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(494, 402);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Controls.Add(this.pnlBottom);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "MapSelect";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Select map";
|
||||
this.Load += new System.EventHandler(this.MapSelect_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).EndInit();
|
||||
this.pnlBottom.ResumeLayout(false);
|
||||
this.pnlBottom.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.PerformLayout();
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.PerformLayout();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public System.Windows.Forms.ListView MapList;
|
||||
public System.Windows.Forms.Button btnCancel;
|
||||
public System.Windows.Forms.Button btnOk;
|
||||
public System.Windows.Forms.Label lblNew;
|
||||
public System.Windows.Forms.TextBox txtNew;
|
||||
public System.Windows.Forms.ColumnHeader colMapName;
|
||||
public System.Windows.Forms.ImageList MapIconsList;
|
||||
public System.Windows.Forms.PictureBox pbMinimap;
|
||||
public System.Windows.Forms.Panel pnlBottom;
|
||||
public System.Windows.Forms.SplitContainer splitContainer1;
|
||||
public System.Windows.Forms.Label lblMinimap;
|
||||
public System.Windows.Forms.TextBox txtTheater;
|
||||
public System.Windows.Forms.Label lblTheater;
|
||||
public System.Windows.Forms.TextBox txtAuthor;
|
||||
public System.Windows.Forms.Label lblAuthor;
|
||||
public System.Windows.Forms.TextBox txtTitle;
|
||||
public System.Windows.Forms.Label lblMapName;
|
||||
public System.Windows.Forms.TextBox txtDesc;
|
||||
public System.Windows.Forms.Label lblDesc;
|
||||
public System.Windows.Forms.Label lblMapList;
|
||||
public System.Windows.Forms.Label lblPathOut;
|
||||
public System.Windows.Forms.Label lblPath;
|
||||
public System.Windows.Forms.TextBox txtPathOut;
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
}
|
||||
}
|
||||
66
OpenRA.Editor/MapSelect.cs
Normal file
66
OpenRA.Editor/MapSelect.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
public partial class MapSelect : Form
|
||||
{
|
||||
public string MapFolderPath;
|
||||
|
||||
public MapSelect()
|
||||
{
|
||||
InitializeComponent();
|
||||
MapIconsList.Images.Add(pictureBox1.Image);
|
||||
}
|
||||
|
||||
void MapSelect_Load(object sender, EventArgs e)
|
||||
{
|
||||
DirectoryInfo directory = new DirectoryInfo(MapFolderPath);
|
||||
DirectoryInfo[] directories = directory.GetDirectories();
|
||||
MapList.Items.Clear();
|
||||
txtPathOut.Text = MapFolderPath;
|
||||
foreach (DirectoryInfo subDirectory in directories)
|
||||
{
|
||||
ListViewItem map1 = new ListViewItem(subDirectory.Name);
|
||||
map1.ImageIndex = 0;
|
||||
MapList.Items.Add(map1);
|
||||
}
|
||||
|
||||
// hack
|
||||
if (txtNew.Text != "unnamed")
|
||||
MapList.Items[0].Selected = true;
|
||||
}
|
||||
|
||||
void MapList_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (MapList.SelectedItems.Count == 1)
|
||||
{
|
||||
txtNew.Text = MapList.SelectedItems[0].Text;
|
||||
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text)));
|
||||
txtTitle.Text = map.Title;
|
||||
txtAuthor.Text = map.Author;
|
||||
txtTheater.Text = map.Theater;
|
||||
txtDesc.Text = map.Description;
|
||||
pbMinimap.Image = null;
|
||||
try
|
||||
{
|
||||
pbMinimap.Image = Minimap.AddStaticResources(map, Minimap.TerrainBitmap(map, true));
|
||||
}
|
||||
catch (Exception ed)
|
||||
{
|
||||
Console.WriteLine("No map preview image found: {0}", ed.ToString());
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
}
|
||||
|
||||
void txtPathOut_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
MapFolderPath = txtPathOut.Text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
177
OpenRA.Editor/MapSelect.resx
Normal file
177
OpenRA.Editor/MapSelect.resx
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="MapIconsList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAArjSURBVFhHrVcJUFRXFmVpkE0Wg0ZEMoIBl8RodGSMmVES
|
||||
R0NiChVxCyIIAmFfhe6maeh9AZodZHFpUFQWcQmKisiuLKLEKFFEcIuljtZMYmI5Uc/c14EZYyapmpq8
|
||||
qlP/9/+/373v3HPu+19P7/cf+jSlEWHCOEuzZfNn2Yvo3Pj3D/PTjCwYAwtgyeFwFk163Tos2tvtWJZw
|
||||
zeUjmYFP6vL9fhw31vRPI8/9LnmMrtCWZhtPcJ7hbC/W8DwfnS0LR0t5NKoFazHcqsaprE3YGbMQLrYW
|
||||
W/7fBAxogjGEd5wcXuPK4jxa60qD75VrfIbKMrYMD7VlPX/Ul49rp8RoyPbFIaEnhpuU6NRGoVa2HKuX
|
||||
zEj/X8vAVmlIsDY2Nna2sjBd+ee5b7Yq4tfgfm8a7pxNw60OFa6e4uFmhxr/uFSIexfz0VsZh7PaIJzb
|
||||
F42u8hAcV2/ANz3KF8Hub52kucb+Fv+jAccbm5quWOfxYX5y6Mcnq/IDh1oreX/vOcx9drdbjTudUgye
|
||||
Tsb1piT0H4/DACUw0JiEh33ZePhlFi7UxOCLtI1o2x6IW2cUqM/egLtdediV9MnjSTYm60bE+Ys8rMzN
|
||||
zd1c3/vLgVRV3lN1XjkqyzNoNaEUjIvrLXwMtQsw1JqEy/UxuHg0DJcp+KXj8bh0IobOucSGDA8vpqE6
|
||||
+VNINixBU0kQbp5JJ8jxDSXdeyAE5arlAxTZ/BfRra2tS8Tqwh9L9tQhq6gSabm7odLkoP8oF90V/rjR
|
||||
LsRgExc32oS40ZFCiQgw2Mgj+gW42pBI4OPSsUh6Jgn1mX4ojXJH865IXDzCx50uDe6fV+P8oQQ4Tx6r
|
||||
pOATmVteKgdjXu/Mhk1h328rO4TMwn3gp2YhmquEX7gAfYfjcb4qGH0HQ3D5WAiunU7ApfpofH0ymhIS
|
||||
UwkSqQRb6VoYvm6IZvXG7W4VBVbjwQU1/tanIQZkGDqtwOmSjzHXxXaLsZnZpy85QpdAnfunax/mllRD
|
||||
ma2FQJyHxORMJAqzwBVpUJgtRLF8E7bxlqKjzA991QEYaIijgFwMt6VggJK60hCFr46F4sqprbjbLaf6
|
||||
S0icIh1rwy1i3OvNQff+GEgj3r87/c1JLIGfjX1LP/F6KJDlIy1vN4SyQohVRdAU7IVIXQxuSiZ8/OOw
|
||||
JYyP8EiqfV04Lh2JoHIwMSbiwoFgtO1ah97aTSTMKGIjDl/WhONWl5jKlYrbZ9OJGRWVIg/+axf8SK5a
|
||||
8WoC5fPm//l2qqIIOaVVECm3QZG5C7L0HZCklYJLTCQKNUiWFYAnykJYRDRaywNxrTGRyhKNKyciiIEY
|
||||
dFd743z1ZioT6eJkHK41kXDbRFSKbHzTpcJwsxoHc71fTLGzyBix+L/zUFlaWX+VTcFZ4NzSamQXV1Lw
|
||||
EggkeeBRAsnSfKgyy6DKKcNnxEahIgRfHg5B/7EoDDYn4ma7FD0VAThfG4Cemi3EDI90IKWVq3GbHHKz
|
||||
nUpCbrh6QokEr5mPTEw4773MQij9aPZY5fNYrC6hEhRAnrkTjJEkcS5ieWokS/IhUZdCrtlJbGQiIjQQ
|
||||
/YeD0VMVhoTVbmgs8iVBctG11xtdlUHkDGpQpIN7velUAhmG2+W43spclI6K9JWY6TyxlGKOGxWjG53s
|
||||
5HBMBpZ7+iI6UY44vhoiVTH4ohxCLoTyArqu1OlBll6CZHE20mI9EOjuis3L5uFCbTh6D4Wgu8offYeC
|
||||
qSRccgcPD/qyMEiBb55VYahFgSuNckhjlr2YaGMqH2ntOiKmEAQGBgbnNviGPg2LFSM4UoiAUD78ghLo
|
||||
yEVojBhRiQqEx0nAI5sKiBH/z+OgVfuic7c/Lh+NwZndfughDfQdCtL1hKFmEW51ymn1EjpSAh1ytFCL
|
||||
Pl+nhKebY8XLTYn16DWEgzY2ttdzyI6yjB06+uP4acRANokvhzRRjBR5oe4aN4WupeYgNCIWZ2vj0b17
|
||||
I/UKf3Tt34jOis9otTyyILmkORUDTRKyqxj9DSI07Y0k26Yhes38Roo3YVQH7OVhGiGR0K7O0epEqCRB
|
||||
shKwRIQkQrZqMelAIM6ncihII9uQSCXZEi2HSMjDXvVqXKSGdTLbg6z6OVkwGcfLQvHB4jkYbJMS/UL0
|
||||
1aeSM6So1Hg/oljTR93AupEVYSXhGE+soZa8X+cIlgALzFhg5/HJ6YhIzACXVs9EKiHRMmckSfMQGx0G
|
||||
rXIldU4/dJSvJx3EoSDZC7OszHByTxTOfZGEq00y9B3lo70iElamhp4Ujy1eN8wIrEOd0BRW6DpiWEwq
|
||||
giKSdYiIl5IOUskRKh39AmKECZNP7Mg0O6Ci59Pzd4O/NQK7FBvQULyGOmMUpBsX4KqjGTL5qzHQIqJy
|
||||
iNG6Px5dtYlY7jqhmeKxvUE32C7FGKiP58uf5W6v0ekgPkmNrYIMor4YqcoinQBFdGQrl2ZsB4/cwBJR
|
||||
Zml/+k0sxcQnQZzgDWHIIni9NQHSHU5IS15EPSEN11ok6G9UQs1dh/lvv/GdkZHR3NEETOhkIUE7zvb1
|
||||
wRRFwYv0vD3UBTORJCEdSHMhydgFCXVHVnuWEGvZrDewjqmzKbHDNjHmFl5KBlasWokiFwtop5nhyL6p
|
||||
2JO/CN2HBdSgMpHJ88GH82c8s7b4T1vmUPA3CFxCp19QzBPdtpxdRqon2kkDKRSYXeOJcyBUFMI7IJ70
|
||||
kYsEgRLTXGbgrzNnwmWqC2Y4OsLZZjx43El4ggXI1zohy24MAFd4u9tj8YLpmD71DTiMtwGHY1A7ygB7
|
||||
52N29CLULV7qeT+HnFCoPairu87/RC9rTjE8JYJoY/p4lR8lVQAp7Rc+/pHY7OKE61NN8a21MbQpfwC+
|
||||
m4fbQ7MQNdcCfWMMsTPWDi2yyRgyNkDhOGPYGhpeo97jP5oAcwJjYQ4hk3DOyzvwn9v3HtUJjHXAzSFc
|
||||
RHHlCAznIyAsCZa2k56u3xT2gtHPmGHCdXtnHh47mKBqjS1K5Q7ITrCjlf8RqXPM0bDUCr3bp2C9nj70
|
||||
DDinKMYSwmujCbAjY4G9ZrN3tyMLP/D4IT1vP/J21CBeoKaa55MTUhAeK8J7i91v0DMdxqZmgw7Oc74N
|
||||
iFQ8T5YX6ZzisWI9Uiebo8rKCOcsjLAv1Z72BydUxE5ElcTuKf2P9RunEeGzmD8bTIzsI0I7wc7xdgyf
|
||||
NiayWVoueZ1qz7zPT8l5McnBqZieYZsYO/a4zF7yaKWP4HlASMKLj9xX4WrXWzhdMxUFlkaI1tPDAZE9
|
||||
Htc4wWuhOas5Y/oXgUezYDdZdmK2N6zzCfuB1V1GFkulNswT5cFllms73f+QMIWwjCDjGJnUW1rbfu2z
|
||||
wvXJk85pUH5gieNJdugvd8QV7RSc0TjgiMwevkvH3np1xa/+ZplZE9jecNh14UcPmO8VmnLyfzGr/feU
|
||||
mB/dY7VjybItdSZhrb6+fvEYY6PuMWOMn7ZbGeILfQNYmnN+mO1o/OBdCw74HAMsMjR8NjL/r+Yx+p3H
|
||||
XhjKZs93uxMZr4Z/uOb54qWf3bGf4pw3EpC1UPYsS3g0EU9K4uBsI86zYHPOY3MOp4zuRRLyDfT1O941
|
||||
Mrzvb86Bob4h+0r6zcEmdiFICA2vvT55kLFBYOJhnYt9or06TOmCJ7HTbGxgADpndmaJMU29QxAQKvTo
|
||||
vhnHkN1nX12/OlgCNoT3CZsIvgRWc9ao2IT/bTD3+BID7N1/zisBWCKOBB/CagKf8PboJP8CoUmu3yhA
|
||||
ga8AAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
OpenRA.Editor/OpenRA.Editor.Icon.ico
Normal file
BIN
OpenRA.Editor/OpenRA.Editor.Icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -12,6 +12,9 @@
|
||||
<AssemblyName>OpenRA.Editor</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ApplicationIcon>OpenRA.Editor.Icon.ico</ApplicationIcon>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -33,6 +36,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -59,12 +63,24 @@
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LegacyMapImporter.cs" />
|
||||
<Compile Include="MapSelect.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MapSelect.Designer.cs">
|
||||
<DependentUpon>MapSelect.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="NewMapDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="NewMapDialog.Designer.cs">
|
||||
<DependentUpon>NewMapDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="PaletteBox.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="PaletteBox.Designer.cs">
|
||||
<DependentUpon>PaletteBox.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="PropertiesDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -76,9 +92,15 @@
|
||||
<EmbeddedResource Include="Form1.resx">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="MapSelect.resx">
|
||||
<DependentUpon>MapSelect.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="NewMapDialog.resx">
|
||||
<DependentUpon>NewMapDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="PaletteBox.resx">
|
||||
<DependentUpon>PaletteBox.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="PropertiesDialog.resx">
|
||||
<DependentUpon>PropertiesDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -103,6 +125,7 @@
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="RenderUtils.cs" />
|
||||
<Compile Include="ResizeDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -123,6 +146,9 @@
|
||||
<Name>OpenRA.Game</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="OpenRA.Editor.Icon.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
165
OpenRA.Editor/PaletteBox.Designer.cs
generated
Normal file
165
OpenRA.Editor/PaletteBox.Designer.cs
generated
Normal file
@@ -0,0 +1,165 @@
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
partial class PaletteBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Требуется переменная конструктора.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Освободить все используемые ресурсы.
|
||||
/// </summary>
|
||||
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Код, автоматически созданный конструктором форм Windows
|
||||
|
||||
/// <summary>
|
||||
/// Обязательный метод для поддержки конструктора - не изменяйте
|
||||
/// содержимое данного метода при помощи редактора кода.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.LayerBox = new System.Windows.Forms.ComboBox();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.pbtilePalette = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.pbactorPalette = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.tabPage3 = new System.Windows.Forms.TabPage();
|
||||
this.pbresourcePalette = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.tabPage2.SuspendLayout();
|
||||
this.tabPage3.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// LayerBox
|
||||
//
|
||||
this.LayerBox.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.LayerBox.FormattingEnabled = true;
|
||||
this.LayerBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.LayerBox.Name = "LayerBox";
|
||||
this.LayerBox.Size = new System.Drawing.Size(194, 21);
|
||||
this.LayerBox.TabIndex = 0;
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
this.tabControl1.Controls.Add(this.tabPage2);
|
||||
this.tabControl1.Controls.Add(this.tabPage3);
|
||||
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl1.Location = new System.Drawing.Point(0, 21);
|
||||
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
|
||||
this.tabControl1.Multiline = true;
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(194, 357);
|
||||
this.tabControl1.TabIndex = 1;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.pbtilePalette);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(186, 331);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Templates";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pbtilePalette
|
||||
//
|
||||
this.pbtilePalette.AutoScroll = true;
|
||||
this.pbtilePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.pbtilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pbtilePalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.pbtilePalette.Name = "pbtilePalette";
|
||||
this.pbtilePalette.Size = new System.Drawing.Size(180, 325);
|
||||
this.pbtilePalette.TabIndex = 1;
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Controls.Add(this.pbactorPalette);
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(186, 331);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Actors";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pbactorPalette
|
||||
//
|
||||
this.pbactorPalette.AutoScroll = true;
|
||||
this.pbactorPalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.pbactorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pbactorPalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.pbactorPalette.Name = "pbactorPalette";
|
||||
this.pbactorPalette.Size = new System.Drawing.Size(180, 325);
|
||||
this.pbactorPalette.TabIndex = 2;
|
||||
//
|
||||
// tabPage3
|
||||
//
|
||||
this.tabPage3.Controls.Add(this.pbresourcePalette);
|
||||
this.tabPage3.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage3.Name = "tabPage3";
|
||||
this.tabPage3.Size = new System.Drawing.Size(186, 331);
|
||||
this.tabPage3.TabIndex = 2;
|
||||
this.tabPage3.Text = "Resources";
|
||||
this.tabPage3.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pbresourcePalette
|
||||
//
|
||||
this.pbresourcePalette.AutoScroll = true;
|
||||
this.pbresourcePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.pbresourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pbresourcePalette.Location = new System.Drawing.Point(0, 0);
|
||||
this.pbresourcePalette.Name = "pbresourcePalette";
|
||||
this.pbresourcePalette.Size = new System.Drawing.Size(186, 331);
|
||||
this.pbresourcePalette.TabIndex = 3;
|
||||
//
|
||||
// PaletteBox
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(194, 378);
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Controls.Add(this.LayerBox);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "PaletteBox";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Palette Box";
|
||||
this.TopMost = true;
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage2.ResumeLayout(false);
|
||||
this.tabPage3.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public System.Windows.Forms.ComboBox LayerBox;
|
||||
public System.Windows.Forms.TabControl tabControl1;
|
||||
public System.Windows.Forms.TabPage tabPage1;
|
||||
public System.Windows.Forms.FlowLayoutPanel pbtilePalette;
|
||||
public System.Windows.Forms.TabPage tabPage2;
|
||||
public System.Windows.Forms.FlowLayoutPanel pbactorPalette;
|
||||
public System.Windows.Forms.TabPage tabPage3;
|
||||
public System.Windows.Forms.FlowLayoutPanel pbresourcePalette;
|
||||
|
||||
}
|
||||
}
|
||||
19
OpenRA.Editor/PaletteBox.cs
Normal file
19
OpenRA.Editor/PaletteBox.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
public partial class PaletteBox : Form
|
||||
{
|
||||
public PaletteBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
OpenRA.Editor/PaletteBox.resx
Normal file
120
OpenRA.Editor/PaletteBox.resx
Normal 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>
|
||||
136
OpenRA.Editor/RenderUtils.cs
Normal file
136
OpenRA.Editor/RenderUtils.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
static class RenderUtils
|
||||
{
|
||||
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
|
||||
{
|
||||
var template = ts.Templates[n];
|
||||
var tile = ts.Tiles[n];
|
||||
|
||||
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
|
||||
{
|
||||
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
|
||||
for (var i = 0; i < ts.TileSize; i++)
|
||||
for (var j = 0; j < ts.TileSize; j++)
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = p.GetColor(rawImage[i + ts.TileSize * j]).ToArgb();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < ts.TileSize; i++)
|
||||
for (var j = 0; j < ts.TileSize; j++)
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = Color.Transparent.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static Bitmap RenderShp(ShpReader shp, Palette p)
|
||||
{
|
||||
var frame = shp[0];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride2 = data.Stride >> 2;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride2 + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
|
||||
{
|
||||
var ri = info.Traits.Get<RenderSimpleInfo>();
|
||||
string image = null;
|
||||
if (ri.OverrideTheater != null)
|
||||
for (int i = 0; i < ri.OverrideTheater.Length; i++)
|
||||
if (ri.OverrideTheater[i] == tileset.Id)
|
||||
image = ri.OverrideImage[i];
|
||||
|
||||
image = image ?? ri.Image ?? info.Name;
|
||||
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
|
||||
{
|
||||
var shp = new ShpReader(s);
|
||||
var bitmap = RenderShp(shp, p);
|
||||
|
||||
try
|
||||
{
|
||||
using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions))
|
||||
{
|
||||
var shp2 = new ShpReader(s2);
|
||||
var roofBitmap = RenderShp(shp2, p);
|
||||
|
||||
using (var g = System.Drawing.Graphics.FromImage(bitmap))
|
||||
g.DrawImage(roofBitmap, 0, 0);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
|
||||
}
|
||||
}
|
||||
|
||||
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
|
||||
{
|
||||
var image = info.SpriteNames[0];
|
||||
using (var s = FileSystem.OpenWithExts(image, exts))
|
||||
{
|
||||
var shp = new ShpReader(s);
|
||||
var frame = shp[shp.ImageCount - 1];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,8 @@ namespace OpenRA.Editor
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (Map == null) return;
|
||||
|
||||
Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
|
||||
|
||||
Invalidate();
|
||||
@@ -114,6 +116,8 @@ namespace OpenRA.Editor
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (Map == null) return;
|
||||
|
||||
var oldMousePos = MousePos;
|
||||
MousePos = new int2(e.Location);
|
||||
|
||||
@@ -332,6 +336,8 @@ namespace OpenRA.Editor
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
if (Map == null) return;
|
||||
|
||||
if (!IsPanning)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right) Erase();
|
||||
@@ -346,7 +352,7 @@ namespace OpenRA.Editor
|
||||
Bitmap RenderChunk(int u, int v)
|
||||
{
|
||||
|
||||
var bitmap = new Bitmap(ChunkSize * 24, ChunkSize * 24);
|
||||
var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
|
||||
bitmap.SetPixel(0, 0, Color.Green);
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
@@ -364,9 +370,9 @@ namespace OpenRA.Editor
|
||||
var tile = TileSet.Tiles[tr.type];
|
||||
var index = (tr.image < tile.TileBitmapBytes.Count) ? tr.image : (byte)0;
|
||||
var rawImage = tile.TileBitmapBytes[index];
|
||||
for (var x = 0; x < 24; x++)
|
||||
for (var y = 0; y < 24; y++)
|
||||
p[(j * 24 + y) * stride + i * 24 + x] = Palette.GetColor(rawImage[x + 24 * y]).ToArgb();
|
||||
for (var x = 0; x < TileSet.TileSize; x++)
|
||||
for (var y = 0; y < TileSet.TileSize; y++)
|
||||
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb();
|
||||
|
||||
if (Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type != 0)
|
||||
{
|
||||
@@ -377,12 +383,12 @@ namespace OpenRA.Editor
|
||||
int* q = (int*)srcdata.Scan0.ToPointer();
|
||||
var srcstride = srcdata.Stride >> 2;
|
||||
|
||||
for (var x = 0; x < 24; x++)
|
||||
for (var y = 0; y < 24; y++)
|
||||
for (var x = 0; x < TileSet.TileSize; x++)
|
||||
for (var y = 0; y < TileSet.TileSize; y++)
|
||||
{
|
||||
var c = q[y * srcstride + x];
|
||||
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
|
||||
p[(j * 24 + y) * stride + i * 24 + x] = c;
|
||||
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c;
|
||||
}
|
||||
|
||||
resourceImage.UnlockBits(srcdata);
|
||||
@@ -398,16 +404,16 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
|
||||
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
|
||||
return new int2(vX / 24, vY / 24);
|
||||
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
|
||||
}
|
||||
|
||||
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t)
|
||||
{
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - 12 : 0;
|
||||
float DrawX = 24 * p.X * Zoom + Offset.X - OffsetX;
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize/2 : 0;
|
||||
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
|
||||
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - 12 : 0;
|
||||
float DrawY = 24 * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize/2 : 0;
|
||||
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
float width = t.Bitmap.Width * Zoom;
|
||||
float height = t.Bitmap.Height * Zoom;
|
||||
@@ -418,11 +424,11 @@ namespace OpenRA.Editor
|
||||
|
||||
void DrawImage(System.Drawing.Graphics g, Bitmap bmp, int2 location)
|
||||
{
|
||||
float OffsetX = bmp.Width / 2 - 12;
|
||||
float DrawX = 24 * location.X * Zoom + Offset.X - OffsetX;
|
||||
float OffsetX = bmp.Width / 2 - TileSet.TileSize / 2;
|
||||
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
|
||||
|
||||
float OffsetY = bmp.Height / 2 - 12;
|
||||
float DrawY = 24 * location.Y * Zoom + Offset.Y - OffsetY;
|
||||
float OffsetY = bmp.Height / 2 - TileSet.TileSize / 2;
|
||||
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
float width = bmp.Width * Zoom;
|
||||
float height = bmp.Height * Zoom;
|
||||
@@ -433,16 +439,12 @@ namespace OpenRA.Editor
|
||||
|
||||
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
|
||||
{
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - 12 : 0;
|
||||
float DrawX = 24 * p.X * Zoom + Offset.X - OffsetX;
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
|
||||
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - 12 : 0;
|
||||
float DrawY = 24 * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
float width = t.Bitmap.Width * Zoom;
|
||||
float height = t.Bitmap.Height * Zoom;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
|
||||
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
|
||||
g.DrawRectangle(CordonPen,
|
||||
DrawX, DrawY,
|
||||
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
|
||||
@@ -461,32 +463,32 @@ namespace OpenRA.Editor
|
||||
|
||||
Bitmap bmp = Chunks[x];
|
||||
|
||||
float DrawX = 24.0f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
float DrawY = 24.0f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
|
||||
float DrawX = TileSet.TileSize* 1f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
float DrawY = TileSet.TileSize * 1f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
|
||||
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
|
||||
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(CordonPen,
|
||||
Map.XOffset * 24 * Zoom + Offset.X,
|
||||
Map.YOffset * 24 * Zoom + Offset.Y,
|
||||
Map.Width * 24 * Zoom,
|
||||
Map.Height * 24 * Zoom);
|
||||
Map.XOffset * TileSet.TileSize * Zoom + Offset.X,
|
||||
Map.YOffset * TileSet.TileSize * Zoom + Offset.Y,
|
||||
Map.Width * TileSet.TileSize * Zoom,
|
||||
Map.Height * TileSet.TileSize * Zoom);
|
||||
|
||||
foreach (var ar in Map.Actors)
|
||||
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type]);
|
||||
|
||||
foreach (var wp in Map.Waypoints)
|
||||
e.Graphics.DrawRectangle(Pens.LimeGreen,
|
||||
24 * wp.Value.X * Zoom + Offset.X + 4,
|
||||
24 * wp.Value.Y * Zoom + Offset.Y + 4,
|
||||
16 * Zoom, 16 * Zoom);
|
||||
TileSet.TileSize * wp.Value.X * Zoom + Offset.X + 4,
|
||||
TileSet.TileSize * wp.Value.Y * Zoom + Offset.Y + 4,
|
||||
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
|
||||
|
||||
if (Brush != null)
|
||||
e.Graphics.DrawImage(Brush.Bitmap,
|
||||
24 * GetBrushLocation().X * Zoom + Offset.X,
|
||||
24 * GetBrushLocation().Y * Zoom + Offset.Y,
|
||||
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X,
|
||||
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y,
|
||||
Brush.Bitmap.Width * Zoom,
|
||||
Brush.Bitmap.Height * Zoom);
|
||||
|
||||
@@ -498,9 +500,9 @@ namespace OpenRA.Editor
|
||||
|
||||
if (Waypoint != null)
|
||||
e.Graphics.DrawRectangle(Pens.LimeGreen,
|
||||
24 * GetBrushLocation().X * Zoom + Offset.X + 4,
|
||||
24 * GetBrushLocation().Y * Zoom + Offset.Y + 4,
|
||||
16 * Zoom, 16 * Zoom);
|
||||
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X + 4,
|
||||
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y + 4,
|
||||
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
|
||||
|
||||
if (Brush == null && Actor == null && Resource == null)
|
||||
{
|
||||
|
||||
22
OpenRA.FileFormats/Exts.cs
Normal file → Executable file
22
OpenRA.FileFormats/Exts.cs
Normal file → Executable file
@@ -73,5 +73,27 @@ namespace OpenRA
|
||||
{
|
||||
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
|
||||
}
|
||||
|
||||
public static T[] GetCustomAttributes<T>( this MemberInfo mi, bool inherit )
|
||||
where T : class
|
||||
{
|
||||
return (T[])mi.GetCustomAttributes( typeof( T ), inherit );
|
||||
}
|
||||
|
||||
public static T[] GetCustomAttributes<T>( this ParameterInfo mi )
|
||||
where T : class
|
||||
{
|
||||
return (T[])mi.GetCustomAttributes( typeof( T ), true );
|
||||
}
|
||||
|
||||
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
if (val.CompareTo(min) < 0)
|
||||
return min;
|
||||
else if (val.CompareTo(max) > 0)
|
||||
return max;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
OpenRA.FileFormats/FieldLoader.cs
Normal file → Executable file
21
OpenRA.FileFormats/FieldLoader.cs
Normal file → Executable file
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
@@ -99,7 +100,7 @@ namespace OpenRA.FileFormats
|
||||
else if (fieldType == typeof(float))
|
||||
{
|
||||
float res;
|
||||
if (float.TryParse(x.Replace("%",""), out res))
|
||||
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
|
||||
return res * (x.Contains( '%' ) ? 0.01f : 1f);
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
@@ -111,9 +112,9 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
var parts = x.Split(',');
|
||||
if (parts.Length == 3)
|
||||
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
|
||||
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
|
||||
if (parts.Length == 4)
|
||||
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
|
||||
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
|
||||
@@ -177,11 +178,12 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
var ret = new Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>();
|
||||
|
||||
foreach( var field in type.GetFields() )
|
||||
foreach( var ff in type.GetFields() )
|
||||
{
|
||||
var load = (LoadAttribute[])field.GetCustomAttributes( typeof( LoadAttribute ), false );
|
||||
var loadUsing = (LoadUsingAttribute[])field.GetCustomAttributes( typeof( LoadUsingAttribute ), false );
|
||||
var fromYamlKey = (FieldFromYamlKeyAttribute[])field.GetCustomAttributes( typeof( FieldFromYamlKeyAttribute ), false );
|
||||
var field = ff;
|
||||
var load = field.GetCustomAttributes<LoadAttribute>( false );
|
||||
var loadUsing = field.GetCustomAttributes<LoadUsingAttribute>( false );
|
||||
var fromYamlKey = field.GetCustomAttributes<FieldFromYamlKeyAttribute>( false );
|
||||
if( loadUsing.Length != 0 )
|
||||
ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml );
|
||||
else if( fromYamlKey.Length != 0 )
|
||||
@@ -262,7 +264,10 @@ namespace OpenRA.FileFormats
|
||||
if (f.FieldType == typeof(Color))
|
||||
{
|
||||
var c = (Color)v;
|
||||
return "{0},{1},{2},{3}".F(c.A,c.R,c.G,c.B);
|
||||
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
|
||||
((int)c.R).Clamp(0, 255),
|
||||
((int)c.G).Clamp(0, 255),
|
||||
((int)c.B).Clamp(0, 255));
|
||||
}
|
||||
|
||||
return f.FieldType.IsArray
|
||||
|
||||
@@ -52,13 +52,13 @@ namespace OpenRA.FileFormats.Graphics
|
||||
public interface IVertexBuffer<T>
|
||||
{
|
||||
void Bind();
|
||||
void SetData( T[] vertices );
|
||||
void SetData( T[] vertices, int length );
|
||||
}
|
||||
|
||||
public interface IIndexBuffer
|
||||
{
|
||||
void Bind();
|
||||
void SetData( ushort[] indices );
|
||||
void SetData( ushort[] indices, int length );
|
||||
}
|
||||
|
||||
public interface IShader
|
||||
|
||||
@@ -18,18 +18,21 @@ namespace OpenRA.FileFormats
|
||||
public class Manifest
|
||||
{
|
||||
public readonly string[]
|
||||
Folders, Packages, Rules,
|
||||
Mods, Folders, Packages, Rules,
|
||||
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Weapons, Voices, Music, Movies, TileSets;
|
||||
|
||||
public readonly string ShellmapUid, LoadScreen;
|
||||
public readonly int TileSize = 24;
|
||||
|
||||
public Manifest(string[] mods)
|
||||
{
|
||||
Mods = mods;
|
||||
var yaml = mods
|
||||
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
|
||||
.Aggregate(MiniYaml.Merge);
|
||||
|
||||
|
||||
// Todo: Use fieldloader
|
||||
Folders = YamlList(yaml, "Folders");
|
||||
Packages = YamlList(yaml, "Packages");
|
||||
Rules = YamlList(yaml, "Rules");
|
||||
@@ -46,6 +49,9 @@ namespace OpenRA.FileFormats
|
||||
|
||||
ShellmapUid = yaml.First( x => x.Key == "ShellmapUid" ).Value.Value;
|
||||
LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value;
|
||||
|
||||
if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null)
|
||||
TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value);
|
||||
}
|
||||
|
||||
static string[] YamlList(List<MiniYamlNode> ys, string key)
|
||||
|
||||
@@ -17,15 +17,15 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
|
||||
|
||||
public Terrain( Stream stream )
|
||||
public Terrain( Stream stream, int size )
|
||||
{
|
||||
// Try loading as a cnc .tem
|
||||
BinaryReader reader = new BinaryReader( stream );
|
||||
int Width = reader.ReadUInt16();
|
||||
int Height = reader.ReadUInt16();
|
||||
|
||||
if( Width != 24 || Height != 24 )
|
||||
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
|
||||
|
||||
if( Width != size || Height != size )
|
||||
throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) );
|
||||
|
||||
/*NumTiles = */reader.ReadUInt16();
|
||||
/*Zero1 = */reader.ReadUInt16();
|
||||
@@ -46,9 +46,7 @@ namespace OpenRA.FileFormats
|
||||
reader = new BinaryReader( stream );
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
if( Width != 24 || Height != 24 )
|
||||
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
|
||||
|
||||
|
||||
/*NumTiles = */reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
/*XDim = */reader.ReadUInt16();
|
||||
@@ -67,8 +65,8 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
if (b != 255)
|
||||
{
|
||||
stream.Position = ImgStart + b * 24 * 24;
|
||||
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(24 * 24));
|
||||
stream.Position = ImgStart + b * size * size;
|
||||
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size));
|
||||
}
|
||||
else
|
||||
TileBitmapBytes.Add(null);
|
||||
|
||||
@@ -74,11 +74,12 @@ namespace OpenRA.FileFormats
|
||||
public string Name;
|
||||
public string Id;
|
||||
public string Palette;
|
||||
public int TileSize = 24;
|
||||
public string[] Extensions;
|
||||
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
|
||||
public Dictionary<ushort, Terrain> Tiles = new Dictionary<ushort, Terrain>();
|
||||
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
|
||||
static List<string> fields = new List<string>() {"Name", "Id", "Palette", "Extensions"};
|
||||
static List<string> fields = new List<string>() {"Name", "TileSize", "Id", "Palette", "Extensions"};
|
||||
|
||||
public TileSet() {}
|
||||
public TileSet( string filepath )
|
||||
@@ -103,20 +104,13 @@ namespace OpenRA.FileFormats
|
||||
using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
|
||||
{
|
||||
if( !Tiles.ContainsKey( t.Key ) )
|
||||
Tiles.Add( t.Key, new Terrain( s ) );
|
||||
Tiles.Add( t.Key, new Terrain( s, TileSize ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string filepath)
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
foreach (var field in fields)
|
||||
{
|
||||
FieldInfo f = this.GetType().GetField(field);
|
||||
if (f.GetValue(this) == null) continue;
|
||||
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
|
||||
}
|
||||
|
||||
var gen = new List<MiniYamlNode>();
|
||||
foreach (var field in fields)
|
||||
{
|
||||
@@ -144,7 +138,7 @@ namespace OpenRA.FileFormats
|
||||
if( Tiles.TryGetValue( r.type, out tile ) )
|
||||
return tile.TileBitmapBytes[ r.image ];
|
||||
|
||||
byte[] missingTile = new byte[ 24 * 24 ];
|
||||
byte[] missingTile = new byte[ TileSize * TileSize ];
|
||||
for( int i = 0 ; i < missingTile.Length ; i++ )
|
||||
missingTile[ i ] = 0x36;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
@@ -8,11 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
@@ -57,6 +54,7 @@ namespace OpenRA.FileFormats
|
||||
colors[0] = 0;
|
||||
if (remapTransparent)
|
||||
{
|
||||
colors[1] = 178u << 24; // Hack for d2k; may have side effects
|
||||
colors[3] = 178u << 24;
|
||||
colors[4] = 140u << 24;
|
||||
}
|
||||
|
||||
@@ -15,15 +15,16 @@ using System.Linq;
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
// TODO: ship this out of here.
|
||||
public enum PaletteFormat { ra, cnc, d2k }
|
||||
|
||||
public class PlayerColorRemap : IPaletteRemap
|
||||
{
|
||||
Dictionary<int, Color> remapColors;
|
||||
|
||||
public PlayerColorRemap(Color c1, Color c2, bool useSplitRamp)
|
||||
public PlayerColorRemap(Color c1, Color c2, PaletteFormat fmt)
|
||||
{
|
||||
var baseIndex = useSplitRamp ? 0xb0 : 80;
|
||||
var ramp = useSplitRamp
|
||||
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
|
||||
var ramp = (fmt == PaletteFormat.cnc)
|
||||
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
|
||||
: new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
@@ -45,5 +46,34 @@ namespace OpenRA.FileFormats
|
||||
return remapColors.TryGetValue(index, out c)
|
||||
? c : original;
|
||||
}
|
||||
|
||||
// hk is hue in the range [0,1] instead of [0,360]
|
||||
public static Color ColorFromHSL(float hk, float s, float l)
|
||||
{
|
||||
// Convert from HSL to RGB
|
||||
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
|
||||
var p = 2 * l - q;
|
||||
|
||||
float[] trgb = { hk + 1 / 3.0f,
|
||||
hk,
|
||||
hk - 1/3.0f };
|
||||
float[] rgb = { 0, 0, 0 };
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
while (trgb[k] < 0) trgb[k] += 1.0f;
|
||||
while (trgb[k] > 1) trgb[k] -= 1.0f;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
|
||||
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
|
||||
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
|
||||
else { rgb[k] = p; }
|
||||
}
|
||||
|
||||
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace OpenRA
|
||||
public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); }
|
||||
public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); }
|
||||
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
|
||||
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
|
||||
|
||||
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
|
||||
@@ -59,5 +60,15 @@ namespace OpenRA
|
||||
{
|
||||
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
public static int Lerp( int a, int b, int mul, int div )
|
||||
{
|
||||
return a + ( b - a ) * mul / div;
|
||||
}
|
||||
|
||||
public static int2 Lerp( int2 a, int2 b, int mul, int div )
|
||||
{
|
||||
return a + ( b - a ) * mul / div;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
OpenRA.FileFormats/Thirdparty/Random.cs
vendored
5
OpenRA.FileFormats/Thirdparty/Random.cs
vendored
@@ -18,6 +18,8 @@ namespace OpenRA.Thirdparty
|
||||
{
|
||||
uint[] mt = new uint[624];
|
||||
int index = 0;
|
||||
|
||||
public int Last;
|
||||
|
||||
public Random() : this(Environment.TickCount) { }
|
||||
|
||||
@@ -39,7 +41,8 @@ namespace OpenRA.Thirdparty
|
||||
y ^= y >> 18;
|
||||
|
||||
index = (index + 1) % 624;
|
||||
return (int)(y % int.MaxValue);
|
||||
Last = (int)(y % int.MaxValue);
|
||||
return Last;
|
||||
}
|
||||
|
||||
public int Next(int low, int high) { return low + Next() % (high - low); }
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits;
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -26,7 +26,8 @@ namespace OpenRA
|
||||
public readonly World World;
|
||||
public readonly uint ActorID;
|
||||
|
||||
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
|
||||
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
|
||||
public float2 CenterLocation { get { return Trait<IHasLocation>().PxPosition; } }
|
||||
[Sync]
|
||||
public Player Owner;
|
||||
|
||||
@@ -52,9 +53,6 @@ namespace OpenRA
|
||||
AddTrait(trait.Create(init));
|
||||
}
|
||||
|
||||
if( CenterLocation == float2.Zero && HasTrait<IOccupySpace>() )
|
||||
CenterLocation = Traits.Util.CenterOfCell(Location);
|
||||
|
||||
Size = Lazy.New(() =>
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
@@ -74,8 +72,13 @@ namespace OpenRA
|
||||
while (currentActivity != null)
|
||||
{
|
||||
var a = currentActivity;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
currentActivity = a.Tick(this) ?? new Idle();
|
||||
|
||||
var dt = sw.ElapsedTime();
|
||||
if(dt > Game.Settings.Debug.LongTickThreshold)
|
||||
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", a, dt * 1000, Game.LocalTick);
|
||||
|
||||
if (a == currentActivity) break;
|
||||
|
||||
if (currentActivity is Idle)
|
||||
@@ -94,8 +97,6 @@ namespace OpenRA
|
||||
get { return currentActivity == null || currentActivity is Idle; }
|
||||
}
|
||||
|
||||
public float2 CenterLocation;
|
||||
|
||||
OpenRA.FileFormats.Lazy<float2> Size;
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
@@ -105,23 +106,6 @@ namespace OpenRA
|
||||
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
|
||||
}
|
||||
|
||||
public Order Order( int2 xy, MouseInput mi, Actor underCursor )
|
||||
{
|
||||
if (Owner != World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (Destroyed)
|
||||
return null;
|
||||
|
||||
return TraitsImplementing<IIssueOrder>()
|
||||
.OrderByDescending( x => x.OrderPriority( this, xy, mi, underCursor ) )
|
||||
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
|
||||
.FirstOrDefault( x => x != null );
|
||||
}
|
||||
|
||||
public RectangleF GetBounds(bool useAltitude)
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
@@ -146,16 +130,9 @@ namespace OpenRA
|
||||
public void QueueActivity( IActivity nextActivity )
|
||||
{
|
||||
if( currentActivity == null )
|
||||
{
|
||||
currentActivity = nextActivity;
|
||||
return;
|
||||
}
|
||||
var act = currentActivity;
|
||||
while( act.NextActivity != null )
|
||||
{
|
||||
act = act.NextActivity;
|
||||
}
|
||||
act.NextActivity = nextActivity;
|
||||
else
|
||||
currentActivity.Queue( nextActivity );
|
||||
}
|
||||
|
||||
public void CancelActivity()
|
||||
|
||||
@@ -20,9 +20,9 @@ namespace OpenRA
|
||||
sequence = CursorProvider.GetCursorSequence(cursor);
|
||||
}
|
||||
|
||||
public void Draw(int frame, float2 pos)
|
||||
public void Draw(WorldRenderer wr, int frame, float2 pos)
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sequence.GetSprite(frame), pos - sequence.Hotspot, sequence.Palette);
|
||||
sequence.GetSprite(frame).DrawAt(wr, pos - sequence.Hotspot, sequence.Palette);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Effects
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
{
|
||||
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow");
|
||||
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
OpenRA.Game/Exts.cs
Normal file → Executable file
22
OpenRA.Game/Exts.cs
Normal file → Executable file
@@ -34,17 +34,17 @@ namespace OpenRA
|
||||
return xs.Aggregate(1f, (a, x) => a * x);
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
|
||||
where V : new()
|
||||
{
|
||||
return d.GetOrAdd( k, _ => new V() );
|
||||
return d.GetOrAdd(k, _ => new V());
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k, Func<K, V> createFn )
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
|
||||
{
|
||||
V ret;
|
||||
if( !d.TryGetValue( k, out ret ) )
|
||||
d.Add( k, ret = createFn( k ) );
|
||||
if (!d.TryGetValue(k, out ret))
|
||||
d.Add(k, ret = createFn(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -54,18 +54,18 @@ namespace OpenRA
|
||||
return xs[r.Next(xs.Length)];
|
||||
}
|
||||
|
||||
public static void DoTimed<T>( this IEnumerable<T> e, Action<T> a, string text, double time )
|
||||
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
||||
e.Do( x =>
|
||||
e.Do(x =>
|
||||
{
|
||||
var t = sw.ElapsedTime();
|
||||
a( x );
|
||||
a(x);
|
||||
var dt = sw.ElapsedTime() - t;
|
||||
if( dt > time )
|
||||
Log.Write("perf", text, x, dt * 1000);
|
||||
} );
|
||||
if (dt > time)
|
||||
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Server;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
using Timer = OpenRA.Support.Timer;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Server;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
using XRandom = OpenRA.Thirdparty.Random;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public static class Game
|
||||
{
|
||||
public static readonly int CellSize = 24;
|
||||
public static int CellSize { get { return modData.Manifest.TileSize; } }
|
||||
|
||||
public static ModData modData;
|
||||
public static World world;
|
||||
private static WorldRenderer worldRenderer;
|
||||
|
||||
public static Viewport viewport;
|
||||
public static Settings Settings;
|
||||
|
||||
@@ -41,37 +41,25 @@ namespace OpenRA
|
||||
public static XRandom CosmeticRandom = new XRandom(); // not synced
|
||||
|
||||
public static Renderer Renderer;
|
||||
public static Session LobbyInfo = new Session();
|
||||
public static bool HasInputFocus = false;
|
||||
|
||||
static void LoadMap(string uid)
|
||||
{
|
||||
var map = modData.PrepareMap(uid);
|
||||
|
||||
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
|
||||
world = new World(modData.Manifest, map);
|
||||
}
|
||||
|
||||
public static void MoveViewport(int2 loc)
|
||||
{
|
||||
viewport.Center(loc);
|
||||
}
|
||||
|
||||
internal static string CurrentHost = "";
|
||||
internal static int CurrentPort = 0;
|
||||
|
||||
internal static void JoinServer(string host, int port)
|
||||
{
|
||||
if (orderManager != null) orderManager.Dispose();
|
||||
|
||||
CurrentHost = host;
|
||||
CurrentPort = port;
|
||||
var replayFilename = ChooseReplayFilename();
|
||||
string path = Path.Combine( Game.SupportDir, "Replays" );
|
||||
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
|
||||
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
|
||||
|
||||
orderManager = new OrderManager( host, port, new ReplayRecorderConnection( new NetworkConnection( host, port ), replayFile ) );
|
||||
lastConnectionState = ConnectionState.PreConnecting;
|
||||
ConnectionStateChanged();
|
||||
|
||||
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
|
||||
ConnectionStateChanged(orderManager);
|
||||
}
|
||||
|
||||
static string ChooseReplayFilename()
|
||||
@@ -81,71 +69,36 @@ namespace OpenRA
|
||||
|
||||
static void JoinLocal()
|
||||
{
|
||||
lastConnectionState = ConnectionState.PreConnecting;
|
||||
ConnectionStateChanged();
|
||||
|
||||
if (orderManager != null) orderManager.Dispose();
|
||||
orderManager = new OrderManager(new EchoConnection());
|
||||
}
|
||||
|
||||
static int lastTime = Environment.TickCount;
|
||||
|
||||
static void ResetTimer()
|
||||
{
|
||||
lastTime = Environment.TickCount;
|
||||
orderManager = new OrderManager("<no server>", -1, new EchoConnection());
|
||||
lastConnectionState = ConnectionState.PreConnecting;
|
||||
ConnectionStateChanged( orderManager );
|
||||
}
|
||||
|
||||
internal static int RenderFrame = 0;
|
||||
internal static int LocalTick = 0;
|
||||
internal static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
|
||||
|
||||
public static event Action ConnectionStateChanged = () => { };
|
||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||
|
||||
internal static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
|
||||
|
||||
static void Tick()
|
||||
static void Tick( OrderManager orderManager, Viewport viewPort )
|
||||
{
|
||||
if (orderManager.Connection.ConnectionState != lastConnectionState)
|
||||
{
|
||||
lastConnectionState = orderManager.Connection.ConnectionState;
|
||||
ConnectionStateChanged();
|
||||
}
|
||||
|
||||
int t = Environment.TickCount;
|
||||
int dt = t - lastTime;
|
||||
if (dt >= Settings.Game.Timestep)
|
||||
if (orderManager.Connection.ConnectionState != lastConnectionState)
|
||||
{
|
||||
using (new PerfSample("tick_time"))
|
||||
{
|
||||
lastTime += Settings.Game.Timestep;
|
||||
Widget.DoTick(world);
|
||||
Sound.Tick();
|
||||
orderManager.TickImmediate(world);
|
||||
|
||||
var isNetTick = LocalTick % NetTickScale == 0;
|
||||
|
||||
if (!isNetTick || orderManager.IsReadyForNextFrame)
|
||||
{
|
||||
++LocalTick;
|
||||
|
||||
if (isNetTick) orderManager.Tick(world);
|
||||
|
||||
world.OrderGenerator.Tick(world);
|
||||
world.Selection.Tick(world);
|
||||
world.Tick();
|
||||
|
||||
PerfHistory.Tick();
|
||||
}
|
||||
else
|
||||
if (orderManager.FrameNumber == 0)
|
||||
lastTime = Environment.TickCount;
|
||||
}
|
||||
lastConnectionState = orderManager.Connection.ConnectionState;
|
||||
ConnectionStateChanged( orderManager );
|
||||
}
|
||||
|
||||
Tick( orderManager );
|
||||
if( orderManager.world != worldRenderer.world )
|
||||
Tick( worldRenderer.world.orderManager );
|
||||
|
||||
using (new PerfSample("render"))
|
||||
{
|
||||
++RenderFrame;
|
||||
viewport.DrawRegions(world);
|
||||
viewport.DrawRegions(worldRenderer);
|
||||
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
|
||||
}
|
||||
|
||||
@@ -157,64 +110,85 @@ namespace OpenRA
|
||||
MasterServerQuery.Tick();
|
||||
}
|
||||
|
||||
private static void Tick( OrderManager orderManager )
|
||||
{
|
||||
int t = Environment.TickCount;
|
||||
int dt = t - orderManager.LastTickTime;
|
||||
if (dt >= Settings.Game.Timestep)
|
||||
using( new PerfSample( "tick_time" ) )
|
||||
{
|
||||
orderManager.LastTickTime += Settings.Game.Timestep;
|
||||
Widget.DoTick();
|
||||
var world = orderManager.world;
|
||||
if( orderManager.GameStarted && world.LocalPlayer != null )
|
||||
++Viewport.TicksSinceLastMove;
|
||||
Sound.Tick();
|
||||
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
|
||||
|
||||
var isNetTick = LocalTick % NetTickScale == 0;
|
||||
|
||||
if( !isNetTick || orderManager.IsReadyForNextFrame )
|
||||
{
|
||||
++orderManager.LocalFrameNumber;
|
||||
|
||||
Log.Write( "debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local" );
|
||||
|
||||
if( isNetTick ) orderManager.Tick();
|
||||
|
||||
world.OrderGenerator.Tick( world );
|
||||
world.Selection.Tick( world );
|
||||
world.Tick();
|
||||
worldRenderer.Tick();
|
||||
|
||||
PerfHistory.Tick();
|
||||
}
|
||||
else
|
||||
if( orderManager.NetFrameNumber == 0 )
|
||||
orderManager.LastTickTime = Environment.TickCount;
|
||||
}
|
||||
}
|
||||
|
||||
internal static event Action LobbyInfoChanged = () => { };
|
||||
|
||||
internal static void SyncLobbyInfo(string data)
|
||||
internal static void SyncLobbyInfo()
|
||||
{
|
||||
LobbyInfo = Session.Deserialize(data);
|
||||
|
||||
if( !world.GameHasStarted )
|
||||
world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
|
||||
|
||||
if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
|
||||
world.SetLocalPlayer(orderManager.Connection.LocalClientId);
|
||||
|
||||
if (orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted)
|
||||
{
|
||||
orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Debug("Order lag is now {0} frames.".F(LobbyInfo.GlobalSettings.OrderLatency));
|
||||
}
|
||||
|
||||
LobbyInfoChanged();
|
||||
}
|
||||
|
||||
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
|
||||
|
||||
|
||||
public static event Action AfterGameStart = () => {};
|
||||
public static event Action<World> AfterGameStart = _ => {};
|
||||
public static event Action BeforeGameStart = () => {};
|
||||
internal static void StartGame(string map)
|
||||
internal static void StartGame(string mapUID)
|
||||
{
|
||||
BeforeGameStart();
|
||||
LoadMap(map);
|
||||
if (orderManager.GameStarted) return;
|
||||
Widget.SelectedWidget = null;
|
||||
|
||||
orderManager.StartGame();
|
||||
viewport.RefreshPalette();
|
||||
AfterGameStart();
|
||||
var map = modData.PrepareMap(mapUID);
|
||||
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
orderManager.world = new World(modData.Manifest, map, orderManager);
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
|
||||
if (orderManager.GameStarted) return;
|
||||
Widget.SelectedWidget = null;
|
||||
|
||||
orderManager.LocalFrameNumber = 0;
|
||||
|
||||
orderManager.StartGame();
|
||||
worldRenderer.RefreshPalette();
|
||||
AfterGameStart( orderManager.world );
|
||||
}
|
||||
|
||||
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
|
||||
{
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
int sync = world.SyncHash();
|
||||
var initialWorld = world;
|
||||
|
||||
var mi = new MouseInput
|
||||
Sync.CheckSyncUnchanged( orderManager.world, () =>
|
||||
{
|
||||
Button = (MouseButton)(int)e.Button,
|
||||
Event = ev,
|
||||
Location = new int2(e.Location),
|
||||
Modifiers = modifierKeys,
|
||||
};
|
||||
Widget.HandleInput(world, mi);
|
||||
|
||||
if (sync != world.SyncHash() && world == initialWorld)
|
||||
throw new InvalidOperationException("Desync in DispatchMouseInput");
|
||||
var mi = new MouseInput
|
||||
{
|
||||
Button = (MouseButton)(int)e.Button,
|
||||
Event = ev,
|
||||
Location = new int2( e.Location ),
|
||||
Modifiers = modifierKeys,
|
||||
};
|
||||
Widget.HandleInput( mi );
|
||||
} );
|
||||
}
|
||||
|
||||
public static bool IsHost
|
||||
@@ -222,23 +196,12 @@ namespace OpenRA
|
||||
get { return orderManager.Connection.LocalClientId == 0; }
|
||||
}
|
||||
|
||||
internal static Session.Client LocalClient
|
||||
{
|
||||
get { return LobbyInfo.Clients.FirstOrDefault(c => c.Index == orderManager.Connection.LocalClientId); }
|
||||
}
|
||||
|
||||
public static void HandleKeyEvent(KeyInput e)
|
||||
{
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
int sync = world.SyncHash();
|
||||
|
||||
if (Widget.HandleKeyPress(e))
|
||||
return;
|
||||
|
||||
if (sync != Game.world.SyncHash())
|
||||
throw new InvalidOperationException("Desync in OnKeyPress");
|
||||
Sync.CheckSyncUnchanged( orderManager.world, () =>
|
||||
{
|
||||
Widget.HandleKeyPress( e );
|
||||
} );
|
||||
}
|
||||
|
||||
static Modifiers modifiers;
|
||||
@@ -247,37 +210,83 @@ namespace OpenRA
|
||||
|
||||
internal static void Initialize(Arguments args)
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
||||
|
||||
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
|
||||
+ Path.DirectorySeparatorChar + "OpenRA";
|
||||
|
||||
SupportDir = args.GetValue("SupportDir", defaultSupport);
|
||||
Settings = new Settings(SupportDir + "settings.yaml", args);
|
||||
|
||||
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
|
||||
Log.AddChannel("perf", "perf.log");
|
||||
Log.AddChannel("debug", "debug.log");
|
||||
Log.AddChannel("sync", "syncreport.log");
|
||||
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
||||
|
||||
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
|
||||
+ Path.DirectorySeparatorChar + "OpenRA";
|
||||
|
||||
SupportDir = args.GetValue("SupportDir", defaultSupport);
|
||||
Settings = new Settings(SupportDir + "settings.yaml", args);
|
||||
|
||||
// force master server upgrade -- remove once everyone is switched over.
|
||||
if (Settings.Server.MasterServer == "http://open-ra.org/master/")
|
||||
Settings.Server.MasterServer = "http://master.open-ra.org/";
|
||||
|
||||
Settings.Save();
|
||||
|
||||
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
|
||||
Log.AddChannel("perf", "perf.log");
|
||||
Log.AddChannel("debug", "debug.log");
|
||||
Log.AddChannel("sync", "syncreport.log");
|
||||
|
||||
FileSystem.Mount("."); // Needed to access shaders
|
||||
Renderer.Initialize( Game.Settings.Graphics.Mode );
|
||||
Renderer.SheetSize = Settings.Game.SheetSize;
|
||||
Renderer = new Renderer();
|
||||
|
||||
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods;
|
||||
modData = new ModData( LobbyInfo.GlobalSettings.Mods );
|
||||
Console.WriteLine("Available mods:");
|
||||
foreach(var mod in ModData.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
|
||||
// Discard any invalid mods
|
||||
var mods = Settings.Game.Mods.Where( m => ModData.AllMods.ContainsKey( m ) ).ToArray();
|
||||
Console.WriteLine("Loading mods: {0}",string.Join(",",mods));
|
||||
|
||||
modData = new ModData( mods );
|
||||
|
||||
Sound.Initialize();
|
||||
PerfHistory.items["render"].hasNormalTick = false;
|
||||
PerfHistory.items["batches"].hasNormalTick = false;
|
||||
PerfHistory.items["text"].hasNormalTick = false;
|
||||
PerfHistory.items["cursor"].hasNormalTick = false;
|
||||
|
||||
PerfHistory.items["cursor"].hasNormalTick = false;
|
||||
|
||||
|
||||
JoinLocal();
|
||||
StartGame(modData.Manifest.ShellmapUid);
|
||||
|
||||
|
||||
Game.AfterGameStart += world => Widget.OpenWindow("INGAME_ROOT", new Dictionary<string,object>{{"world", world},{"orderManager",orderManager}});
|
||||
|
||||
Game.ConnectionStateChanged += orderManager =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
switch( orderManager.Connection.ConnectionState )
|
||||
{
|
||||
case ConnectionState.PreConnecting:
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
Widget.OpenWindow( "CONNECTING_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.NotConnected:
|
||||
Widget.OpenWindow( "CONNECTION_FAILED_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
var lobby = Widget.OpenWindow( "SERVER_LOBBY", new Dictionary<string, object> { { "orderManager", orderManager } } );
|
||||
lobby.GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true;
|
||||
lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true;
|
||||
lobby.GetWidget("DISCONNECT_BUTTON").Visible = true;
|
||||
//r.GetWidget("INGAME_ROOT").GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "PERF_BG" );
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
|
||||
Game.orderManager.LastTickTime = Environment.TickCount;
|
||||
}
|
||||
|
||||
static bool quit;
|
||||
@@ -285,50 +294,48 @@ namespace OpenRA
|
||||
{
|
||||
while (!quit)
|
||||
{
|
||||
{
|
||||
Tick( orderManager, viewport );
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void Exit() { quit = true; }
|
||||
public static void Exit() { quit = true; }
|
||||
|
||||
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
|
||||
|
||||
|
||||
public static void Debug(string s)
|
||||
{
|
||||
public static void Debug(string s, params object[] args)
|
||||
{
|
||||
AddChatLine(Color.White, "Debug", String.Format(s,args));
|
||||
}
|
||||
|
||||
public static void Disconnect()
|
||||
{
|
||||
orderManager.Dispose();
|
||||
var shellmap = modData.Manifest.ShellmapUid;
|
||||
var shellmap = modData.Manifest.ShellmapUid;
|
||||
LobbyInfo = new Session();
|
||||
JoinLocal();
|
||||
StartGame(shellmap);
|
||||
|
||||
|
||||
Widget.RootWidget.CloseWindow();
|
||||
Widget.RootWidget.OpenWindow("MAINMENU_BG");
|
||||
}
|
||||
|
||||
static string baseSupportDir = null;
|
||||
public static string SupportDir
|
||||
{
|
||||
set
|
||||
{
|
||||
var dir = value;
|
||||
|
||||
// Expand paths relative to the personal directory
|
||||
if (dir.ElementAt(0) == '~')
|
||||
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
|
||||
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
Widget.CloseWindow();
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
}
|
||||
|
||||
static string baseSupportDir = null;
|
||||
public static string SupportDir
|
||||
{
|
||||
set
|
||||
{
|
||||
var dir = value;
|
||||
|
||||
// Expand paths relative to the personal directory
|
||||
if (dir.ElementAt(0) == '~')
|
||||
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
|
||||
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
baseSupportDir = dir + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
get { return baseSupportDir; }
|
||||
}
|
||||
|
||||
public static T CreateObject<T>( string name )
|
||||
@@ -336,4 +343,4 @@ namespace OpenRA
|
||||
return modData.ObjectCreator.CreateObject<T>( name );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace OpenRA
|
||||
{
|
||||
public static class Rules
|
||||
{
|
||||
public static TechTree TechTree;
|
||||
|
||||
public static Dictionary<string, ActorInfo> Info;
|
||||
public static Dictionary<string, WeaponInfo> Weapons;
|
||||
public static Dictionary<string, VoiceInfo> Voices;
|
||||
@@ -41,8 +39,6 @@ namespace OpenRA
|
||||
var t = new TileSet(file);
|
||||
TileSets.Add(t.Id,t);
|
||||
}
|
||||
|
||||
TechTree = new TechTree();
|
||||
}
|
||||
|
||||
static Dictionary<string, T> LoadYamlRules<T>(string[] files, List<MiniYamlNode> dict, Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> f)
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using System;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.GameRules
|
||||
public int ListenPort = 1234;
|
||||
public int ExternalPort = 1234;
|
||||
public bool AdvertiseOnline = true;
|
||||
public string MasterServer = "http://open-ra.org/master/";
|
||||
public string MasterServer = "http://master.open-ra.org/";
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace OpenRA.GameRules
|
||||
public bool PerfGraph = false;
|
||||
public bool RecordSyncReports = true;
|
||||
public bool ShowCollisions = false;
|
||||
public float LongTickThreshold = 0.001f;
|
||||
}
|
||||
|
||||
public class GraphicSettings
|
||||
@@ -68,6 +69,7 @@ namespace OpenRA.GameRules
|
||||
// Behaviour settings
|
||||
public bool ViewportEdgeScroll = true;
|
||||
public bool InverseDragScroll = false;
|
||||
public float ViewportEdgeScrollStep = 10f;
|
||||
|
||||
// Internal game settings
|
||||
public int Timestep = 40;
|
||||
@@ -105,12 +107,12 @@ namespace OpenRA.GameRules
|
||||
|
||||
FieldLoader.UnknownFieldAction = (s,f) =>
|
||||
{
|
||||
System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
|
||||
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
|
||||
};
|
||||
|
||||
if (File.Exists(SettingsFile))
|
||||
{
|
||||
System.Console.WriteLine("Loading settings file {0}",SettingsFile);
|
||||
Console.WriteLine("Loading settings file {0}",SettingsFile);
|
||||
var yaml = MiniYaml.DictFromFile(SettingsFile);
|
||||
|
||||
foreach (var kv in Sections)
|
||||
@@ -122,7 +124,7 @@ namespace OpenRA.GameRules
|
||||
foreach (var kv in Sections)
|
||||
foreach (var f in kv.Value.GetType().GetFields())
|
||||
if (args.Contains(kv.Key+"."+f.Name))
|
||||
OpenRA.FileFormats.FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
|
||||
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
|
||||
|
||||
FieldLoader.UnknownFieldAction = err1;
|
||||
FieldLoader.InvalidValueAction = err2;
|
||||
@@ -132,16 +134,11 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
foreach( var kv in Sections )
|
||||
root.Add( new MiniYamlNode( kv.Key, SectionYaml( kv.Value ) ) );
|
||||
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
|
||||
|
||||
root.WriteToFile(SettingsFile);
|
||||
}
|
||||
|
||||
MiniYaml SectionYaml(object section)
|
||||
{
|
||||
return FieldSaver.SaveDifferences(section, Activator.CreateInstance(section.GetType()));
|
||||
}
|
||||
|
||||
void LoadSectionYaml(MiniYaml yaml, object section)
|
||||
{
|
||||
object defaults = Activator.CreateInstance(section.GetType());
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
public class TechTree
|
||||
{
|
||||
readonly Cache<string, List<ActorInfo>> producesIndex = new Cache<string, List<ActorInfo>>(x => new List<ActorInfo>());
|
||||
|
||||
public TechTree()
|
||||
{
|
||||
foreach( var info in Rules.Info.Values )
|
||||
{
|
||||
var pi = info.Traits.GetOrDefault<ProductionInfo>();
|
||||
if (pi != null)
|
||||
foreach( var p in pi.Produces )
|
||||
producesIndex[ p ].Add( info );
|
||||
}
|
||||
}
|
||||
|
||||
public Cache<string, List<Actor>> GatherBuildings( Player player )
|
||||
{
|
||||
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
|
||||
if (player == null)
|
||||
return ret;
|
||||
|
||||
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
|
||||
{
|
||||
ret[ b.Info.Name ].Add( b );
|
||||
var tt = b.Info.Traits.GetOrDefault<TooltipInfo>();
|
||||
if( tt != null )
|
||||
foreach( var alt in tt.AlternateName )
|
||||
ret[ alt ].Add( b );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool CanBuild( ActorInfo info, Player player, Cache<string, List<Actor>> playerBuildings )
|
||||
{
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
var bi = info.Traits.GetOrDefault<BuildableInfo>();
|
||||
if( bi == null ) return false;
|
||||
|
||||
if( !bi.Owner.Contains( player.Country.Race ) )
|
||||
return false;
|
||||
|
||||
foreach( var p in bi.Prerequisites )
|
||||
if( playerBuildings[ p ].Count == 0 )
|
||||
return false;
|
||||
|
||||
if( producesIndex[ bi.Queue ].All( x => playerBuildings[ x.Name ].Count == 0 ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<string> BuildableItems( Player player, params string[] categories )
|
||||
{
|
||||
if (player == null)
|
||||
yield break;
|
||||
|
||||
var playerBuildings = GatherBuildings( player );
|
||||
foreach (var unit in AllBuildables(categories))
|
||||
if( CanBuild( unit, player, playerBuildings ) )
|
||||
yield return unit.Name;
|
||||
}
|
||||
|
||||
public IEnumerable<ActorInfo> AllBuildables(params string[] categories)
|
||||
{
|
||||
return Rules.Info.Values
|
||||
.Where( x => x.Name[ 0 ] != '^' )
|
||||
.Where( x => x.Traits.Contains<BuildableInfo>() )
|
||||
.Where( x => categories.Contains(x.Traits.Get<BuildableInfo>().Queue) );
|
||||
}
|
||||
|
||||
public IEnumerable<ActorInfo> UnitBuiltAt( ActorInfo info )
|
||||
{
|
||||
var bi = info.Traits.Get<BuildableInfo>();
|
||||
var builtAt = bi.BuiltAt;
|
||||
if( builtAt.Length != 0 )
|
||||
return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] );
|
||||
else
|
||||
return producesIndex[ bi.Queue ];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.GameRules
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public readonly Lazy<Dictionary<string, VoicePool>> Pools;
|
||||
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
|
||||
|
||||
public VoiceInfo( MiniYaml y )
|
||||
{
|
||||
@@ -41,6 +41,9 @@ namespace OpenRA.GameRules
|
||||
|
||||
if (!Voices.ContainsKey("Attack"))
|
||||
Voices.Add("Attack", Voices["Move"]);
|
||||
|
||||
if (!Voices.ContainsKey("AttackMove"))
|
||||
Voices.Add("AttackMove", Voices["Move"]);
|
||||
|
||||
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace OpenRA.GameRules
|
||||
[FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal
|
||||
[FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
|
||||
[FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
|
||||
[FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry.
|
||||
|
||||
public float EffectivenessAgainst(Actor self)
|
||||
{
|
||||
@@ -92,6 +93,7 @@ namespace OpenRA.GameRules
|
||||
[FieldLoader.Load] public readonly bool Underwater = false;
|
||||
[FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" };
|
||||
[FieldLoader.Load] public readonly int BurstDelay = 5;
|
||||
[FieldLoader.Load] public readonly float MinRange = 0;
|
||||
|
||||
[FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile;
|
||||
[FieldLoader.LoadUsing( "LoadWarheads" )] public List<WarheadInfo> Warheads;
|
||||
|
||||
@@ -13,45 +13,46 @@ using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class LineRenderer
|
||||
public class LineRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
Renderer renderer;
|
||||
IVertexBuffer<Vertex> vertexBuffer;
|
||||
IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */
|
||||
|
||||
const int linesPerBatch = 1024;
|
||||
|
||||
Vertex[] vertices = new Vertex[ 2 * linesPerBatch ];
|
||||
ushort[] indices = new ushort[ 2 * linesPerBatch ];
|
||||
int lines = 0;
|
||||
Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ];
|
||||
ushort[] indices = new ushort[ Renderer.TempBufferSize ];
|
||||
int nv = 0, ni = 0;
|
||||
|
||||
public LineRenderer( Renderer renderer )
|
||||
{
|
||||
this.renderer = renderer;
|
||||
vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length );
|
||||
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if( lines > 0 )
|
||||
if( ni > 0 )
|
||||
{
|
||||
renderer.LineShader.Render( () =>
|
||||
{
|
||||
vertexBuffer.SetData( vertices );
|
||||
indexBuffer.SetData( indices );
|
||||
renderer.DrawBatch( vertexBuffer, indexBuffer,
|
||||
var vb = renderer.GetTempVertexBuffer();
|
||||
var ib = renderer.GetTempIndexBuffer();
|
||||
vb.SetData( vertices, nv );
|
||||
ib.SetData( indices, ni );
|
||||
renderer.DrawBatch( vb, ib,
|
||||
nv, ni / 2, PrimitiveType.LineList );
|
||||
} );
|
||||
|
||||
nv = 0; ni = 0;
|
||||
lines = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor )
|
||||
{
|
||||
Renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if( ni + 2 > Renderer.TempBufferSize )
|
||||
Flush();
|
||||
if( nv + 2 > Renderer.TempBufferSize )
|
||||
Flush();
|
||||
|
||||
indices[ ni++ ] = (ushort)nv;
|
||||
|
||||
vertices[ nv++ ] = new Vertex( start,
|
||||
@@ -63,9 +64,6 @@ namespace OpenRA.Graphics
|
||||
vertices[ nv++ ] = new Vertex( end,
|
||||
new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
|
||||
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
|
||||
|
||||
if( ++lines >= linesPerBatch )
|
||||
Flush();
|
||||
}
|
||||
|
||||
public void FillRect( RectangleF r, Color color )
|
||||
|
||||
@@ -14,16 +14,29 @@ using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class Minimap
|
||||
{
|
||||
public static Bitmap TerrainBitmap(Map map)
|
||||
{
|
||||
return TerrainBitmap(map, false);
|
||||
}
|
||||
|
||||
public static Bitmap TerrainBitmap(Map map, bool actualSize)
|
||||
{
|
||||
var tileset = Rules.TileSets[map.Tileset];
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
Bitmap terrain = new Bitmap(size, size);
|
||||
var width = map.Width;
|
||||
var height = map.Height;
|
||||
|
||||
if (!actualSize)
|
||||
{
|
||||
width = height = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
}
|
||||
|
||||
Bitmap terrain = new Bitmap(width, height);
|
||||
|
||||
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
@@ -38,6 +51,9 @@ namespace OpenRA.Graphics
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]);
|
||||
if (!tileset.Terrain.ContainsKey(type))
|
||||
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
|
||||
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Support;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -23,10 +24,10 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
internal static int SheetSize;
|
||||
|
||||
public IShader SpriteShader { get; private set; } /* note: shared shader params */
|
||||
public IShader LineShader { get; private set; }
|
||||
public IShader RgbaSpriteShader { get; private set; }
|
||||
public IShader WorldSpriteShader { get; private set; }
|
||||
internal IShader SpriteShader { get; private set; } /* note: shared shader params */
|
||||
internal IShader LineShader { get; private set; }
|
||||
internal IShader RgbaSpriteShader { get; private set; }
|
||||
internal IShader WorldSpriteShader { get; private set; }
|
||||
|
||||
public SpriteRenderer SpriteRenderer { get; private set; }
|
||||
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
|
||||
@@ -37,6 +38,12 @@ namespace OpenRA.Graphics
|
||||
|
||||
public readonly SpriteFont RegularFont, BoldFont, TitleFont;
|
||||
|
||||
internal const int TempBufferSize = 8192;
|
||||
const int TempBufferCount = 8;
|
||||
|
||||
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
|
||||
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
|
||||
|
||||
public Renderer()
|
||||
{
|
||||
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
|
||||
@@ -52,9 +59,15 @@ namespace OpenRA.Graphics
|
||||
RegularFont = new SpriteFont("FreeSans.ttf", 14);
|
||||
BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
|
||||
TitleFont = new SpriteFont("titles.ttf", 48);
|
||||
|
||||
for( int i = 0 ; i < TempBufferCount ; i++ )
|
||||
{
|
||||
tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) );
|
||||
tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) );
|
||||
}
|
||||
}
|
||||
|
||||
public IGraphicsDevice Device { get { return device; } }
|
||||
internal IGraphicsDevice Device { get { return device; } }
|
||||
|
||||
public void BeginFrame(float2 scroll)
|
||||
{
|
||||
@@ -81,6 +94,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void EndFrame()
|
||||
{
|
||||
Flush();
|
||||
device.End();
|
||||
device.Present();
|
||||
}
|
||||
@@ -111,15 +125,9 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
WorldSpriteRenderer.Flush();
|
||||
RgbaSpriteRenderer.Flush();
|
||||
LineRenderer.Flush();
|
||||
CurrentBatchRenderer = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static IGraphicsDevice device;
|
||||
|
||||
public static Size Resolution { get { return device.WindowSize; } }
|
||||
@@ -154,5 +162,49 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
|
||||
{
|
||||
var ret = tempBuffersV.Dequeue();
|
||||
tempBuffersV.Enqueue( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal IIndexBuffer GetTempIndexBuffer()
|
||||
{
|
||||
var ret = tempBuffersI.Dequeue();
|
||||
tempBuffersI.Enqueue( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
public interface IBatchRenderer
|
||||
{
|
||||
void Flush();
|
||||
}
|
||||
|
||||
static IBatchRenderer currentBatchRenderer;
|
||||
public static IBatchRenderer CurrentBatchRenderer
|
||||
{
|
||||
get { return currentBatchRenderer; }
|
||||
set
|
||||
{
|
||||
if( currentBatchRenderer == value ) return;
|
||||
if( currentBatchRenderer != null )
|
||||
currentBatchRenderer.Flush();
|
||||
currentBatchRenderer = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableScissor(int left, int top, int width, int height)
|
||||
{
|
||||
Flush();
|
||||
Device.EnableScissor( left, top, width, height );
|
||||
}
|
||||
|
||||
public void DisableScissor()
|
||||
{
|
||||
Flush();
|
||||
Device.DisableScissor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,21 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
return uvhax[ k ];
|
||||
}
|
||||
|
||||
public void DrawAt( WorldRenderer wr, float2 location, string palette )
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size );
|
||||
}
|
||||
|
||||
public void DrawAt( float2 location, int paletteIndex )
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
|
||||
}
|
||||
|
||||
public void DrawAt( float2 location, int paletteIndex, float2 size )
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size );
|
||||
}
|
||||
}
|
||||
|
||||
public enum TextureChannel
|
||||
|
||||
@@ -80,17 +80,20 @@ namespace OpenRA.Graphics
|
||||
GlyphInfo CreateGlyph(Pair<char,Color> c)
|
||||
{
|
||||
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
|
||||
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
|
||||
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
|
||||
throw new InvalidOperationException( "FT_Load_Glyph failed." );
|
||||
|
||||
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
|
||||
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
|
||||
|
||||
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
|
||||
var s = builder.Allocate(
|
||||
new Size(_glyph.metrics.width.ToInt32() >> 6,
|
||||
_glyph.metrics.height.ToInt32() >> 6));
|
||||
|
||||
var g = new GlyphInfo
|
||||
{
|
||||
Sprite = s,
|
||||
Advance = _glyph.metrics.horiAdvance / 64f,
|
||||
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
|
||||
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
|
||||
};
|
||||
|
||||
|
||||
@@ -12,28 +12,20 @@ using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class SpriteRenderer
|
||||
public class SpriteRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
IVertexBuffer<Vertex> vertexBuffer;
|
||||
IIndexBuffer indexBuffer;
|
||||
Renderer renderer;
|
||||
IShader shader;
|
||||
|
||||
const int spritesPerBatch = 1024;
|
||||
|
||||
Vertex[] vertices = new Vertex[4 * spritesPerBatch];
|
||||
ushort[] indices = new ushort[6 * spritesPerBatch];
|
||||
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
|
||||
ushort[] indices = new ushort[Renderer.TempBufferSize];
|
||||
Sheet currentSheet = null;
|
||||
int sprites = 0;
|
||||
int nv = 0, ni = 0;
|
||||
|
||||
public SpriteRenderer(Renderer renderer, IShader shader)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
|
||||
vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length );
|
||||
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
|
||||
}
|
||||
|
||||
public SpriteRenderer(Renderer renderer)
|
||||
@@ -41,14 +33,16 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (sprites > 0)
|
||||
if (ni > 0)
|
||||
{
|
||||
shader.SetValue( "DiffuseTexture", currentSheet.Texture );
|
||||
shader.Render(() =>
|
||||
{
|
||||
vertexBuffer.SetData(vertices);
|
||||
indexBuffer.SetData(indices);
|
||||
renderer.DrawBatch(vertexBuffer, indexBuffer,
|
||||
var vb = renderer.GetTempVertexBuffer();
|
||||
var ib = renderer.GetTempIndexBuffer();
|
||||
vb.SetData(vertices, nv);
|
||||
ib.SetData(indices, ni);
|
||||
renderer.DrawBatch(vb, ib,
|
||||
new Range<int>(0, nv),
|
||||
new Range<int>(0, ni),
|
||||
PrimitiveType.TriangleList,
|
||||
@@ -57,30 +51,34 @@ namespace OpenRA.Graphics
|
||||
|
||||
nv = 0; ni = 0;
|
||||
currentSheet = null;
|
||||
sprites = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSprite(Sprite s, float2 location, string palette)
|
||||
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette)
|
||||
{
|
||||
DrawSprite(s, location, Game.world.WorldRenderer.GetPaletteIndex(palette), s.size);
|
||||
DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size);
|
||||
}
|
||||
|
||||
public void DrawSprite(Sprite s, float2 location, string palette, float2 size)
|
||||
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size)
|
||||
{
|
||||
DrawSprite(s, location, Game.world.WorldRenderer.GetPaletteIndex(palette), size);
|
||||
DrawSprite(s, location, wr.GetPaletteIndex(palette), size);
|
||||
}
|
||||
|
||||
public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
|
||||
{
|
||||
Renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (s.sheet != currentSheet)
|
||||
Flush();
|
||||
|
||||
if( nv + 4 > Renderer.TempBufferSize )
|
||||
Flush();
|
||||
if( ni + 6 > Renderer.TempBufferSize )
|
||||
Flush();
|
||||
|
||||
currentSheet = s.sheet;
|
||||
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size);
|
||||
nv += 4; ni += 6;
|
||||
if (++sprites >= spritesPerBatch)
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace OpenRA.Graphics
|
||||
this.map = world.Map;
|
||||
|
||||
Size tileSize = new Size( Game.CellSize, Game.CellSize );
|
||||
|
||||
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
|
||||
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
|
||||
|
||||
@@ -47,7 +46,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
Sprite tile = tileMapping[map.MapTiles[i, j]];
|
||||
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
|
||||
// before the palettes are created
|
||||
// before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined
|
||||
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni, tile.size);
|
||||
nv += 4;
|
||||
ni += 6;
|
||||
@@ -57,20 +56,20 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
|
||||
vertexBuffer.SetData( vertices );
|
||||
vertexBuffer.SetData( vertices, nv );
|
||||
|
||||
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
|
||||
indexBuffer.SetData( indices );
|
||||
indexBuffer.SetData( indices, ni );
|
||||
}
|
||||
|
||||
public void Draw( Viewport viewport )
|
||||
public void Draw( WorldRenderer wr, Viewport viewport )
|
||||
{
|
||||
int indicesPerRow = map.Width * 6;
|
||||
int verticesPerRow = map.Width * 4;
|
||||
|
||||
int visibleRows = (int)(viewport.Height / 24.0f + 2);
|
||||
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
|
||||
|
||||
int firstRow = (int)((viewport.Location.Y) / 24.0f - map.YOffset);
|
||||
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.YOffset);
|
||||
int lastRow = firstRow + visibleRows;
|
||||
|
||||
if (lastRow < 0 || firstRow > map.Height)
|
||||
@@ -99,7 +98,7 @@ namespace OpenRA.Graphics
|
||||
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
|
||||
|
||||
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
|
||||
r.Render();
|
||||
r.Render( wr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
@@ -96,34 +95,23 @@ namespace OpenRA.Graphics
|
||||
this.scrollPosition = Game.CellSize* mapStart;
|
||||
}
|
||||
|
||||
public void DrawRegions( World world )
|
||||
public void DrawRegions( WorldRenderer wr )
|
||||
{
|
||||
renderer.BeginFrame(scrollPosition);
|
||||
world.WorldRenderer.Draw();
|
||||
wr.Draw();
|
||||
|
||||
Widget.DoDraw(world);
|
||||
Widget.DoDraw( wr );
|
||||
|
||||
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
var c = new Cursor(cursorName);
|
||||
c.Draw((int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
|
||||
renderer.RgbaSpriteRenderer.Flush();
|
||||
renderer.SpriteRenderer.Flush();
|
||||
renderer.WorldSpriteRenderer.Flush();
|
||||
c.Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
|
||||
renderer.EndFrame();
|
||||
}
|
||||
|
||||
public void RefreshPalette()
|
||||
{
|
||||
Game.world.WorldRenderer.palette.Update(
|
||||
Game.world.WorldActor.TraitsImplementing<IPaletteModifier>());
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
cursorFrame += 0.5f;
|
||||
RefreshPalette();
|
||||
}
|
||||
|
||||
public float2 ViewToWorld(int2 loc)
|
||||
@@ -151,12 +139,21 @@ namespace OpenRA.Graphics
|
||||
scrollPosition = this.NormalizeScrollPosition((avgPos - .5f * new float2(Width, Height)));
|
||||
}
|
||||
|
||||
public Rectangle? ShroudBounds()
|
||||
public Rectangle ShroudBounds( World world )
|
||||
{
|
||||
var localPlayer = Game.world.LocalPlayer;
|
||||
if (localPlayer == null) return null;
|
||||
if (localPlayer.Shroud.Disabled) return null;
|
||||
return localPlayer.Shroud.Bounds;
|
||||
var localPlayer = world.LocalPlayer;
|
||||
if( localPlayer == null ) return world.Map.Bounds;
|
||||
if( localPlayer.Shroud.Disabled ) return world.Map.Bounds;
|
||||
if( !localPlayer.Shroud.Bounds.HasValue ) return world.Map.Bounds;
|
||||
return Rectangle.Intersect( localPlayer.Shroud.Bounds.Value, world.Map.Bounds );
|
||||
}
|
||||
|
||||
public Rectangle ViewBounds()
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,9 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class WorldRenderer
|
||||
{
|
||||
readonly World world;
|
||||
public readonly World world;
|
||||
internal readonly TerrainRenderer terrainRenderer;
|
||||
internal readonly UiOverlay uiOverlay;
|
||||
public readonly UiOverlay uiOverlay;
|
||||
internal readonly HardwarePalette palette;
|
||||
|
||||
internal WorldRenderer(World world)
|
||||
@@ -31,6 +31,9 @@ namespace OpenRA.Graphics
|
||||
terrainRenderer = new TerrainRenderer(world, this);
|
||||
uiOverlay = new UiOverlay();
|
||||
palette = new HardwarePalette(world.Map);
|
||||
|
||||
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) )
|
||||
pal.Trait.InitPalette( this );
|
||||
}
|
||||
|
||||
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
|
||||
@@ -41,11 +44,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public int Compare(Renderable x, Renderable y)
|
||||
{
|
||||
var result = x.ZOffset.CompareTo(y.ZOffset);
|
||||
if (result == 0)
|
||||
result = x.Pos.Y.CompareTo(y.Pos.Y);
|
||||
|
||||
return result;
|
||||
return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,33 +92,26 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
RefreshPalette();
|
||||
var bounds = GetBoundsRect();
|
||||
Game.Renderer.Device.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
|
||||
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
|
||||
|
||||
terrainRenderer.Draw(Game.viewport);
|
||||
terrainRenderer.Draw(this, Game.viewport);
|
||||
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderBeforeWorld(world);
|
||||
world.OrderGenerator.RenderBeforeWorld(this, world);
|
||||
|
||||
Game.Renderer.SpriteRenderer.Flush();
|
||||
Game.Renderer.LineRenderer.Flush();
|
||||
|
||||
foreach (var image in worldSprites)
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(image.Sprite, image.Pos, image.Palette);
|
||||
uiOverlay.Draw(world);
|
||||
Game.Renderer.SpriteRenderer.Flush();
|
||||
foreach( var image in worldSprites )
|
||||
image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) );
|
||||
uiOverlay.Draw(this, world);
|
||||
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderAfterWorld(world);
|
||||
world.OrderGenerator.RenderAfterWorld(this, world);
|
||||
|
||||
if (world.LocalPlayer != null)
|
||||
world.LocalPlayer.Shroud.Draw();
|
||||
world.LocalPlayer.Shroud.Draw( this );
|
||||
|
||||
Game.Renderer.SpriteRenderer.Flush();
|
||||
|
||||
Game.Renderer.Device.DisableScissor();
|
||||
|
||||
Game.Renderer.LineRenderer.Flush();
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
|
||||
void DrawBox(RectangleF r, Color color)
|
||||
@@ -142,8 +134,8 @@ namespace OpenRA.Graphics
|
||||
for (var j = 0; j < world.Map.MapSize.Y;
|
||||
j += world.WorldActor.Info.Traits.Get<SpatialBinsInfo>().BinSize)
|
||||
{
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * 24), new float2(world.Map.MapSize.X * 24, j * 24), Color.Black, Color.Black);
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(j * 24, 0), new float2(j * 24, world.Map.MapSize.Y * 24), Color.Black, Color.Black);
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * Game.CellSize), new float2(world.Map.MapSize.X * Game.CellSize, j * Game.CellSize), Color.Black, Color.Black);
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(j * Game.CellSize, 0), new float2(j * Game.CellSize, world.Map.MapSize.Y * Game.CellSize), Color.Black, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,5 +189,10 @@ namespace OpenRA.Graphics
|
||||
prev = pos;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshPalette()
|
||||
{
|
||||
palette.Update( world.WorldActor.TraitsImplementing<IPaletteModifier>() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,14 +62,22 @@ namespace OpenRA
|
||||
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
|
||||
|
||||
public Map()
|
||||
{
|
||||
// Do nothing; not a valid map (editor hack)
|
||||
}
|
||||
|
||||
public Map(string tileset)
|
||||
{
|
||||
MapSize = new int2(1, 1);
|
||||
Tileset = tileset;
|
||||
MapResources = new TileReference<byte, byte>[1, 1];
|
||||
MapTiles = new TileReference<ushort, byte>[1, 1]
|
||||
{ { new TileReference<ushort, byte> {
|
||||
type = (ushort)0xffffu,
|
||||
image = (byte)0xffu,
|
||||
index = (byte)0xffu } } };
|
||||
|
||||
var tile = OpenRA.Rules.TileSets[Tileset].Templates.First();
|
||||
MapTiles = new TileReference<ushort, byte>[1, 1]
|
||||
{ { new TileReference<ushort, byte> {
|
||||
type = tile.Key,
|
||||
image = (byte)(tile.Value.PickAny ? 0xffu : 0),
|
||||
index = (byte)(tile.Value.PickAny ? 0xffu : 0) } } };
|
||||
|
||||
PlayerCount = 0;
|
||||
TopLeft = new int2(0, 0);
|
||||
|
||||
@@ -19,15 +19,48 @@ namespace OpenRA
|
||||
{
|
||||
public class ModData
|
||||
{
|
||||
public static readonly Dictionary<string,Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public static Dictionary<string,Mod> ValidateMods(string[] mods)
|
||||
{
|
||||
var ret = new Dictionary<string,Mod>();
|
||||
foreach (var m in mods)
|
||||
{
|
||||
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
|
||||
continue;
|
||||
|
||||
var yaml = new MiniYaml( null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
|
||||
if (!yaml.NodesDict.ContainsKey("Metadata"))
|
||||
{
|
||||
System.Console.WriteLine("Invalid mod: "+m);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.Add(m,FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class Mod
|
||||
{
|
||||
public string Title;
|
||||
public string Description;
|
||||
public string Version;
|
||||
public string Author;
|
||||
public string[] RequiresMods;
|
||||
public bool Standalone = false;
|
||||
}
|
||||
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
public readonly CursorSheetBuilder CursorSheetBuilder;
|
||||
public readonly Dictionary<string, MapStub> AvailableMaps;
|
||||
public readonly WidgetLoader WidgetLoader;
|
||||
public ILoadScreen LoadScreen = null;
|
||||
|
||||
public ModData( params string[] mods )
|
||||
{
|
||||
{
|
||||
Manifest = new Manifest( mods );
|
||||
ObjectCreator = new ObjectCreator( Manifest );
|
||||
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
|
||||
@@ -39,6 +72,7 @@ namespace OpenRA
|
||||
SheetBuilder = new SheetBuilder( TextureChannel.Red );
|
||||
CursorSheetBuilder = new CursorSheetBuilder( this );
|
||||
AvailableMaps = FindMaps( mods );
|
||||
WidgetLoader = new WidgetLoader( this );
|
||||
}
|
||||
|
||||
// TODO: Do this nicer
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA.Network
|
||||
Connected,
|
||||
}
|
||||
|
||||
interface IConnection
|
||||
interface IConnection : IDisposable
|
||||
{
|
||||
int LocalClientId { get; }
|
||||
ConnectionState ConnectionState { get; }
|
||||
@@ -73,9 +73,11 @@ namespace OpenRA.Network
|
||||
foreach( var p in packets )
|
||||
packetFn( p.FromClient, p.Data );
|
||||
}
|
||||
|
||||
public virtual void Dispose() { }
|
||||
}
|
||||
|
||||
class NetworkConnection : EchoConnection, IDisposable
|
||||
class NetworkConnection : EchoConnection
|
||||
{
|
||||
TcpClient socket;
|
||||
int clientId;
|
||||
@@ -112,12 +114,13 @@ namespace OpenRA.Network
|
||||
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
|
||||
}
|
||||
}
|
||||
catch( SocketException )
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
connectionState = ConnectionState.NotConnected;
|
||||
if( socket != null )
|
||||
socket.Close();
|
||||
}
|
||||
catch ( IOException ) { socket.Close(); }
|
||||
catch (ThreadAbortException ) { socket.Close(); }
|
||||
}
|
||||
) { IsBackground = true };
|
||||
t.Start();
|
||||
@@ -132,12 +135,10 @@ namespace OpenRA.Network
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(BitConverter.GetBytes((int)packet.Length));
|
||||
ms.Write(packet);
|
||||
ms.WriteTo(socket.GetStream());
|
||||
|
||||
}
|
||||
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
|
||||
catch (ObjectDisposedException) { /* ditto */ }
|
||||
@@ -145,7 +146,7 @@ namespace OpenRA.Network
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
public void Dispose ()
|
||||
public override void Dispose ()
|
||||
{
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
@@ -160,48 +161,4 @@ namespace OpenRA.Network
|
||||
|
||||
~NetworkConnection() { Dispose(); }
|
||||
}
|
||||
|
||||
class ReplayConnection : IConnection
|
||||
{
|
||||
//uint nextFrame = 1;
|
||||
FileStream replayStream;
|
||||
|
||||
public ReplayConnection( string replayFilename )
|
||||
{
|
||||
replayStream = File.OpenRead( replayFilename );
|
||||
}
|
||||
|
||||
public int LocalClientId
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public ConnectionState ConnectionState
|
||||
{
|
||||
get { return ConnectionState.Connected; }
|
||||
}
|
||||
|
||||
public void Send( byte[] packet )
|
||||
{
|
||||
// do nothing; ignore locally generated orders
|
||||
}
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
if( replayStream == null ) return;
|
||||
|
||||
var reader = new BinaryReader( replayStream );
|
||||
while( replayStream.Position < replayStream.Length )
|
||||
{
|
||||
var client = reader.ReadInt32();
|
||||
var packetLen = reader.ReadInt32();
|
||||
var packet = reader.ReadBytes( packetLen );
|
||||
packetFn( client, packet );
|
||||
|
||||
if( !Game.orderManager.GameStarted )
|
||||
return;
|
||||
}
|
||||
replayStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
56
OpenRA.Game/Network/FrameData.cs
Executable file
56
OpenRA.Game/Network/FrameData.cs
Executable file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class FrameData
|
||||
{
|
||||
public struct ClientOrder
|
||||
{
|
||||
public int Client;
|
||||
public Order Order;
|
||||
}
|
||||
|
||||
readonly Dictionary<int, int> clientQuitTimes = new Dictionary<int, int>();
|
||||
readonly Dictionary<int, Dictionary<int, byte[]>> framePackets = new Dictionary<int, Dictionary<int, byte[]>>();
|
||||
|
||||
public IEnumerable<int> ClientsPlayingInFrame( int frame )
|
||||
{
|
||||
return clientQuitTimes
|
||||
.Where( x => frame <= x.Value )
|
||||
.Select( x => x.Key )
|
||||
.OrderBy( x => x );
|
||||
}
|
||||
|
||||
public void ClientQuit( int clientId, int lastClientFrame )
|
||||
{
|
||||
clientQuitTimes.Add( clientId, lastClientFrame );
|
||||
}
|
||||
|
||||
public void AddFrameOrders( int clientId, int frame, byte[] orders )
|
||||
{
|
||||
var frameData = framePackets.GetOrAdd( frame );
|
||||
frameData.Add( clientId, orders );
|
||||
}
|
||||
|
||||
public bool IsReadyForFrame( int frame )
|
||||
{
|
||||
var frameData = framePackets.GetOrAdd( frame );
|
||||
return ClientsPlayingInFrame( frame )
|
||||
.All( client => frameData.ContainsKey( client ) );
|
||||
}
|
||||
|
||||
public IEnumerable<ClientOrder> OrdersForFrame( World world, int frame )
|
||||
{
|
||||
var frameData = framePackets[ frame ];
|
||||
var clientData = ClientsPlayingInFrame( frame )
|
||||
.ToDictionary( k => k, v => frameData[ v ] );
|
||||
|
||||
return clientData
|
||||
.SelectMany( x => x.Value
|
||||
.ToOrderList( world )
|
||||
.Select( o => new ClientOrder { Client = x.Key, Order = o } ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,9 +187,9 @@ namespace OpenRA
|
||||
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item);
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item)
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, item);
|
||||
return new Order("CancelProduction", subject, new int2( count, 0 ), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,45 +18,44 @@ namespace OpenRA.Network
|
||||
{
|
||||
class OrderManager : IDisposable
|
||||
{
|
||||
SyncReport syncReport = new SyncReport();
|
||||
readonly SyncReport syncReport;
|
||||
readonly FrameData frameData = new FrameData();
|
||||
|
||||
public int FrameNumber { get; private set; }
|
||||
public Session LobbyInfo = new Session( Game.Settings.Game.Mods );
|
||||
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } }
|
||||
public World world;
|
||||
|
||||
public readonly string Host;
|
||||
public readonly int Port;
|
||||
|
||||
public int NetFrameNumber { get; private set; }
|
||||
public int LocalFrameNumber;
|
||||
public int FramesAhead = 0;
|
||||
|
||||
public bool GameStarted { get { return FrameNumber != 0; } }
|
||||
public int LastTickTime = Environment.TickCount;
|
||||
|
||||
public bool GameStarted { get { return NetFrameNumber != 0; } }
|
||||
public IConnection Connection { get; private set; }
|
||||
|
||||
public readonly int SyncHeaderSize = 9;
|
||||
|
||||
Dictionary<int, int> clientQuitTimes = new Dictionary<int, int>();
|
||||
|
||||
Dictionary<int, Dictionary<int, byte[]>> frameClientData =
|
||||
new Dictionary<int, Dictionary<int, byte[]>>();
|
||||
List<Order> localOrders = new List<Order>();
|
||||
|
||||
FileStream replaySaveFile;
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
if (GameStarted) return;
|
||||
|
||||
FrameNumber = 1;
|
||||
for( int i = FrameNumber ; i <= FramesAhead ; i++ )
|
||||
NetFrameNumber = 1;
|
||||
for( int i = NetFrameNumber ; i <= FramesAhead ; i++ )
|
||||
Connection.Send( new List<Order>().Serialize( i ) );
|
||||
}
|
||||
|
||||
public OrderManager( IConnection conn )
|
||||
public OrderManager( string host, int port, IConnection conn )
|
||||
{
|
||||
this.Host = host;
|
||||
this.Port = port;
|
||||
Connection = conn;
|
||||
}
|
||||
|
||||
public OrderManager( IConnection conn, string replayFilename )
|
||||
: this( conn )
|
||||
{
|
||||
string path = Game.SupportDir + "Replays" + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
replaySaveFile = File.Create( path + replayFilename );
|
||||
syncReport = new SyncReport( this );
|
||||
}
|
||||
|
||||
public void IssueOrders( Order[] orders )
|
||||
@@ -70,7 +69,7 @@ namespace OpenRA.Network
|
||||
localOrders.Add( order );
|
||||
}
|
||||
|
||||
public void TickImmediate( World world )
|
||||
public void TickImmediate()
|
||||
{
|
||||
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
|
||||
if( immediateOrders.Count != 0 )
|
||||
@@ -84,21 +83,18 @@ namespace OpenRA.Network
|
||||
{
|
||||
var frame = BitConverter.ToInt32( packet, 0 );
|
||||
if( packet.Length == 5 && packet[ 4 ] == 0xBF )
|
||||
clientQuitTimes[ clientId ] = frame;
|
||||
frameData.ClientQuit( clientId, frame );
|
||||
else if( packet.Length >= 5 && packet[ 4 ] == 0x65 )
|
||||
CheckSync( packet );
|
||||
else if( frame == 0 )
|
||||
immediatePackets.Add( Pair.New( clientId, packet ) );
|
||||
else
|
||||
frameClientData.GetOrAdd( frame ).Add( clientId, packet );
|
||||
frameData.AddFrameOrders( clientId, frame, packet );
|
||||
} );
|
||||
|
||||
foreach( var p in immediatePackets )
|
||||
{
|
||||
foreach( var o in p.Second.ToOrderList( world ) )
|
||||
UnitOrders.ProcessOrder( world, p.First, o );
|
||||
WriteImmediateToReplay( immediatePackets );
|
||||
}
|
||||
UnitOrders.ProcessOrder( this, world, p.First, o );
|
||||
}
|
||||
|
||||
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
|
||||
@@ -134,14 +130,9 @@ namespace OpenRA.Network
|
||||
syncForFrame.Add(frame, packet);
|
||||
}
|
||||
|
||||
void OutOfSync( int frame , int index)
|
||||
{
|
||||
var frameData = clientQuitTimes
|
||||
.Where( x => frame <= x.Value )
|
||||
.OrderBy( x => x.Key )
|
||||
.ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] );
|
||||
|
||||
var order = frameData.SelectMany( o => o.Value.ToOrderList( Game.world ).Select( a => new { Client = o.Key, Order = a } ) ).ElementAt(index);
|
||||
void OutOfSync(int frame, int index)
|
||||
{
|
||||
var order = frameData.OrdersForFrame( world, frame ).ElementAt(index);
|
||||
throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, order.Order.ToString()));
|
||||
}
|
||||
|
||||
@@ -157,72 +148,34 @@ namespace OpenRA.Network
|
||||
|
||||
public bool IsReadyForNextFrame
|
||||
{
|
||||
get
|
||||
{
|
||||
return FrameNumber > 0 &&
|
||||
clientQuitTimes
|
||||
.Where( x => FrameNumber <= x.Value )
|
||||
.All( x => frameClientData.GetOrAdd( FrameNumber ).ContainsKey( x.Key ) );
|
||||
}
|
||||
get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); }
|
||||
}
|
||||
|
||||
public void Tick( World world )
|
||||
public void Tick()
|
||||
{
|
||||
if( !IsReadyForNextFrame )
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Connection.Send( localOrders.Serialize( FrameNumber + FramesAhead ) );
|
||||
Connection.Send( localOrders.Serialize( NetFrameNumber + FramesAhead ) );
|
||||
localOrders.Clear();
|
||||
|
||||
var frameData = clientQuitTimes
|
||||
.Where( x => FrameNumber <= x.Value )
|
||||
.OrderBy( x => x.Key )
|
||||
.ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] );
|
||||
var sync = new List<int>();
|
||||
sync.Add( world.SyncHash() );
|
||||
|
||||
foreach( var order in frameData.SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) )
|
||||
foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) )
|
||||
{
|
||||
UnitOrders.ProcessOrder( world, order.Client, order.Order );
|
||||
UnitOrders.ProcessOrder( this, world, order.Client, order.Order );
|
||||
sync.Add( world.SyncHash() );
|
||||
}
|
||||
|
||||
var ss = sync.SerializeSync( FrameNumber );
|
||||
var ss = sync.SerializeSync( NetFrameNumber );
|
||||
Connection.Send( ss );
|
||||
WriteToReplay( frameData, ss );
|
||||
|
||||
syncReport.UpdateSyncReport();
|
||||
|
||||
CheckSync( ss );
|
||||
|
||||
++FrameNumber;
|
||||
}
|
||||
|
||||
void WriteToReplay( Dictionary<int, byte[]> frameData, byte[] syncData )
|
||||
{
|
||||
if( replaySaveFile == null ) return;
|
||||
|
||||
foreach( var f in frameData )
|
||||
{
|
||||
replaySaveFile.Write( BitConverter.GetBytes( f.Key ) );
|
||||
replaySaveFile.Write( BitConverter.GetBytes( f.Value.Length ) );
|
||||
replaySaveFile.Write( f.Value );
|
||||
}
|
||||
replaySaveFile.Write( BitConverter.GetBytes( (int)0 ) );
|
||||
replaySaveFile.Write( BitConverter.GetBytes( (int)syncData.Length ) );
|
||||
replaySaveFile.Write( syncData );
|
||||
}
|
||||
|
||||
void WriteImmediateToReplay( List<Pair<int, byte[]>> immediatePackets )
|
||||
{
|
||||
if( replaySaveFile == null ) return;
|
||||
|
||||
foreach( var i in immediatePackets )
|
||||
{
|
||||
replaySaveFile.Write( BitConverter.GetBytes( i.First ) );
|
||||
replaySaveFile.Write( BitConverter.GetBytes( i.Second.Length ) );
|
||||
replaySaveFile.Write( i.Second );
|
||||
}
|
||||
++NetFrameNumber;
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
@@ -230,11 +183,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
if (replaySaveFile != null)
|
||||
replaySaveFile.Dispose();
|
||||
|
||||
var disposableConnection = Connection as IDisposable;
|
||||
if (disposableConnection != null) disposableConnection.Dispose();
|
||||
Connection.Dispose();
|
||||
|
||||
disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
100
OpenRA.Game/Network/ReplayConnection.cs
Executable file
100
OpenRA.Game/Network/ReplayConnection.cs
Executable file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class ReplayConnection : IConnection
|
||||
{
|
||||
//uint nextFrame = 1;
|
||||
FileStream replayStream;
|
||||
|
||||
public ReplayConnection( string replayFilename )
|
||||
{
|
||||
replayStream = File.OpenRead( replayFilename );
|
||||
}
|
||||
|
||||
public int LocalClientId
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public ConnectionState ConnectionState
|
||||
{
|
||||
get { return ConnectionState.Connected; }
|
||||
}
|
||||
|
||||
public void Send( byte[] packet )
|
||||
{
|
||||
// do nothing; ignore locally generated orders
|
||||
}
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
if( replayStream == null ) return;
|
||||
|
||||
var reader = new BinaryReader( replayStream );
|
||||
while( replayStream.Position < replayStream.Length )
|
||||
{
|
||||
var client = reader.ReadInt32();
|
||||
var packetLen = reader.ReadInt32();
|
||||
var packet = reader.ReadBytes( packetLen );
|
||||
packetFn( client, packet );
|
||||
}
|
||||
replayStream = null;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
class ReplayRecorderConnection : IConnection
|
||||
{
|
||||
IConnection inner;
|
||||
FileStream replayFile;
|
||||
BinaryWriter writer;
|
||||
|
||||
public ReplayRecorderConnection( IConnection inner, FileStream replayFile )
|
||||
{
|
||||
this.inner = inner;
|
||||
this.replayFile = replayFile;
|
||||
this.writer = new BinaryWriter( replayFile );
|
||||
}
|
||||
|
||||
public int LocalClientId { get { return inner.LocalClientId; } }
|
||||
public ConnectionState ConnectionState { get { return inner.ConnectionState; } }
|
||||
|
||||
public void Send( byte[] packet )
|
||||
{
|
||||
inner.Send( packet );
|
||||
}
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
inner.Receive( ( client, data ) =>
|
||||
{
|
||||
writer.Write( client );
|
||||
writer.Write( data.Length );
|
||||
writer.Write( data );
|
||||
packetFn( client, data );
|
||||
} );
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if( disposed )
|
||||
return;
|
||||
|
||||
writer.Close();
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
~ReplayRecorderConnection()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
@@ -20,6 +21,16 @@ namespace OpenRA.Network
|
||||
public List<Slot> Slots = new List<Slot>();
|
||||
public Global GlobalSettings = new Global();
|
||||
|
||||
public Client ClientWithIndex( int clientID )
|
||||
{
|
||||
return Clients.SingleOrDefault( c => c.Index == clientID );
|
||||
}
|
||||
|
||||
public Client ClientInSlot( Slot slot )
|
||||
{
|
||||
return Clients.SingleOrDefault( c => c.Slot == slot.Index );
|
||||
}
|
||||
|
||||
public enum ClientState
|
||||
{
|
||||
NotReady,
|
||||
@@ -51,6 +62,7 @@ namespace OpenRA.Network
|
||||
|
||||
public class Global
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
@@ -59,6 +71,11 @@ namespace OpenRA.Network
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
public Session( string[] mods )
|
||||
{
|
||||
this.GlobalSettings.Mods = mods.ToArray();
|
||||
}
|
||||
|
||||
public string Serialize()
|
||||
{
|
||||
var clientData = new List<MiniYamlNode>();
|
||||
@@ -76,8 +93,7 @@ namespace OpenRA.Network
|
||||
|
||||
public static Session Deserialize(string data)
|
||||
{
|
||||
var session = new Session();
|
||||
session.GlobalSettings.Mods = Game.Settings.Game.Mods;
|
||||
var session = new Session( Game.Settings.Game.Mods );
|
||||
|
||||
var ys = MiniYaml.FromString(data);
|
||||
foreach (var y in ys)
|
||||
|
||||
@@ -3,61 +3,89 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class SyncReport
|
||||
{
|
||||
Queue<Pair<int, string>> syncReports = new Queue<Pair<int, string>>();
|
||||
readonly OrderManager orderManager;
|
||||
const int numSyncReports = 5;
|
||||
Report[] syncReports = new Report[numSyncReports];
|
||||
int curIndex = 0;
|
||||
|
||||
public SyncReport( OrderManager orderManager )
|
||||
{
|
||||
this.orderManager = orderManager;
|
||||
for (var i = 0; i < numSyncReports; i++)
|
||||
syncReports[i] = new SyncReport.Report();
|
||||
}
|
||||
|
||||
internal void UpdateSyncReport()
|
||||
{
|
||||
if (!Game.Settings.Debug.RecordSyncReports)
|
||||
return;
|
||||
|
||||
while (syncReports.Count >= numSyncReports) syncReports.Dequeue();
|
||||
syncReports.Enqueue(Pair.New(Game.orderManager.FrameNumber, GenerateSyncReport()));
|
||||
|
||||
GenerateSyncReport(syncReports[curIndex]);
|
||||
curIndex = ++curIndex % numSyncReports;
|
||||
}
|
||||
|
||||
string GenerateSyncReport()
|
||||
|
||||
void GenerateSyncReport(Report report)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Actors:");
|
||||
foreach (var a in Game.world.Actors)
|
||||
sb.AppendLine("\t {0} {1} {2} ({3})".F(
|
||||
a.ActorID,
|
||||
a.Info.Name,
|
||||
(a.Owner == null) ? "null" : a.Owner.InternalName,
|
||||
Sync.CalculateSyncHash(a)));
|
||||
|
||||
sb.AppendLine("Tick Actors:");
|
||||
foreach (var a in Game.world.Queries.WithTraitMultiple<object>())
|
||||
report.Frame = orderManager.NetFrameNumber;
|
||||
report.SyncedRandom = orderManager.world.SharedRandom.Last;
|
||||
report.Traits.Clear();
|
||||
foreach (var a in orderManager.world.Queries.WithTraitMultiple<object>())
|
||||
{
|
||||
var sync = Sync.CalculateSyncHash(a.Trait);
|
||||
if (sync != 0)
|
||||
sb.AppendLine("\t {0} {1} {2} {3} ({4})".F(
|
||||
a.Actor.ActorID,
|
||||
a.Actor.Info.Name,
|
||||
(a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
|
||||
a.Trait.GetType().Name,
|
||||
sync));
|
||||
report.Traits.Add(new TraitReport()
|
||||
{
|
||||
ActorID = a.Actor.ActorID,
|
||||
Type = a.Actor.Info.Name,
|
||||
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
|
||||
Trait = a.Trait.GetType().Name,
|
||||
Hash = sync
|
||||
});
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void DumpSyncReport(int frame)
|
||||
{
|
||||
var f = syncReports.FirstOrDefault(a => a.First == frame);
|
||||
if (f == default(Pair<int, string>))
|
||||
{
|
||||
Log.Write("sync", "No sync report available!");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Write("sync", "Sync for net frame {0} -------------", f.First);
|
||||
Log.Write("sync", "{0}", f.Second);
|
||||
foreach (var r in syncReports)
|
||||
if (r.Frame == frame)
|
||||
{
|
||||
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
|
||||
Log.Write("sync", "SharedRandom: "+r.SyncedRandom);
|
||||
Log.Write("sync", "Synced Traits:");
|
||||
foreach (var a in r.Traits)
|
||||
Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(
|
||||
a.ActorID,
|
||||
a.Type,
|
||||
a.Owner,
|
||||
a.Trait,
|
||||
a.Hash
|
||||
));
|
||||
return;
|
||||
}
|
||||
Log.Write("sync", "No sync report available!");
|
||||
}
|
||||
|
||||
class Report
|
||||
{
|
||||
public int Frame;
|
||||
public int SyncedRandom;
|
||||
public List<TraitReport> Traits = new List<TraitReport>();
|
||||
}
|
||||
|
||||
struct TraitReport
|
||||
{
|
||||
public uint ActorID;
|
||||
public string Type;
|
||||
public string Owner;
|
||||
public string Trait;
|
||||
public int Hash;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,16 @@ namespace OpenRA.Network
|
||||
{
|
||||
static class UnitOrders
|
||||
{
|
||||
static Session.Client FindClientById(int id)
|
||||
static Player FindPlayerByClient( this World world, Session.Client c)
|
||||
{
|
||||
return Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == id);
|
||||
/* todo: this is still a hack.
|
||||
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
|
||||
* bots,.. */
|
||||
return world.players.Values.FirstOrDefault(
|
||||
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
|
||||
}
|
||||
|
||||
static Player FindPlayerByClientId(int id)
|
||||
{
|
||||
/* todo: find the interactive player. */
|
||||
return Game.world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
|
||||
}
|
||||
|
||||
public static void ProcessOrder( World world, int clientId, Order order )
|
||||
public static void ProcessOrder( OrderManager orderManager, World world, int clientId, Order order )
|
||||
{
|
||||
// Drop exploiting orders
|
||||
if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId)
|
||||
@@ -40,32 +38,40 @@ namespace OpenRA.Network
|
||||
{
|
||||
case "Chat":
|
||||
{
|
||||
var client = FindClientById(clientId);
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex( clientId );
|
||||
if (client != null)
|
||||
{
|
||||
var player = FindPlayerByClientId(clientId);
|
||||
if (player != null && player.WinState == WinState.Lost)
|
||||
Game.AddChatLine(client.Color1, client.Name + " (Dead)", order.TargetString);
|
||||
else
|
||||
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
|
||||
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
|
||||
}
|
||||
else
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = FindClientById(clientId);
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = FindPlayerByClientId(clientId);
|
||||
var display = (world.GameHasStarted) ?
|
||||
player != null && (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost) :
|
||||
client == Game.LocalClient || (client.Team == Game.LocalClient.Team && client.Team != 0);
|
||||
|
||||
if (display)
|
||||
if (world == null)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
|
||||
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.Color1, client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&& (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
|
||||
if (display)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
|
||||
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -73,25 +79,43 @@ namespace OpenRA.Network
|
||||
case "StartGame":
|
||||
{
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(Game.LobbyInfo.GlobalSettings.Map);
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
|
||||
break;
|
||||
}
|
||||
case "SyncInfo":
|
||||
{
|
||||
Game.SyncLobbyInfo(order.TargetString);
|
||||
orderManager.LobbyInfo = Session.Deserialize( order.TargetString );
|
||||
|
||||
//if( !world.GameHasStarted )
|
||||
// world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
|
||||
|
||||
//if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
|
||||
// world.SetLocalPlayer(orderManager.Connection.LocalClientId);
|
||||
|
||||
if( orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted )
|
||||
{
|
||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Game.Debug( "Order lag is now {0} frames.".F( orderManager.LobbyInfo.GlobalSettings.OrderLatency ) );
|
||||
}
|
||||
|
||||
Game.SyncLobbyInfo();
|
||||
break;
|
||||
}
|
||||
case "SetStance":
|
||||
{
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var oldStance = order.Player.Stances[targetPlayer];
|
||||
order.Player.Stances[targetPlayer] = (Stance)order.TargetLocation.Y;
|
||||
|
||||
if (targetPlayer == world.LocalPlayer)
|
||||
world.WorldActor.Trait<Shroud>().UpdatePlayerStance(world, order.Player, oldStance, order.Player.Stances[targetPlayer]);
|
||||
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy)
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, order.Player.Stances[targetPlayer]));
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -103,5 +127,13 @@ namespace OpenRA.Network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerStance(World w, Player a, Player b, Stance s)
|
||||
{
|
||||
var oldStance = a.Stances[b];
|
||||
a.Stances[b] = s;
|
||||
if (b == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, b, oldStance, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -30,19 +31,63 @@ namespace OpenRA
|
||||
public static Action<string> MissingTypeAction =
|
||||
s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); };
|
||||
|
||||
public T CreateObject<T>(string classname)
|
||||
public T CreateObject<T>(string className)
|
||||
{
|
||||
foreach (var mod in ModAssemblies)
|
||||
{
|
||||
var fullTypeName = mod.Second + "." + classname;
|
||||
var obj = mod.First.CreateInstance(fullTypeName);
|
||||
if (obj != null)
|
||||
return (T)obj;
|
||||
}
|
||||
return CreateObject<T>( className, new Dictionary<string, object>() );
|
||||
}
|
||||
|
||||
MissingTypeAction(classname);
|
||||
public T CreateObject<T>( string className, Dictionary<string, object> args )
|
||||
{
|
||||
foreach( var mod in ModAssemblies )
|
||||
{
|
||||
var type = mod.First.GetType( mod.Second + "." + className, false );
|
||||
if( type == null ) continue;
|
||||
var ctors = type.GetConstructors( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ).Where( x => x.HasAttribute<UseCtorAttribute>() ).ToList();
|
||||
if( ctors.Count == 0 )
|
||||
return (T)CreateBasic( type );
|
||||
else if( ctors.Count == 1 )
|
||||
return (T)CreateUsingArgs( ctors[ 0 ], args );
|
||||
else
|
||||
throw new InvalidOperationException( "ObjectCreator: UseCtor on multiple constructors; invalid." );
|
||||
}
|
||||
MissingTypeAction(className);
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public object CreateBasic( Type type )
|
||||
{
|
||||
return type.GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] );
|
||||
}
|
||||
|
||||
public object CreateUsingArgs( ConstructorInfo ctor, Dictionary<string, object> args )
|
||||
{
|
||||
var p = ctor.GetParameters();
|
||||
var a = new object[ p.Length ];
|
||||
for( int i = 0 ; i < p.Length ; i++ )
|
||||
{
|
||||
var attrs = p[ i ].GetCustomAttributes<ParamAttribute>();
|
||||
if( attrs.Length != 1 ) throw new InvalidOperationException( "ObjectCreator: argument in [UseCtor] doesn't have [Param]" );
|
||||
a[ i ] = args[ attrs[ 0 ].ParamName ?? p[i].Name ];
|
||||
}
|
||||
return ctor.Invoke( a );
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Parameter )]
|
||||
public class ParamAttribute : Attribute
|
||||
{
|
||||
public string ParamName { get; private set; }
|
||||
|
||||
public ParamAttribute() { }
|
||||
|
||||
public ParamAttribute( string paramName )
|
||||
{
|
||||
ParamName = paramName;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Constructor )]
|
||||
public class UseCtorAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -75,7 +75,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Effects\RepairIndicator.cs" />
|
||||
<Compile Include="GameRules\WeaponInfo.cs" />
|
||||
<Compile Include="Group.cs" />
|
||||
<Compile Include="Orders\GenericSelectTarget.cs" />
|
||||
@@ -83,7 +82,6 @@
|
||||
<Compile Include="Traits\BaseBuilding.cs" />
|
||||
<Compile Include="Traits\LintAttributes.cs" />
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="Traits\Player\TechTreeCache.cs" />
|
||||
<Compile Include="Traits\World\Shroud.cs" />
|
||||
<Compile Include="Widgets\ChatEntryWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
|
||||
@@ -99,7 +97,6 @@
|
||||
<Compile Include="Effects\MoveFlash.cs" />
|
||||
<Compile Include="Exts.cs" />
|
||||
<Compile Include="GameRules\ActorInfo.cs" />
|
||||
<Compile Include="GameRules\TechTree.cs" />
|
||||
<Compile Include="GameRules\VoiceInfo.cs" />
|
||||
<Compile Include="Effects\IEffect.cs" />
|
||||
<Compile Include="Graphics\ChromeProvider.cs" />
|
||||
@@ -137,7 +134,6 @@
|
||||
<Compile Include="Traits\Activities\RemoveSelf.cs" />
|
||||
<Compile Include="Traits\Activities\Sell.cs" />
|
||||
<Compile Include="Orders\IOrderGenerator.cs" />
|
||||
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Graphics\Sheet.cs" />
|
||||
<Compile Include="PathFinder.cs" />
|
||||
@@ -157,23 +153,15 @@
|
||||
<Compile Include="Graphics\TerrainRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Move.cs" />
|
||||
<Compile Include="Traits\Activities\Turn.cs" />
|
||||
<Compile Include="Traits\Buildable.cs" />
|
||||
<Compile Include="Traits\Building.cs" />
|
||||
<Compile Include="Traits\World\BuildingInfluence.cs" />
|
||||
<Compile Include="Traits\Player\PlaceBuilding.cs" />
|
||||
<Compile Include="Traits\World\PlayerColorPalette.cs" />
|
||||
<Compile Include="Traits\World\ResourceLayer.cs" />
|
||||
<Compile Include="Traits\World\ResourceType.cs" />
|
||||
<Compile Include="Traits\SupportPower.cs" />
|
||||
<Compile Include="Traits\ProvidesRadar.cs" />
|
||||
<Compile Include="Traits\Selectable.cs" />
|
||||
<Compile Include="Traits\Player\ProductionQueue.cs" />
|
||||
<Compile Include="Traits\Mobile.cs" />
|
||||
<Compile Include="Traits\Production.cs" />
|
||||
<Compile Include="Traits\RallyPoint.cs" />
|
||||
<Compile Include="Traits\Render\RenderSimple.cs" />
|
||||
<Compile Include="Traits\TraitsInterfaces.cs" />
|
||||
<Compile Include="Traits\Turreted.cs" />
|
||||
<Compile Include="Traits\World\UnitInfluence.cs" />
|
||||
<Compile Include="Network\UnitOrders.cs" />
|
||||
<Compile Include="Traits\Util.cs" />
|
||||
@@ -193,8 +181,6 @@
|
||||
<Compile Include="Widgets\BackgroundWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWidget.cs" />
|
||||
<Compile Include="Widgets\CheckboxWidget.cs" />
|
||||
<Compile Include="Traits\World\BibLayer.cs" />
|
||||
<Compile Include="Traits\World\SmudgeLayer.cs" />
|
||||
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
|
||||
<Compile Include="Widgets\PerfGraphWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
|
||||
@@ -202,7 +188,6 @@
|
||||
<Compile Include="Widgets\ColorBlockWidget.cs" />
|
||||
<Compile Include="GameRules\MusicInfo.cs" />
|
||||
<Compile Include="Widgets\ImageWidget.cs" />
|
||||
<Compile Include="Traits\SharesCell.cs" />
|
||||
<Compile Include="Widgets\TextFieldWidget.cs" />
|
||||
<Compile Include="Widgets\ChatDisplayWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
|
||||
@@ -217,16 +202,16 @@
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Targetable.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Traits\RepairableBuilding.cs" />
|
||||
<Compile Include="Traits\Activities\Drag.cs" />
|
||||
<Compile Include="Widgets\VqaPlayerWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
|
||||
<Compile Include="Traits\MPStartLocations.cs" />
|
||||
<Compile Include="GameRules\Settings.cs" />
|
||||
<Compile Include="Support\Arguments.cs" />
|
||||
<Compile Include="Traits\ActorStance.cs" />
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Graphics\CursorProvider.cs" />
|
||||
<Compile Include="Traits\Player\TechTree.cs" />
|
||||
<Compile Include="Traits\Player\PowerManager.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
@@ -237,12 +222,17 @@
|
||||
<Compile Include="ActorReference.cs" />
|
||||
<Compile Include="ModData.cs" />
|
||||
<Compile Include="Map.cs" />
|
||||
<Compile Include="Network\FrameData.cs" />
|
||||
<Compile Include="Network\ReplayConnection.cs" />
|
||||
<Compile Include="Network\Session.cs" />
|
||||
<Compile Include="ObjectCreator.cs" />
|
||||
<Compile Include="Network\SyncReport.cs" />
|
||||
<Compile Include="TraitDictionary.cs" />
|
||||
<Compile Include="Traits\PrimaryBuilding.cs" />
|
||||
<Compile Include="Traits\SharesCell.cs" />
|
||||
<Compile Include="Traits\Valued.cs" />
|
||||
<Compile Include="Traits\World\BibLayer.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
<Compile Include="Widgets\ScrollingTextWidget.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
|
||||
@@ -10,18 +10,27 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
{
|
||||
public class GenericSelectTarget : IOrderGenerator
|
||||
{
|
||||
readonly Actor subject;
|
||||
readonly IEnumerable<Actor> subjects;
|
||||
readonly string order;
|
||||
readonly string cursor;
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
|
||||
{
|
||||
this.subjects = subjects;
|
||||
this.order = order;
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public GenericSelectTarget(Actor subject, string order, string cursor)
|
||||
{
|
||||
this.subject = subject;
|
||||
this.subjects = new Actor[] { subject };
|
||||
this.order = order;
|
||||
this.cursor = cursor;
|
||||
}
|
||||
@@ -36,12 +45,34 @@ namespace OpenRA.Orders
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left && world.Map.IsInMap(xy))
|
||||
yield return new Order(order, subject, xy);
|
||||
{
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in subjects)
|
||||
yield return new Order(order, subject, xy);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Tick(World world) { }
|
||||
public void RenderAfterWorld(World world) { }
|
||||
public void RenderBeforeWorld(World world) { }
|
||||
|
||||
public void RenderBeforeWorld(WorldRenderer wr, World world)
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
|
||||
t.RenderBeforeWorld(wr, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world)
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(wr, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
|
||||
}
|
||||
@@ -63,5 +94,4 @@ namespace OpenRA.Orders
|
||||
world.CancelInputMode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -16,8 +17,8 @@ namespace OpenRA
|
||||
{
|
||||
IEnumerable<Order> Order(World world, int2 xy, MouseInput mi);
|
||||
void Tick(World world);
|
||||
void RenderBeforeWorld(World world);
|
||||
void RenderAfterWorld(World world);
|
||||
void RenderBeforeWorld(WorldRenderer wr, World world);
|
||||
void RenderAfterWorld(WorldRenderer wr, World world);
|
||||
string GetCursor(World world, int2 xy, MouseInput mi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
@@ -25,59 +25,127 @@ namespace OpenRA.Orders
|
||||
.FirstOrDefault();
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => a.Order(xy, mi, underCursor))
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
var actorsInvolved = orders.Select(o => o.Subject).Distinct();
|
||||
var actorsInvolved = orders.Select(o => o.self).Distinct();
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return o;
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
|
||||
|
||||
foreach( var o in orders )
|
||||
yield return CheckSameOrder( o.iot, o.trait.IssueOrder( o.self, o.iot, o.target ) );
|
||||
}
|
||||
|
||||
public void Tick( World world ) {}
|
||||
|
||||
public void RenderBeforeWorld(World world)
|
||||
public void RenderBeforeWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
|
||||
t.RenderBeforeWorld(a);
|
||||
|
||||
t.RenderBeforeWorld( wr, a );
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld( World world )
|
||||
public void RenderAfterWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(a);
|
||||
t.RenderAfterWorld( wr, a );
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
|
||||
{
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
|
||||
.Any();
|
||||
|
||||
if (underCursor)
|
||||
return "select";
|
||||
}
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
var c = Order(world, xy, mi)
|
||||
.Select(o => o.Subject.TraitsImplementing<IOrderCursor>()
|
||||
.Select(pc => pc.CursorForOrder(o.Subject, o)).FirstOrDefault(a => a != null))
|
||||
.FirstOrDefault(a => a != null);
|
||||
|
||||
return c ?? "default";
|
||||
if( mi.Modifiers.HasModifier( Modifiers.Shift ) || !world.Selection.Actors.Any() )
|
||||
if( underCursor != null )
|
||||
return "select";
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
if( orders.Length == 0 ) return "default";
|
||||
|
||||
return orders[ 0 ].cursor ?? "default";
|
||||
}
|
||||
|
||||
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!self.World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (self.Destroyed)
|
||||
return null;
|
||||
|
||||
//var old = self.TraitsImplementing<IIssueOrder>()
|
||||
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
|
||||
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
|
||||
// .FirstOrDefault( x => x != null );
|
||||
//if( old != null )
|
||||
// return old;
|
||||
|
||||
if( mi.Button == MouseButton.Right )
|
||||
{
|
||||
var uim = self.World.WorldActor.Trait<UnitInfluence>();
|
||||
foreach( var o in self.TraitsImplementing<IIssueOrder>()
|
||||
.SelectMany( trait => trait.Orders
|
||||
.Select( x => new { Trait = trait, Order = x } ) )
|
||||
.OrderByDescending( x => x.Order.OrderPriority ) )
|
||||
{
|
||||
var actorsAt = uim.GetUnitsAt( xy ).ToList();
|
||||
|
||||
string cursor = null;
|
||||
if( underCursor != null )
|
||||
if( o.Order.CanTargetUnit( self, underCursor, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
|
||||
if( o.Order.CanTargetLocation( self, xy, actorsAt, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Order CheckSameOrder( IOrderTargeter iot, Order order )
|
||||
{
|
||||
if( order == null && iot.OrderID != null )
|
||||
Game.Debug( "BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID );
|
||||
else if( iot.OrderID != order.OrderString )
|
||||
Game.Debug( "BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString );
|
||||
return order;
|
||||
}
|
||||
|
||||
class UnitOrderResult
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly IOrderTargeter iot;
|
||||
public readonly IIssueOrder trait;
|
||||
public readonly string cursor;
|
||||
public readonly Target target;
|
||||
|
||||
public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target )
|
||||
{
|
||||
this.self = self;
|
||||
this.iot = iot;
|
||||
this.trait = trait;
|
||||
this.cursor = cursor;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,11 +207,11 @@ namespace OpenRA
|
||||
|
||||
public struct CellInfo
|
||||
{
|
||||
public float MinCost;
|
||||
public int MinCost;
|
||||
public int2 Path;
|
||||
public bool Seen;
|
||||
|
||||
public CellInfo( float minCost, int2 path, bool seen )
|
||||
public CellInfo( int minCost, int2 path, bool seen )
|
||||
{
|
||||
MinCost = minCost;
|
||||
Path = path;
|
||||
@@ -221,10 +221,10 @@ namespace OpenRA
|
||||
|
||||
public struct PathDistance : IComparable<PathDistance>
|
||||
{
|
||||
public float EstTotal;
|
||||
public int EstTotal;
|
||||
public int2 Location;
|
||||
|
||||
public PathDistance(float estTotal, int2 location)
|
||||
public PathDistance(int estTotal, int2 location)
|
||||
{
|
||||
EstTotal = estTotal;
|
||||
Location = location;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA
|
||||
World world;
|
||||
public CellInfo[ , ] cellInfo;
|
||||
public PriorityQueue<PathDistance> queue;
|
||||
public Func<int2, float> heuristic;
|
||||
public Func<int2, int> heuristic;
|
||||
Func<int2, bool> customBlock;
|
||||
public bool checkForBlocked;
|
||||
public Actor ignoreBuilding;
|
||||
@@ -58,7 +58,7 @@ namespace OpenRA
|
||||
return this;
|
||||
}
|
||||
|
||||
public PathSearch WithHeuristic(Func<int2, float> h)
|
||||
public PathSearch WithHeuristic(Func<int2, int> h)
|
||||
{
|
||||
heuristic = h;
|
||||
return this;
|
||||
@@ -66,7 +66,7 @@ namespace OpenRA
|
||||
|
||||
public PathSearch WithoutLaneBias()
|
||||
{
|
||||
LaneBias = 0f;
|
||||
LaneBias = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace OpenRA
|
||||
return this;
|
||||
}
|
||||
|
||||
float LaneBias = .5f;
|
||||
int LaneBias = 1;
|
||||
|
||||
public int2 Expand( World world )
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA
|
||||
|
||||
var thisCost = Mobile.MovementCostForCell(mobileInfo, world, p.Location);
|
||||
|
||||
if (thisCost == float.PositiveInfinity)
|
||||
if (thisCost == int.MaxValue)
|
||||
return p.Location;
|
||||
|
||||
foreach( int2 d in directions )
|
||||
@@ -104,7 +104,7 @@ namespace OpenRA
|
||||
|
||||
var costHere = Mobile.MovementCostForCell(mobileInfo, world, newHere);
|
||||
|
||||
if (costHere == float.PositiveInfinity)
|
||||
if (costHere == int.MaxValue)
|
||||
continue;
|
||||
|
||||
if (!Mobile.CanEnterCell(mobileInfo, world, uim, bim, newHere, ignoreBuilding, checkForBlocked))
|
||||
@@ -114,10 +114,11 @@ namespace OpenRA
|
||||
continue;
|
||||
|
||||
var est = heuristic( newHere );
|
||||
if( est == float.PositiveInfinity )
|
||||
if( est == int.MaxValue )
|
||||
continue;
|
||||
|
||||
float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * costHere;
|
||||
int cellCost = costHere;
|
||||
if( d.X * d.Y != 0 ) cellCost = ( cellCost * 34 ) / 24;
|
||||
|
||||
// directional bonuses for smoother flow!
|
||||
var ux = (newHere.X + (inReverse ? 1 : 0) & 1);
|
||||
@@ -128,7 +129,7 @@ namespace OpenRA
|
||||
if (uy == 0 && d.X < 0) cellCost += LaneBias;
|
||||
else if (uy == 1 && d.X > 0) cellCost += LaneBias;
|
||||
|
||||
float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
|
||||
int newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
|
||||
|
||||
if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost )
|
||||
continue;
|
||||
@@ -199,18 +200,18 @@ namespace OpenRA
|
||||
var cellInfo = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ];
|
||||
for( int x = 0 ; x < world.Map.MapSize.X ; x++ )
|
||||
for( int y = 0 ; y < world.Map.MapSize.Y ; y++ )
|
||||
cellInfo[ x, y ] = new CellInfo( float.PositiveInfinity, new int2( x, y ), false );
|
||||
cellInfo[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false );
|
||||
return cellInfo;
|
||||
}
|
||||
|
||||
public static Func<int2, float> DefaultEstimator( int2 destination )
|
||||
public static Func<int2, int> DefaultEstimator( int2 destination )
|
||||
{
|
||||
return here =>
|
||||
{
|
||||
int2 d = ( here - destination ).Abs();
|
||||
int diag = Math.Min( d.X, d.Y );
|
||||
int straight = Math.Abs( d.X - d.Y );
|
||||
return 1.5f * diag + straight;
|
||||
return (3400 * diag / 24) + (100 * straight);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace OpenRA
|
||||
public readonly int Index;
|
||||
public readonly bool NonCombatant = false;
|
||||
public readonly int ClientIndex;
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public World World { get; private set; }
|
||||
@@ -46,11 +47,10 @@ namespace OpenRA
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
|
||||
Index = index;
|
||||
Palette = "player"+index;
|
||||
|
||||
Color = pr.Color;
|
||||
Color2 = pr.Color2;
|
||||
ClientIndex = 0; /* it's a map player, "owned" by host */
|
||||
@@ -63,15 +63,13 @@ namespace OpenRA
|
||||
|
||||
PlayerRef = pr;
|
||||
|
||||
RegisterPlayerColor(world, Palette);
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
}
|
||||
|
||||
public Player( World world, Session.Client client, PlayerReference pr, int index )
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
|
||||
Index = index;
|
||||
Palette = "player"+index;
|
||||
@@ -86,15 +84,7 @@ namespace OpenRA
|
||||
ClientIndex = client.Index;
|
||||
PlayerRef = pr;
|
||||
|
||||
RegisterPlayerColor(world, Palette);
|
||||
}
|
||||
|
||||
public void RegisterPlayerColor(World world, string palette)
|
||||
{
|
||||
var info = Rules.Info["world"].Traits.Get<PlayerColorPaletteInfo>();
|
||||
var newpal = new Palette(world.WorldRenderer.GetPalette(info.BasePalette),
|
||||
new PlayerColorRemap(Color, Color2, info.SplitRamp));
|
||||
world.WorldRenderer.AddPalette(palette, newpal);
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
}
|
||||
|
||||
public void GiveAdvice(string advice)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA
|
||||
else
|
||||
actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList();
|
||||
|
||||
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.HasVoice());
|
||||
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoice());
|
||||
if (voicedUnit != null)
|
||||
Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race);
|
||||
|
||||
@@ -56,6 +56,10 @@ namespace OpenRA
|
||||
public void Tick(World world)
|
||||
{
|
||||
actors.RemoveAll(a => !a.IsInWorld);
|
||||
|
||||
foreach (var cg in controlGroups.Values)
|
||||
cg.RemoveAll(a => a.Destroyed); // note: NOT `!a.IsInWorld`, since that would remove things
|
||||
// that are in transports.
|
||||
}
|
||||
|
||||
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
|
||||
|
||||
1
OpenRA.Game/Server/Exts.cs
Normal file → Executable file
1
OpenRA.Game/Server/Exts.cs
Normal file → Executable file
@@ -11,6 +11,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
|
||||
60
OpenRA.Game/Server/MasterServerQuery.cs
Normal file → Executable file
60
OpenRA.Game/Server/MasterServerQuery.cs
Normal file → Executable file
@@ -14,15 +14,20 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
static class MasterServerQuery
|
||||
{
|
||||
public static event Action<GameServer[]> OnComplete = _ => { };
|
||||
public static event Action<string> OnVersion = _ => { };
|
||||
|
||||
static GameServer[] Games = { };
|
||||
public static string ClientVersion = "";
|
||||
public static string ServerVersion = "";
|
||||
static AutoResetEvent ev = new AutoResetEvent(false);
|
||||
static AutoResetEvent ev2 = new AutoResetEvent(false);
|
||||
|
||||
public static void Refresh(string masterServerUrl)
|
||||
{
|
||||
@@ -30,9 +35,7 @@ namespace OpenRA.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
var wc = new WebClient();
|
||||
var data = wc.DownloadData(new Uri(masterServerUrl + "list.php"));
|
||||
var str = Encoding.UTF8.GetString(data);
|
||||
var str = GetData(new Uri(masterServerUrl + "list.php"));
|
||||
|
||||
var yaml = MiniYaml.FromString(str);
|
||||
|
||||
@@ -48,10 +51,61 @@ namespace OpenRA.Server
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public static void GetMOTD(string masterServerUrl)
|
||||
{
|
||||
var motd = Widget.RootWidget.GetWidget<ScrollingTextWidget>("MOTD_SCROLLER");
|
||||
|
||||
// Runs in a separate thread to prevent dns lookup hitches
|
||||
new Thread(() =>
|
||||
{
|
||||
if (motd != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
motd.SetText(GetData(new Uri(masterServerUrl + "motd.php?v=" + ClientVersion)));
|
||||
motd.ResetScroll();
|
||||
}
|
||||
catch
|
||||
{
|
||||
motd.SetText("Welcome to OpenRA. MOTD unable to be loaded from server.");
|
||||
motd.ResetScroll();
|
||||
}
|
||||
}
|
||||
|
||||
ev.Set();
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public static void Tick()
|
||||
{
|
||||
if (ev.WaitOne(TimeSpan.FromMilliseconds(0)))
|
||||
OnComplete(Games);
|
||||
if (ev2.WaitOne(TimeSpan.FromMilliseconds(0)))
|
||||
OnVersion(ServerVersion);
|
||||
}
|
||||
|
||||
static string GetData(Uri uri)
|
||||
{
|
||||
var wc = new WebClient();
|
||||
var data = wc.DownloadData(uri);
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public static void GetCurrentVersion(string masterServerUrl)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerVersion = GetData(new Uri(masterServerUrl + "VERSION"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
ServerVersion = "";
|
||||
}
|
||||
|
||||
ev2.Set();
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,11 +60,11 @@ namespace OpenRA.Server
|
||||
randomSeed = (int)DateTime.Now.ToBinary();
|
||||
ModData = modData;
|
||||
|
||||
lobbyInfo = new Session();
|
||||
lobbyInfo.GlobalSettings.Mods = settings.Game.Mods;
|
||||
lobbyInfo = new Session( settings.Game.Mods );
|
||||
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
|
||||
lobbyInfo.GlobalSettings.Map = map;
|
||||
lobbyInfo.GlobalSettings.AllowCheats = settings.Server.AllowCheats;
|
||||
lobbyInfo.GlobalSettings.ServerName = settings.Server.Name;
|
||||
|
||||
LoadMap(); // populates the Session's slots, too.
|
||||
|
||||
@@ -164,7 +164,8 @@ namespace OpenRA.Server
|
||||
|
||||
static int ChooseFreeSlot()
|
||||
{
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null).Index;
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null
|
||||
&& !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index;
|
||||
}
|
||||
|
||||
static void AcceptConnection()
|
||||
@@ -588,8 +589,9 @@ namespace OpenRA.Server
|
||||
|
||||
static void SyncLobbyInfo()
|
||||
{
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
|
||||
PingMasterServer();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -128,7 +127,7 @@ namespace OpenRA
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
internal void Draw()
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (disabled)
|
||||
return;
|
||||
@@ -145,71 +144,45 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
var clipRect = Bounds.HasValue ? Rectangle.Intersect(Bounds.Value, map.Bounds) : map.Bounds;
|
||||
|
||||
clipRect = Rectangle.Intersect(Game.viewport.ViewBounds(), clipRect);
|
||||
var miny = clipRect.Top;
|
||||
var maxy = clipRect.Bottom;
|
||||
var minx = clipRect.Left;
|
||||
var maxx = clipRect.Right;
|
||||
|
||||
var shroudPalette = "fog";
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, fogSprites, "fog" );
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, sprites, "shroud" );
|
||||
}
|
||||
|
||||
void DrawShroud( WorldRenderer wr, int minx, int miny, int maxx, int maxy, Sprite[,] s, string pal )
|
||||
{
|
||||
var shroudPalette = wr.GetPaletteIndex(pal);
|
||||
|
||||
for (var j = miny; j < maxy; j++)
|
||||
{
|
||||
var starti = minx;
|
||||
for (var i = minx; i < maxx; i++)
|
||||
{
|
||||
if (fogSprites[i, j] == shadowBits[0x0f])
|
||||
if (s[i, j] == shadowBits[0x0f])
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[starti, j],
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i+1;
|
||||
}
|
||||
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[i, j],
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i+1;
|
||||
}
|
||||
|
||||
if (starti < maxx)
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[starti, j],
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
|
||||
}
|
||||
|
||||
shroudPalette = "shroud";
|
||||
|
||||
for (var j = miny; j < maxy; j++)
|
||||
{
|
||||
var starti = minx;
|
||||
for (var i = minx; i < maxx; i++)
|
||||
{
|
||||
if (sprites[i, j] == shadowBits[0x0f])
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sprites[starti, j],
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sprites[i, j],
|
||||
s[i, j].DrawAt(
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
if (starti < maxx)
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sprites[starti, j],
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
|
||||
|
||||
@@ -129,5 +129,36 @@ namespace OpenRA
|
||||
return p.Index * 0x567;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void CheckSyncUnchanged( World world, Action fn )
|
||||
{
|
||||
CheckSyncUnchanged( world, () => { fn(); return true; } );
|
||||
}
|
||||
|
||||
static bool inUnsyncedCode = false;
|
||||
|
||||
public static T CheckSyncUnchanged<T>( World world, Func<T> fn )
|
||||
{
|
||||
if( world == null ) return fn();
|
||||
int sync = world.SyncHash();
|
||||
bool prevInUnsyncedCode = inUnsyncedCode;
|
||||
inUnsyncedCode = true;
|
||||
try
|
||||
{
|
||||
return fn();
|
||||
}
|
||||
finally
|
||||
{
|
||||
inUnsyncedCode = prevInUnsyncedCode;
|
||||
if( sync != world.SyncHash() )
|
||||
throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" );
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertUnsynced( string message )
|
||||
{
|
||||
if( !inUnsyncedCode )
|
||||
throw new InvalidOperationException( message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Traits;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Drag : IActivity
|
||||
{
|
||||
public IActivity NextActivity { get; set; }
|
||||
IActivity NextActivity { get; set; }
|
||||
|
||||
float2 endLocation;
|
||||
float2 startLocation;
|
||||
int2 endLocation;
|
||||
int2 startLocation;
|
||||
int length;
|
||||
|
||||
public Drag(float2 start, float2 end, int length)
|
||||
public Drag(int2 start, int2 end, int length)
|
||||
{
|
||||
startLocation = start;
|
||||
endLocation = end;
|
||||
@@ -29,15 +29,32 @@ namespace OpenRA.Traits.Activities
|
||||
|
||||
int ticks = 0;
|
||||
public IActivity Tick( Actor self )
|
||||
{
|
||||
self.CenterLocation = float2.Lerp(startLocation, endLocation, (float)ticks/(length-1));
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
mobile.PxPosition = int2.Lerp(startLocation, endLocation, ticks, length - 1);
|
||||
|
||||
if (++ticks >= length)
|
||||
return NextActivity;
|
||||
|
||||
{
|
||||
mobile.IsMoving = false;
|
||||
return NextActivity;
|
||||
}
|
||||
mobile.IsMoving = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Cancel(Actor self) { }
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield return endLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
class Idle : IActivity
|
||||
public class Idle : CancelableActivity
|
||||
{
|
||||
public IActivity NextActivity { get; set; }
|
||||
|
||||
public IActivity Tick(Actor self) { return NextActivity; }
|
||||
public void Cancel(Actor self) {}
|
||||
public override IActivity Tick(Actor self) { return NextActivity; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,33 +15,17 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Move : IActivity
|
||||
public class Move : CancelableActivity
|
||||
{
|
||||
public IActivity NextActivity { get; set; }
|
||||
|
||||
int2? destination;
|
||||
int nearEnough;
|
||||
public List<int2> path;
|
||||
Func<Actor, Mobile, List<int2>> getPath;
|
||||
public Actor ignoreBuilding;
|
||||
bool cancellable = true;
|
||||
|
||||
MovePart move;
|
||||
int ticksBeforePathing;
|
||||
|
||||
const int avgTicksBeforePathing = 5;
|
||||
const int spreadTicksBeforePathing = 5;
|
||||
|
||||
Move()
|
||||
{
|
||||
ticksBeforePathing = avgTicksBeforePathing +
|
||||
Game.world.SharedRandom.Next(-spreadTicksBeforePathing, spreadTicksBeforePathing);
|
||||
}
|
||||
|
||||
// Scriptable move order
|
||||
// Ignores lane bias and nearby units
|
||||
public Move( int2 destination )
|
||||
: this()
|
||||
public Move( int2 destination )
|
||||
{
|
||||
this.getPath = (self,mobile) =>
|
||||
self.World.PathFinder.FindPath(
|
||||
@@ -49,11 +33,9 @@ namespace OpenRA.Traits.Activities
|
||||
.WithoutLaneBias());
|
||||
this.destination = destination;
|
||||
this.nearEnough = 0;
|
||||
this.cancellable = false;
|
||||
}
|
||||
|
||||
public Move( int2 destination, int nearEnough )
|
||||
: this()
|
||||
{
|
||||
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPath( mobile.toCell, destination, self );
|
||||
this.destination = destination;
|
||||
@@ -61,7 +43,6 @@ namespace OpenRA.Traits.Activities
|
||||
}
|
||||
|
||||
public Move(int2 destination, Actor ignoreBuilding)
|
||||
: this()
|
||||
{
|
||||
this.getPath = (self,mobile) =>
|
||||
self.World.PathFinder.FindPath(
|
||||
@@ -75,7 +56,6 @@ namespace OpenRA.Traits.Activities
|
||||
}
|
||||
|
||||
public Move( Actor target, int range )
|
||||
: this()
|
||||
{
|
||||
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
|
||||
mobile.toCell, target.Location,
|
||||
@@ -85,7 +65,6 @@ namespace OpenRA.Traits.Activities
|
||||
}
|
||||
|
||||
public Move(Target target, int range)
|
||||
: this()
|
||||
{
|
||||
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
|
||||
mobile.toCell, Util.CellContaining(target.CenterLocation),
|
||||
@@ -95,35 +74,47 @@ namespace OpenRA.Traits.Activities
|
||||
}
|
||||
|
||||
public Move(Func<List<int2>> getPath)
|
||||
: this()
|
||||
{
|
||||
this.getPath = (_1,_2) => getPath();
|
||||
this.destination = null;
|
||||
this.nearEnough = 0;
|
||||
}
|
||||
|
||||
public IActivity Tick( Actor self )
|
||||
static int HashList<T>(List<T> xs)
|
||||
{
|
||||
int hash = 0;
|
||||
int n = 0;
|
||||
foreach (var x in xs)
|
||||
hash += n++ * x.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
List<int2> EvalPath( Actor self, Mobile mobile )
|
||||
{
|
||||
var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList();
|
||||
mobile.PathHash = HashList(path);
|
||||
Log.Write("debug", "EvalPathHash #{0} {1}",
|
||||
self.ActorID, mobile.PathHash);
|
||||
return path;
|
||||
}
|
||||
|
||||
public override IActivity Tick( Actor self )
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
|
||||
if( move != null )
|
||||
{
|
||||
move.TickMove( self, mobile, this );
|
||||
return this;
|
||||
}
|
||||
|
||||
if (destination == mobile.toCell)
|
||||
return NextActivity;
|
||||
|
||||
if( path == null )
|
||||
{
|
||||
if (ticksBeforePathing > 0)
|
||||
if (mobile.ticksBeforePathing > 0)
|
||||
{
|
||||
--ticksBeforePathing;
|
||||
--mobile.ticksBeforePathing;
|
||||
return this;
|
||||
}
|
||||
|
||||
path = getPath( self, mobile ).TakeWhile( a => a != mobile.toCell ).ToList();
|
||||
path = EvalPath(self, mobile);
|
||||
SanityCheckPath( mobile );
|
||||
}
|
||||
|
||||
@@ -144,22 +135,20 @@ namespace OpenRA.Traits.Activities
|
||||
if( firstFacing != mobile.Facing )
|
||||
{
|
||||
path.Add( nextCell.Value );
|
||||
|
||||
return new Turn( firstFacing ) { NextActivity = this };
|
||||
return Util.SequenceActivities( new Turn( firstFacing ), this ).Tick( self );
|
||||
}
|
||||
else
|
||||
{
|
||||
mobile.toCell = nextCell.Value;
|
||||
move = new MoveFirstHalf(
|
||||
mobile.SetLocation( mobile.fromCell, nextCell.Value );
|
||||
var move = new MoveFirstHalf(
|
||||
this,
|
||||
Util.CenterOfCell( mobile.fromCell ),
|
||||
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
0 );
|
||||
|
||||
move.TickMove( self, mobile, this );
|
||||
|
||||
return this;
|
||||
return move.Tick( self );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +171,9 @@ namespace OpenRA.Traits.Activities
|
||||
var blocker = self.World.WorldActor.Trait<UnitInfluence>().GetUnitsAt(nextCell).FirstOrDefault();
|
||||
if (blocker == null) return;
|
||||
|
||||
Log.Write("debug", "NudgeBlocker #{0} nudges #{1} at {2} from {3}",
|
||||
self.ActorID, blocker.ActorID, nextCell, self.Location);
|
||||
|
||||
var nudge = blocker.TraitOrDefault<INudge>();
|
||||
if (nudge != null)
|
||||
nudge.OnNudge(blocker, self);
|
||||
@@ -215,8 +207,14 @@ namespace OpenRA.Traits.Activities
|
||||
if (--waitTicksRemaining >= 0)
|
||||
return null;
|
||||
|
||||
if (mobile.ticksBeforePathing > 0)
|
||||
{
|
||||
--mobile.ticksBeforePathing;
|
||||
return null;
|
||||
}
|
||||
|
||||
mobile.RemoveInfluence();
|
||||
var newPath = getPath( self, mobile ).TakeWhile(a => a != mobile.toCell).ToList();
|
||||
var newPath = EvalPath(self, mobile);
|
||||
mobile.AddInfluence();
|
||||
|
||||
if (newPath.Count != 0)
|
||||
@@ -230,64 +228,98 @@ namespace OpenRA.Traits.Activities
|
||||
return nextCell;
|
||||
}
|
||||
|
||||
public void Cancel( Actor self )
|
||||
protected override bool OnCancel()
|
||||
{
|
||||
if (!cancellable) return;
|
||||
|
||||
path = new List<int2>();
|
||||
NextActivity = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract class MovePart
|
||||
public override IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
public readonly float2 from, to;
|
||||
if( path != null )
|
||||
return Enumerable.Reverse(path).Select( c => (float2)Util.CenterOfCell(c) );
|
||||
if( destination != null )
|
||||
return new float2[] { destination.Value };
|
||||
return new float2[ 0 ];
|
||||
}
|
||||
|
||||
abstract class MovePart : IActivity
|
||||
{
|
||||
public readonly Move move;
|
||||
public readonly int2 from, to;
|
||||
public readonly int fromFacing, toFacing;
|
||||
public int moveFraction;
|
||||
public readonly int moveFractionTotal;
|
||||
|
||||
public MovePart( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
public MovePart( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
{
|
||||
this.move = move;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.fromFacing = fromFacing;
|
||||
this.toFacing = toFacing;
|
||||
this.moveFraction = startingFraction;
|
||||
this.moveFractionTotal = (int)(( to - from ).Length*3);
|
||||
this.moveFractionTotal = ( ( to - from ) * 3 ).Length;
|
||||
}
|
||||
|
||||
public void TickMove( Actor self, Mobile mobile, Move parent )
|
||||
public void Cancel( Actor self )
|
||||
{
|
||||
moveFraction += (int)mobile.MovementSpeedForCell(self, mobile.toCell);
|
||||
if( moveFraction >= moveFractionTotal )
|
||||
move.Cancel( self );
|
||||
}
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
move.Queue( activity );
|
||||
}
|
||||
|
||||
public IActivity Tick( Actor self )
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var ret = InnerTick( self, mobile );
|
||||
mobile.IsMoving = ( ret is MovePart );
|
||||
|
||||
if( moveFraction > moveFractionTotal )
|
||||
moveFraction = moveFractionTotal;
|
||||
UpdateCenterLocation( self, mobile );
|
||||
if( moveFraction >= moveFractionTotal )
|
||||
{
|
||||
parent.move = OnComplete( self, mobile, parent );
|
||||
if( parent.move == null )
|
||||
UpdateCenterLocation( self, mobile );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IActivity InnerTick( Actor self, Mobile mobile )
|
||||
{
|
||||
moveFraction += (int)mobile.MovementSpeedForCell(self, mobile.toCell);
|
||||
if( moveFraction <= moveFractionTotal )
|
||||
return this;
|
||||
|
||||
var next = OnComplete( self, mobile, move );
|
||||
if( next != null )
|
||||
return next;
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
void UpdateCenterLocation( Actor self, Mobile mobile )
|
||||
{
|
||||
var frac = (float)moveFraction / moveFractionTotal;
|
||||
|
||||
self.CenterLocation = float2.Lerp( from, to, frac );
|
||||
mobile.PxPosition = int2.Lerp( from, to, moveFraction, moveFractionTotal );
|
||||
|
||||
if( moveFraction >= moveFractionTotal )
|
||||
mobile.Facing = toFacing & 0xFF;
|
||||
else
|
||||
mobile.Facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
|
||||
mobile.Facing = int2.Lerp( fromFacing, toFacing, moveFraction, moveFractionTotal ) & 0xFF;
|
||||
}
|
||||
|
||||
protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent );
|
||||
|
||||
public IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
return move.GetCurrentPath();
|
||||
}
|
||||
}
|
||||
|
||||
class MoveFirstHalf : MovePart
|
||||
{
|
||||
public MoveFirstHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
: base( from, to, fromFacing, toFacing, startingFraction )
|
||||
public MoveFirstHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
: base( move, from, to, fromFacing, toFacing, startingFraction )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -299,40 +331,41 @@ namespace OpenRA.Traits.Activities
|
||||
if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) )
|
||||
{
|
||||
var ret = new MoveFirstHalf(
|
||||
move,
|
||||
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
|
||||
Util.BetweenCells( mobile.toCell, nextCell.Value ),
|
||||
mobile.Facing,
|
||||
Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value - mobile.toCell, mobile.Facing ) ),
|
||||
moveFraction - moveFractionTotal );
|
||||
mobile.fromCell = mobile.toCell;
|
||||
mobile.toCell = nextCell.Value;
|
||||
mobile.SetLocation( mobile.toCell, nextCell.Value );
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
parent.path.Add( nextCell.Value );
|
||||
}
|
||||
var ret2 = new MoveSecondHalf(
|
||||
move,
|
||||
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
|
||||
Util.CenterOfCell( mobile.toCell ),
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
moveFraction - moveFractionTotal );
|
||||
mobile.fromCell = mobile.toCell;
|
||||
mobile.SetLocation( mobile.toCell, mobile.toCell );
|
||||
return ret2;
|
||||
}
|
||||
}
|
||||
|
||||
class MoveSecondHalf : MovePart
|
||||
{
|
||||
public MoveSecondHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
: base( from, to, fromFacing, toFacing, startingFraction )
|
||||
public MoveSecondHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
|
||||
: base( move, from, to, fromFacing, toFacing, startingFraction )
|
||||
{
|
||||
}
|
||||
|
||||
protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent )
|
||||
{
|
||||
self.CenterLocation = Util.CenterOfCell( mobile.toCell );
|
||||
mobile.fromCell = mobile.toCell;
|
||||
mobile.PxPosition = Util.CenterOfCell( mobile.toCell );
|
||||
mobile.SetLocation( mobile.toCell, mobile.toCell );
|
||||
mobile.FinishedMoving(self);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -10,18 +10,13 @@
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class RemoveSelf : IActivity
|
||||
public class RemoveSelf : CancelableActivity
|
||||
{
|
||||
bool isCanceled;
|
||||
public IActivity NextActivity { get; set; }
|
||||
|
||||
public IActivity Tick(Actor self)
|
||||
public override IActivity Tick(Actor self)
|
||||
{
|
||||
if (isCanceled) return NextActivity;
|
||||
if (IsCanceled) return NextActivity;
|
||||
self.Destroy();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
class Sell : IActivity
|
||||
{
|
||||
public IActivity NextActivity { get; set; }
|
||||
IActivity NextActivity { get; set; }
|
||||
|
||||
bool started;
|
||||
|
||||
@@ -55,5 +57,18 @@ namespace OpenRA.Traits.Activities
|
||||
}
|
||||
|
||||
public void Cancel(Actor self) { /* never gonna give you up.. */ }
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,8 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Turn : IActivity
|
||||
public class Turn : CancelableActivity
|
||||
{
|
||||
public IActivity NextActivity { get; set; }
|
||||
int desiredFacing;
|
||||
|
||||
public Turn( int desiredFacing )
|
||||
@@ -22,8 +21,9 @@ namespace OpenRA.Traits.Activities
|
||||
this.desiredFacing = desiredFacing;
|
||||
}
|
||||
|
||||
public IActivity Tick( Actor self )
|
||||
public override IActivity Tick( Actor self )
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
var facing = self.Trait<IFacing>();
|
||||
|
||||
if( desiredFacing == facing.Facing )
|
||||
@@ -32,11 +32,5 @@ namespace OpenRA.Traits.Activities
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Cancel( Actor self )
|
||||
{
|
||||
desiredFacing = self.Trait<IFacing>().Facing;
|
||||
NextActivity = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,46 +38,41 @@ namespace OpenRA.Traits
|
||||
public object Create(ActorInitializer init) { return new Building(init); }
|
||||
}
|
||||
|
||||
public class Building : INotifyDamage, IResolveOrder, IRenderModifier, IOccupySpace
|
||||
public class Building : INotifyDamage, IResolveOrder, IOccupySpace
|
||||
{
|
||||
readonly Actor self;
|
||||
public readonly BuildingInfo Info;
|
||||
[Sync]
|
||||
readonly int2 topLeft;
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return self.TraitsImplementing<IDisable>().Any(t => t.Disabled); }
|
||||
}
|
||||
readonly PowerManager PlayerPower;
|
||||
|
||||
public int2 PxPosition { get { return ( 2 * topLeft + Info.Dimensions ) * Game.CellSize / 2; } }
|
||||
|
||||
public Building(ActorInitializer init)
|
||||
{
|
||||
this.self = init.self;
|
||||
this.topLeft = init.Get<LocationInit,int2>();
|
||||
Info = self.Info.Traits.Get<BuildingInfo>();
|
||||
self.CenterLocation = Game.CellSize
|
||||
* ((float2)topLeft + .5f * (float2)Info.Dimensions);
|
||||
|
||||
PlayerPower = init.self.Owner.PlayerActor.Trait<PowerManager>();
|
||||
}
|
||||
|
||||
public int GetPowerUsage()
|
||||
{
|
||||
var modifier = self
|
||||
.TraitsImplementing<IPowerModifier>()
|
||||
.Select(t => t.GetPowerModifier())
|
||||
.Product();
|
||||
if (Info.Power <= 0)
|
||||
return Info.Power;
|
||||
|
||||
if (Info.Power > 0)
|
||||
{
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
var healthFraction = (health == null) ? 1f : health.HPFraction;
|
||||
return (int)(modifier * healthFraction * Info.Power);
|
||||
}
|
||||
else
|
||||
return (int)(modifier * Info.Power);
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
return health != null ? (Info.Power * health.HP / health.MaxHP) : Info.Power;
|
||||
}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
// Power plants lose power with damage
|
||||
if (Info.Power > 0)
|
||||
PlayerPower.UpdateActor(self, GetPowerUsage());
|
||||
|
||||
if (e.DamageState == DamageState.Dead)
|
||||
{
|
||||
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
|
||||
@@ -94,16 +89,6 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
foreach (var a in r)
|
||||
{
|
||||
yield return a;
|
||||
if (Disabled)
|
||||
yield return a.WithPalette("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
public int2 TopLeft
|
||||
{
|
||||
get { return topLeft; }
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.Traits
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(Actor self)
|
||||
public void RenderAfterWorld(WorldRenderer wr, Actor self)
|
||||
{
|
||||
if (self.IsIdle) return;
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace OpenRA.Traits
|
||||
if ((lifetime <= 0 || --lifetime <= 0) && !force)
|
||||
return;
|
||||
|
||||
if (!target.IsValid)
|
||||
return;
|
||||
|
||||
var p = target.CenterLocation;
|
||||
|
||||
Game.Renderer.LineRenderer.DrawLine(self.CenterLocation, p, c, c);
|
||||
|
||||
6
OpenRA.Game/Traits/Health.cs
Normal file → Executable file
6
OpenRA.Game/Traits/Health.cs
Normal file → Executable file
@@ -140,6 +140,8 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public static bool IsDead(this Actor self)
|
||||
{
|
||||
if (self.Destroyed) return true;
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
return (health == null) ? true : health.IsDead;
|
||||
}
|
||||
@@ -161,7 +163,9 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (health == null) return;
|
||||
health.InflictDamage(self, attacker, health.HP, null);
|
||||
|
||||
/* hack. Fix for proper */
|
||||
health.InflictDamage(self, attacker, int.MaxValue, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Diagnostics;
|
||||
using OpenRA.Orders;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -38,7 +40,7 @@ namespace OpenRA.Traits
|
||||
foreach (var t in y.NodesDict["TerrainSpeeds"].Nodes)
|
||||
{
|
||||
var speed = (float)FieldLoader.GetValue("speed", typeof(float),t.Value.Value);
|
||||
var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (float)FieldLoader.GetValue("cost", typeof(float), t.Value.NodesDict["PathingCost"].Value) : 1f/speed;
|
||||
var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (int)FieldLoader.GetValue("cost", typeof(int), t.Value.NodesDict["PathingCost"].Value) : (int)(10000/speed);
|
||||
ret.Add(t.Key, new TerrainInfo{Speed = speed, Cost = cost});
|
||||
}
|
||||
|
||||
@@ -47,39 +49,51 @@ namespace OpenRA.Traits
|
||||
|
||||
public class TerrainInfo
|
||||
{
|
||||
public float Cost = float.PositiveInfinity;
|
||||
public int Cost = int.MaxValue;
|
||||
public float Speed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly MobileInfo Info;
|
||||
public bool IsMoving { get; internal set; }
|
||||
|
||||
int __facing;
|
||||
int2 __fromCell, __toCell;
|
||||
int __altitude;
|
||||
|
||||
[Sync]
|
||||
public int Facing
|
||||
{
|
||||
get { return __facing; }
|
||||
set { __facing = value; }
|
||||
}
|
||||
|
||||
[Sync]
|
||||
public int Altitude
|
||||
{
|
||||
get { return __altitude; }
|
||||
set { __altitude = value; }
|
||||
}
|
||||
|
||||
[Sync]
|
||||
public int Facing { get; set; }
|
||||
[Sync]
|
||||
public int Altitude { get; set; }
|
||||
[Sync]
|
||||
public int ROT { get { return Info.ROT; } }
|
||||
public int InitialFacing { get { return Info.InitialFacing; } }
|
||||
|
||||
int2 __fromCell, __toCell;
|
||||
public int2 fromCell
|
||||
{
|
||||
get { return __fromCell; }
|
||||
set { SetLocation( value, __toCell ); }
|
||||
}
|
||||
|
||||
[Sync]
|
||||
public int2 toCell
|
||||
public int2 PxPosition { get; set; }
|
||||
[Sync]
|
||||
public int2 fromCell { get { return __fromCell; } }
|
||||
[Sync]
|
||||
public int2 toCell { get { return __toCell; } }
|
||||
|
||||
[Sync]
|
||||
public int PathHash; // written by Move.EvalPath, to temporarily debug this crap.
|
||||
|
||||
public void SetLocation(int2 from, int2 to)
|
||||
{
|
||||
get { return __toCell; }
|
||||
set { SetLocation( __fromCell, value ); }
|
||||
}
|
||||
void SetLocation( int2 from, int2 to )
|
||||
{
|
||||
if( fromCell == from && toCell == to ) return;
|
||||
if (fromCell == from && toCell == to) return;
|
||||
RemoveInfluence();
|
||||
__fromCell = from;
|
||||
__toCell = to;
|
||||
@@ -87,6 +101,10 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
UnitInfluence uim;
|
||||
|
||||
const int avgTicksBeforePathing = 5;
|
||||
const int spreadTicksBeforePathing = 5;
|
||||
internal int ticksBeforePathing = 0;
|
||||
|
||||
public Mobile(ActorInitializer init, MobileInfo info)
|
||||
{
|
||||
@@ -98,6 +116,7 @@ namespace OpenRA.Traits
|
||||
if (init.Contains<LocationInit>())
|
||||
{
|
||||
this.__fromCell = this.__toCell = init.Get<LocationInit,int2>();
|
||||
this.PxPosition = Util.CenterOfCell( fromCell );
|
||||
AddInfluence();
|
||||
}
|
||||
|
||||
@@ -108,24 +127,27 @@ namespace OpenRA.Traits
|
||||
public void SetPosition(Actor self, int2 cell)
|
||||
{
|
||||
SetLocation( cell, cell );
|
||||
self.CenterLocation = Util.CenterOfCell(fromCell);
|
||||
PxPosition = Util.CenterOfCell(fromCell);
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public void SetPxPosition( Actor self, int2 px )
|
||||
{
|
||||
// Force move takes precidence
|
||||
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
|
||||
var cell = Util.CellContaining( px );
|
||||
SetLocation( cell, cell );
|
||||
PxPosition = px;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter( Info ); } }
|
||||
|
||||
// Note: Returns a valid order even if the unit can't move to the target
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (Info.OnRails) return null;
|
||||
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
|
||||
var type = (!self.World.LocalPlayer.Shroud.IsVisible(xy) || CanEnterCell(xy)) ? "Move" : "Move-Blocked";
|
||||
return new Order(type, self, xy, mi.Modifiers.HasModifier(Modifiers.Shift));
|
||||
if( order is MoveOrderTargeter )
|
||||
{
|
||||
if( Info.OnRails ) return null;
|
||||
return new Order( "Move", self, Util.CellContaining( target.CenterLocation ), false );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int2 NearestMoveableCell(int2 target)
|
||||
@@ -150,15 +172,16 @@ namespace OpenRA.Traits
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
|
||||
if (order.OrderString == "Move")
|
||||
{
|
||||
int2 currentLocation = NearestMoveableCell(order.TargetLocation);
|
||||
if (!CanEnterCell(currentLocation))
|
||||
return;
|
||||
|
||||
if( !order.Queued ) self.CancelActivity();
|
||||
|
||||
self.QueueActivity(new Activities.Move(currentLocation, 8));
|
||||
|
||||
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
@@ -167,23 +190,14 @@ namespace OpenRA.Traits
|
||||
if (line != null)
|
||||
line.SetTarget(self, Target.FromCell(currentLocation), Color.Green);
|
||||
});
|
||||
ticksBeforePathing = avgTicksBeforePathing +
|
||||
self.World.SharedRandom.Next( -spreadTicksBeforePathing, spreadTicksBeforePathing );
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move")
|
||||
return "move";
|
||||
|
||||
if (order.OrderString == "Move-Blocked")
|
||||
return "move-blocked";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
|
||||
if (order.OrderString == "Move")
|
||||
return "Move";
|
||||
return null;
|
||||
}
|
||||
@@ -220,7 +234,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public static bool CanEnterCell( MobileInfo mobileInfo, World world, UnitInfluence uim, BuildingInfluence bim, int2 cell, Actor ignoreActor, bool checkTransientActors )
|
||||
{
|
||||
if (MovementCostForCell(mobileInfo, world, cell) == float.PositiveInfinity)
|
||||
if (MovementCostForCell(mobileInfo, world, cell) == int.MaxValue)
|
||||
return false;
|
||||
|
||||
// Check for buildings
|
||||
@@ -265,19 +279,14 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public float MovementCostForCell( Actor self, int2 cell )
|
||||
{
|
||||
return MovementCostForCell( Info, self.World, cell );
|
||||
}
|
||||
|
||||
public static float MovementCostForCell(MobileInfo info, World world, int2 cell)
|
||||
public static int MovementCostForCell(MobileInfo info, World world, int2 cell)
|
||||
{
|
||||
if (!world.Map.IsInMap(cell.X,cell.Y))
|
||||
return float.PositiveInfinity;
|
||||
return int.MaxValue;
|
||||
|
||||
var type = world.GetTerrainType(cell);
|
||||
if (!info.TerrainSpeeds.ContainsKey(type))
|
||||
return float.PositiveInfinity;
|
||||
return int.MaxValue;
|
||||
|
||||
return info.TerrainSpeeds[type].Cost;
|
||||
}
|
||||
@@ -293,15 +302,7 @@ namespace OpenRA.Traits
|
||||
.TraitsImplementing<ISpeedModifier>()
|
||||
.Select(t => t.GetSpeedModifier())
|
||||
.Product();
|
||||
return Info.Speed * Info.TerrainSpeeds[type].Speed * modifier;
|
||||
}
|
||||
|
||||
public IEnumerable<float2> GetCurrentPath(Actor self)
|
||||
{
|
||||
var move = self.GetCurrentActivity() as Move;
|
||||
if (move == null || move.path == null) return new float2[] { };
|
||||
|
||||
return Enumerable.Reverse(move.path).Select( c => Util.CenterOfCell(c) );
|
||||
return Info.Speed * Info.TerrainSpeeds[type].Speed * modifier / 100f;
|
||||
}
|
||||
|
||||
public void AddInfluence()
|
||||
@@ -354,6 +355,38 @@ namespace OpenRA.Traits
|
||||
line.SetTargetSilently(self, Target.FromCell(moveTo.Value), Color.Green);
|
||||
});
|
||||
self.QueueActivity(new Move(moveTo.Value, 0));
|
||||
|
||||
Log.Write("debug", "OnNudge #{0} from {1} to {2}",
|
||||
self.ActorID, self.Location, moveTo.Value);
|
||||
}
|
||||
else
|
||||
Log.Write("debug", "OnNudge #{0} refuses at {1}",
|
||||
self.ActorID, self.Location);
|
||||
}
|
||||
|
||||
class MoveOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly MobileInfo unitType;
|
||||
|
||||
public MoveOrderTargeter( MobileInfo unitType )
|
||||
{
|
||||
this.unitType = unitType;
|
||||
}
|
||||
|
||||
public string OrderID { get { return "Move"; } }
|
||||
public int OrderPriority { get { return 4; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = "move";
|
||||
if( self.World.LocalPlayer.Shroud.IsVisible( location ) && !self.Trait<Mobile>().CanEnterCell( location ) )
|
||||
cursor = "move-blocked";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public void ResolveOrder (Actor self, Order order)
|
||||
{
|
||||
if (!Game.LobbyInfo.GlobalSettings.AllowCheats) return;
|
||||
if (!self.World.LobbyInfo.GlobalSettings.AllowCheats) return;
|
||||
|
||||
switch(order.OrderString)
|
||||
{
|
||||
@@ -68,17 +68,14 @@ namespace OpenRA.Traits
|
||||
}
|
||||
case "DevShroud":
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
Game.world.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
}
|
||||
self.World.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
break;
|
||||
}
|
||||
case "DevPathDebug":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
PathDebug ^= true;
|
||||
PathDebug ^= true;
|
||||
break;
|
||||
}
|
||||
case "DevUnitDebug":
|
||||
@@ -86,14 +83,19 @@ namespace OpenRA.Traits
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
Game.Settings.Debug.ShowCollisions ^= true;
|
||||
break;
|
||||
}
|
||||
case "DevGiveExploration":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
case "DevGiveExploration":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Game.Debug("Cheat used: {0} by {1}"
|
||||
.F(order.OrderString, self.Owner.PlayerName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class PlayerResourcesInfo : ITraitInfo
|
||||
public class PlayerResourcesInfo : ITraitInfo
|
||||
{
|
||||
public readonly int InitialCash = 10000;
|
||||
public readonly int InitialOre = 0;
|
||||
@@ -45,17 +45,53 @@ namespace OpenRA.Traits
|
||||
public int OreCapacity;
|
||||
[Sync]
|
||||
public int DisplayOre;
|
||||
|
||||
public float GetSiloFullness() { return (float)Ore / OreCapacity; }
|
||||
|
||||
public void GiveOre(int num)
|
||||
{
|
||||
Ore += num;
|
||||
|
||||
if (Ore > OreCapacity)
|
||||
{
|
||||
nextSiloAdviceTime = 0;
|
||||
Ore = OreCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
[Sync]
|
||||
public int PowerProvided;
|
||||
[Sync]
|
||||
public int PowerDrained;
|
||||
public bool TakeOre(int num)
|
||||
{
|
||||
if (Ore < num) return false;
|
||||
Ore -= num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void GiveCash(int num)
|
||||
{
|
||||
Cash += num;
|
||||
}
|
||||
|
||||
public bool TakeCash(int num)
|
||||
{
|
||||
if (Cash + Ore < num) return false;
|
||||
|
||||
// Spend ore before cash
|
||||
Ore -= num;
|
||||
if (Ore < 0)
|
||||
{
|
||||
Cash += Ore;
|
||||
Ore = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const float displayCashFracPerFrame = .07f;
|
||||
const int displayCashDeltaPerFrame = 37;
|
||||
int nextSiloAdviceTime = 0;
|
||||
|
||||
void TickOre(Actor self)
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait<IStoreOre>()
|
||||
.Sum(a => a.Trait.Capacity);
|
||||
@@ -102,91 +138,5 @@ namespace OpenRA.Traits
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
}
|
||||
}
|
||||
|
||||
int nextPowerAdviceTime = 0;
|
||||
void TickPower()
|
||||
{
|
||||
var oldBalance = PowerProvided - PowerDrained;
|
||||
|
||||
PowerProvided = 0;
|
||||
PowerDrained = 0;
|
||||
|
||||
var myBuildings = Owner.World.Queries.OwnedBy[Owner].WithTrait<Building>();
|
||||
|
||||
foreach (var a in myBuildings)
|
||||
{
|
||||
var q = a.Trait.GetPowerUsage();
|
||||
if (q > 0)
|
||||
PowerProvided += q;
|
||||
else
|
||||
PowerDrained -= q;
|
||||
}
|
||||
|
||||
if (PowerProvided - PowerDrained < 0)
|
||||
if (PowerProvided - PowerDrained != oldBalance)
|
||||
nextPowerAdviceTime = 0;
|
||||
|
||||
if (--nextPowerAdviceTime <= 0)
|
||||
{
|
||||
if (PowerProvided - PowerDrained < 0)
|
||||
Owner.GiveAdvice(Rules.Info["world"].Traits.Get<EvaAlertsInfo>().LowPower);
|
||||
|
||||
nextPowerAdviceTime = AdviceInterval;
|
||||
}
|
||||
}
|
||||
|
||||
public PowerState GetPowerState()
|
||||
{
|
||||
if (PowerProvided >= PowerDrained) return PowerState.Normal;
|
||||
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
|
||||
return PowerState.Critical;
|
||||
}
|
||||
|
||||
public float GetSiloFullness() { return (float)Ore / OreCapacity; }
|
||||
|
||||
public void GiveOre(int num)
|
||||
{
|
||||
Ore += num;
|
||||
|
||||
if (Ore > OreCapacity)
|
||||
{
|
||||
nextSiloAdviceTime = 0;
|
||||
Ore = OreCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TakeOre(int num)
|
||||
{
|
||||
if (Ore < num) return false;
|
||||
Ore -= num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void GiveCash(int num)
|
||||
{
|
||||
Cash += num;
|
||||
}
|
||||
|
||||
public bool TakeCash(int num)
|
||||
{
|
||||
if (Cash + Ore < num) return false;
|
||||
|
||||
// Spend ore before cash
|
||||
Ore -= num;
|
||||
if (Ore < 0)
|
||||
{
|
||||
Cash += Ore;
|
||||
Ore = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
TickPower();
|
||||
TickOre(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
111
OpenRA.Game/Traits/Player/PowerManager.cs
Normal file
111
OpenRA.Game/Traits/Player/PowerManager.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class PowerManagerInfo : ITraitInfo
|
||||
{
|
||||
public readonly int AdviceInterval = 250;
|
||||
public object Create(ActorInitializer init) { return new PowerManager(init, this); }
|
||||
}
|
||||
|
||||
public class PowerManager : ITick
|
||||
{
|
||||
PowerManagerInfo Info;
|
||||
Player Player;
|
||||
|
||||
Dictionary<Actor, int> PowerDrain = new Dictionary<Actor, int>();
|
||||
[Sync] int totalProvided;
|
||||
public int PowerProvided { get { return totalProvided; } }
|
||||
|
||||
[Sync] int totalDrained;
|
||||
public int PowerDrained { get { return totalDrained; } }
|
||||
|
||||
public PowerManager(ActorInitializer init, PowerManagerInfo info)
|
||||
{
|
||||
Info = info;
|
||||
Player = init.self.Owner;
|
||||
|
||||
init.world.ActorAdded += ActorAdded;
|
||||
init.world.ActorRemoved += ActorRemoved;
|
||||
}
|
||||
|
||||
void ActorAdded(Actor a)
|
||||
{
|
||||
if (a.Owner != Player || !a.HasTrait<Building>())
|
||||
return;
|
||||
PowerDrain.Add(a, a.Trait<Building>().GetPowerUsage());
|
||||
UpdateTotals();
|
||||
}
|
||||
|
||||
void ActorRemoved(Actor a)
|
||||
{
|
||||
if (a.Owner != Player || !a.HasTrait<Building>())
|
||||
return;
|
||||
PowerDrain.Remove(a);
|
||||
UpdateTotals();
|
||||
}
|
||||
|
||||
void UpdateTotals()
|
||||
{
|
||||
totalProvided = 0;
|
||||
totalDrained = 0;
|
||||
foreach (var kv in PowerDrain)
|
||||
{
|
||||
var p = kv.Value;
|
||||
if (p > 0)
|
||||
totalProvided += p;
|
||||
else
|
||||
totalDrained -= p;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateActor(Actor a, int newPower)
|
||||
{
|
||||
if (a.Owner != Player || !a.HasTrait<Building>())
|
||||
return;
|
||||
|
||||
PowerDrain[a] = newPower;
|
||||
UpdateTotals();
|
||||
}
|
||||
|
||||
int nextPowerAdviceTime = 0;
|
||||
bool wasLowPower = false;
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var lowPower = totalProvided < totalDrained;
|
||||
if (lowPower && !wasLowPower)
|
||||
nextPowerAdviceTime = 0;
|
||||
wasLowPower = lowPower;
|
||||
|
||||
if (--nextPowerAdviceTime <= 0)
|
||||
{
|
||||
if (lowPower)
|
||||
Player.GiveAdvice(Rules.Info["world"].Traits.Get<EvaAlertsInfo>().LowPower);
|
||||
|
||||
nextPowerAdviceTime = Info.AdviceInterval;
|
||||
}
|
||||
}
|
||||
|
||||
public PowerState PowerState
|
||||
{
|
||||
get {
|
||||
if (PowerProvided >= PowerDrained) return PowerState.Normal;
|
||||
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
|
||||
return PowerState.Critical;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
124
OpenRA.Game/Traits/Player/TechTree.cs
Executable file
124
OpenRA.Game/Traits/Player/TechTree.cs
Executable file
@@ -0,0 +1,124 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class TechTreeInfo : ITraitInfo
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new TechTree(init);}
|
||||
}
|
||||
|
||||
public class TechTree
|
||||
{
|
||||
readonly List<Watcher> watchers = new List<Watcher>();
|
||||
readonly Player player;
|
||||
public TechTree(ActorInitializer init)
|
||||
{
|
||||
player = init.self.Owner;
|
||||
init.world.ActorAdded += ActorChanged;
|
||||
init.world.ActorRemoved += ActorChanged;
|
||||
}
|
||||
|
||||
public void ActorChanged(Actor a)
|
||||
{
|
||||
if (a.Owner == player && a.HasTrait<Building>())
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var buildings = GatherBuildings(player);
|
||||
foreach(var w in watchers)
|
||||
w.Update(buildings);
|
||||
}
|
||||
|
||||
public void Add(string key, List<string> prerequisites, ITechTreeElement tte)
|
||||
{
|
||||
Add(key, prerequisites, false, tte);
|
||||
}
|
||||
|
||||
// set requiresPowered = true to discard buildings that have an IDisabled active (eg manually powered down)
|
||||
public void Add(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement tte)
|
||||
{
|
||||
watchers.Add(new Watcher( key, prerequisites, requiresPowered, tte ));
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
watchers.RemoveAll(x => x.key == key);
|
||||
}
|
||||
|
||||
static Cache<string, List<Actor>> GatherBuildings( Player player )
|
||||
{
|
||||
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
|
||||
if (player == null)
|
||||
return ret;
|
||||
|
||||
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
|
||||
{
|
||||
ret[ b.Info.Name ].Add( b );
|
||||
var tt = b.Info.Traits.GetOrDefault<TooltipInfo>();
|
||||
if( tt != null )
|
||||
foreach( var alt in tt.AlternateName )
|
||||
ret[ alt ].Add( b );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
class Watcher
|
||||
{
|
||||
public readonly string key;
|
||||
// strings may be either actor type, or "alternate name" key
|
||||
public readonly List<string> prerequisites;
|
||||
public readonly ITechTreeElement watcher;
|
||||
bool hasPrerequisites;
|
||||
bool requiresPowered;
|
||||
|
||||
public Watcher(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement watcher)
|
||||
{
|
||||
this.key = key;
|
||||
this.prerequisites = prerequisites;
|
||||
this.watcher = watcher;
|
||||
this.hasPrerequisites = false;
|
||||
this.requiresPowered = requiresPowered;
|
||||
}
|
||||
|
||||
public void Update(Cache<string, List<Actor>> buildings)
|
||||
{
|
||||
var nowHasPrerequisites = true;
|
||||
foreach (var p in prerequisites)
|
||||
if (!buildings.Keys.Contains(p) ||
|
||||
(requiresPowered && buildings[p].All(b => b.TraitsImplementing<IDisable>().Any(d => d.Disabled))))
|
||||
{
|
||||
nowHasPrerequisites = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if( nowHasPrerequisites && !hasPrerequisites )
|
||||
watcher.PrerequisitesAvailable(key);
|
||||
|
||||
if( !nowHasPrerequisites && hasPrerequisites )
|
||||
watcher.PrerequisitesUnavailable(key);
|
||||
|
||||
hasPrerequisites = nowHasPrerequisites;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ITechTreeElement
|
||||
{
|
||||
void PrerequisitesAvailable(string key);
|
||||
void PrerequisitesUnavailable(string key);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class TechTreeCacheInfo : TraitInfo<TechTreeCache> { }
|
||||
|
||||
class TechTreeCache : ITick
|
||||
{
|
||||
class Watcher
|
||||
{
|
||||
public readonly string key;
|
||||
// strings may be either actor type, or "alternate name" key
|
||||
public readonly List<string> prerequisites;
|
||||
public readonly ITechTreeElement watcher;
|
||||
bool hasPrerequisites;
|
||||
|
||||
public Watcher(string key, List<string> prerequisites, ITechTreeElement watcher)
|
||||
{
|
||||
this.key = key;
|
||||
this.prerequisites = prerequisites;
|
||||
this.watcher = watcher;
|
||||
this.hasPrerequisites = false;
|
||||
}
|
||||
|
||||
public void Tick( Player owner, Cache<string, List<Actor>> buildings )
|
||||
{
|
||||
var nowHasPrerequisites = prerequisites.All( a => buildings[ a ].Any( b => !b.Trait<Building>().Disabled ) );
|
||||
|
||||
if( nowHasPrerequisites && !hasPrerequisites )
|
||||
watcher.PrerequisitesAvailable(key);
|
||||
|
||||
if( !nowHasPrerequisites && hasPrerequisites )
|
||||
watcher.PrerequisitesUnavailable(key);
|
||||
|
||||
hasPrerequisites = nowHasPrerequisites;
|
||||
}
|
||||
}
|
||||
|
||||
readonly List<Watcher> watchers = new List<Watcher>();
|
||||
|
||||
public void Tick( Actor self )
|
||||
{
|
||||
var buildings = Rules.TechTree.GatherBuildings( self.Owner );
|
||||
|
||||
foreach( var w in watchers )
|
||||
w.Tick( self.Owner, buildings );
|
||||
}
|
||||
|
||||
public void Add( string key, List<string> prerequisites, ITechTreeElement tte )
|
||||
{
|
||||
watchers.Add( new Watcher( key, prerequisites, tte ) );
|
||||
}
|
||||
|
||||
public void Remove( string key )
|
||||
{
|
||||
watchers.RemoveAll( x => x.key == key );
|
||||
}
|
||||
}
|
||||
|
||||
interface ITechTreeElement
|
||||
{
|
||||
void PrerequisitesAvailable(string key);
|
||||
void PrerequisitesUnavailable(string key);
|
||||
}
|
||||
}
|
||||
12
OpenRA.Game/Traits/Render/RenderSimple.cs
Normal file → Executable file
12
OpenRA.Game/Traits/Render/RenderSimple.cs
Normal file → Executable file
@@ -62,16 +62,20 @@ namespace OpenRA.Traits
|
||||
a.Animation.Tick();
|
||||
}
|
||||
|
||||
protected virtual string GetPrefix(Actor self)
|
||||
protected virtual string NormalizeSequence(Actor self, string baseSequence)
|
||||
{
|
||||
return self.GetDamageState() >= DamageState.Heavy ? "damaged-" : "";
|
||||
string damageState = self.GetDamageState() >= DamageState.Heavy ? "damaged-" : "";
|
||||
if (anim.HasSequence(damageState + baseSequence))
|
||||
return damageState + baseSequence;
|
||||
else
|
||||
return baseSequence;
|
||||
}
|
||||
|
||||
public void PlayCustomAnim(Actor self, string name)
|
||||
{
|
||||
if (anim.HasSequence(name))
|
||||
anim.PlayThen(GetPrefix(self) + name,
|
||||
() => anim.PlayRepeating(GetPrefix(self) + "idle"));
|
||||
anim.PlayThen(NormalizeSequence(self, name),
|
||||
() => anim.PlayRepeating(NormalizeSequence(self, "idle")));
|
||||
}
|
||||
|
||||
public class AnimationWithOffset
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.IsIdle && previousLocation != self.Location)
|
||||
if (previousLocation != self.Location)
|
||||
{
|
||||
previousLocation = self.Location;
|
||||
self.World.WorldActor.Trait<Shroud>().UpdateActor(self);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -29,7 +28,7 @@ namespace OpenRA.Traits
|
||||
static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" };
|
||||
static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
|
||||
|
||||
public void RenderAfterWorld (Actor self)
|
||||
public void RenderAfterWorld (WorldRenderer wr, Actor self)
|
||||
{
|
||||
var bounds = self.GetBounds(true);
|
||||
|
||||
@@ -40,9 +39,9 @@ namespace OpenRA.Traits
|
||||
|
||||
DrawSelectionBox(self, xy, Xy, xY, XY, Color.White);
|
||||
DrawHealthBar(self, xy, Xy);
|
||||
DrawControlGroup(self, xy);
|
||||
DrawPips(self, xY);
|
||||
DrawTags(self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
|
||||
DrawControlGroup(wr, self, xy);
|
||||
DrawPips(wr, self, xY);
|
||||
DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
|
||||
DrawUnitPath(self);
|
||||
}
|
||||
|
||||
@@ -61,9 +60,10 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawHealthBar(Actor self, float2 xy, float2 Xy)
|
||||
{
|
||||
if (!self.IsInWorld) return;
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (self.IsDead() || health == null)
|
||||
return;
|
||||
if (health == null || health.IsDead) return;
|
||||
|
||||
var c = Color.Gray;
|
||||
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA.Traits
|
||||
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2);
|
||||
}
|
||||
|
||||
void DrawControlGroup(Actor self, float2 basePosition)
|
||||
void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition)
|
||||
{
|
||||
var group = self.World.Selection.GetControlGroupForActor(self);
|
||||
if (group == null) return;
|
||||
@@ -96,10 +96,10 @@ namespace OpenRA.Traits
|
||||
var pipImages = new Animation("pips");
|
||||
pipImages.PlayFetchIndex("groups", () => (int)group);
|
||||
pipImages.Tick();
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, basePosition + new float2(-8, 1), "chrome");
|
||||
pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome");
|
||||
}
|
||||
|
||||
void DrawPips(Actor self, float2 basePosition)
|
||||
void DrawPips(WorldRenderer wr, Actor self, float2 basePosition)
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer) return;
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
var pipImages = new Animation("pips");
|
||||
pipImages.PlayRepeating(pipStrings[(int)pip]);
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
|
||||
pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome");
|
||||
pipxyOffset += new float2(4, 0);
|
||||
}
|
||||
// Increment row
|
||||
@@ -131,7 +131,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTags(Actor self, float2 basePosition)
|
||||
void DrawTags(WorldRenderer wr, Actor self, float2 basePosition)
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer) return;
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace OpenRA.Traits
|
||||
|
||||
var tagImages = new Animation("pips");
|
||||
tagImages.PlayRepeating(tagStrings[(int)tag]);
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(tagImages.Image, tagxyBase + tagxyOffset, "chrome");
|
||||
tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome");
|
||||
|
||||
// Increment row
|
||||
tagxyOffset.Y += 8;
|
||||
@@ -158,13 +158,14 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawUnitPath(Actor self)
|
||||
{
|
||||
if (!Game.world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
|
||||
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
|
||||
var activity = self.GetCurrentActivity();
|
||||
var mobile = self.TraitOrDefault<IMove>();
|
||||
if (mobile != null)
|
||||
if (activity != null && mobile != null)
|
||||
{
|
||||
var alt = new float2(0, -mobile.Altitude);
|
||||
var path = mobile.GetCurrentPath(self);
|
||||
var path = activity.GetCurrentPath();
|
||||
var start = self.CenterLocation + alt;
|
||||
|
||||
var c = Color.Green;
|
||||
|
||||
0
OpenRA.Game/Traits/SharesCell.cs
Normal file → Executable file
0
OpenRA.Game/Traits/SharesCell.cs
Normal file → Executable file
@@ -17,7 +17,7 @@ namespace OpenRA.Traits
|
||||
public class TargetableInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] TargetTypes = {};
|
||||
public object Create( ActorInitializer init ) { return new Targetable(this); }
|
||||
public virtual object Create( ActorInitializer init ) { return new Targetable(this); }
|
||||
}
|
||||
|
||||
public class Targetable : ITargetable
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -35,8 +35,15 @@ namespace OpenRA.Traits
|
||||
public interface IRender { IEnumerable<Renderable> Render(Actor self); }
|
||||
public interface IIssueOrder
|
||||
{
|
||||
Order IssueOrder( Actor self, int2 xy, MouseInput mi, Actor underCursor );
|
||||
int OrderPriority( Actor self, int2 xy, MouseInput mi, Actor underCursor );
|
||||
IEnumerable<IOrderTargeter> Orders { get; }
|
||||
Order IssueOrder( Actor self, IOrderTargeter order, Target target );
|
||||
}
|
||||
public interface IOrderTargeter
|
||||
{
|
||||
string OrderID { get; }
|
||||
int OrderPriority { get; }
|
||||
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor );
|
||||
bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor );
|
||||
}
|
||||
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
|
||||
public interface IOrderCursor { string CursorForOrder(Actor self, Order order); }
|
||||
@@ -49,7 +56,6 @@ namespace OpenRA.Traits
|
||||
public interface INotifyProduction { void UnitProduced(Actor self, Actor other, int2 exit); }
|
||||
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
|
||||
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
|
||||
public interface INotifyEnterCell { void OnEnterCell(Actor self, int2 cell); }
|
||||
public interface IStoreOre { int Capacity { get; }}
|
||||
|
||||
public interface IDisable { bool Disabled { get; } }
|
||||
@@ -64,18 +70,17 @@ namespace OpenRA.Traits
|
||||
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
|
||||
public interface IOccupySpace
|
||||
public interface IHasLocation
|
||||
{
|
||||
int2 PxPosition { get; }
|
||||
}
|
||||
|
||||
public interface IOccupySpace : IHasLocation
|
||||
{
|
||||
int2 TopLeft { get; }
|
||||
IEnumerable<int2> OccupiedCells();
|
||||
}
|
||||
|
||||
public interface IOccupyAir
|
||||
{
|
||||
int2 TopLeft { get; }
|
||||
IEnumerable<int2> OccupiedAirCells();
|
||||
}
|
||||
|
||||
public static class IOccupySpaceExts
|
||||
{
|
||||
public static int2 NearestCellTo( this IOccupySpace ios, int2 other )
|
||||
@@ -99,23 +104,21 @@ namespace OpenRA.Traits
|
||||
public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); }
|
||||
public interface IDamageModifier { float GetDamageModifier( WarheadInfo warhead ); }
|
||||
public interface ISpeedModifier { float GetSpeedModifier(); }
|
||||
public interface IPowerModifier { float GetPowerModifier(); }
|
||||
public interface IFirepowerModifier { float GetFirepowerModifier(); }
|
||||
public interface IPalette { void InitPalette( WorldRenderer wr ); }
|
||||
public interface IPaletteModifier { void AdjustPalette(Dictionary<string,Palette> b); }
|
||||
public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
|
||||
public interface ITags { IEnumerable<TagType> GetTags(); }
|
||||
|
||||
public interface ITeleportable /* crap name! */
|
||||
public interface ITeleportable : IHasLocation /* crap name! */
|
||||
{
|
||||
bool CanEnterCell(int2 location);
|
||||
void SetPosition(Actor self, int2 cell);
|
||||
void SetPxPosition(Actor self, int2 px);
|
||||
}
|
||||
|
||||
public interface IMove : ITeleportable
|
||||
{
|
||||
float MovementCostForCell(Actor self, int2 cell);
|
||||
float MovementSpeedForCell(Actor self, int2 cell);
|
||||
IEnumerable<float2> GetCurrentPath(Actor self);
|
||||
int Altitude { get; set; }
|
||||
}
|
||||
|
||||
@@ -138,22 +141,24 @@ namespace OpenRA.Traits
|
||||
public readonly Sprite Sprite;
|
||||
public readonly float2 Pos;
|
||||
public readonly string Palette;
|
||||
public readonly int Z;
|
||||
public readonly int ZOffset;
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int zOffset)
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Pos = pos;
|
||||
Palette = palette;
|
||||
Z = z;
|
||||
ZOffset = zOffset;
|
||||
}
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette)
|
||||
: this(sprite, pos, palette, 0) { }
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z)
|
||||
: this(sprite, pos, palette, z, 0) { }
|
||||
|
||||
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, ZOffset); }
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); }
|
||||
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset); }
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset); }
|
||||
}
|
||||
|
||||
public interface ITraitInfo { object Create(ActorInitializer init); }
|
||||
@@ -170,18 +175,50 @@ namespace OpenRA.Traits
|
||||
|
||||
public interface IActivity
|
||||
{
|
||||
IActivity NextActivity { get; set; }
|
||||
IActivity Tick(Actor self);
|
||||
void Cancel(Actor self);
|
||||
void Queue(IActivity activity);
|
||||
IEnumerable<float2> GetCurrentPath();
|
||||
}
|
||||
|
||||
public interface IRenderOverlay { void Render(); }
|
||||
public abstract class CancelableActivity : IActivity
|
||||
{
|
||||
protected IActivity NextActivity { get; private set; }
|
||||
protected bool IsCanceled { get; private set; }
|
||||
|
||||
public abstract IActivity Tick( Actor self );
|
||||
protected virtual bool OnCancel() { return true; }
|
||||
|
||||
public void Cancel( Actor self )
|
||||
{
|
||||
IsCanceled = OnCancel();
|
||||
if( IsCanceled )
|
||||
NextActivity = null;
|
||||
else if (NextActivity != null)
|
||||
NextActivity.Cancel( self );
|
||||
}
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRenderOverlay { void Render( WorldRenderer wr ); }
|
||||
public interface INotifyIdle { void Idle(Actor self); }
|
||||
|
||||
public interface IBlocksBullets { }
|
||||
|
||||
public interface IPostRenderSelection { void RenderAfterWorld(Actor self); }
|
||||
public interface IPreRenderSelection { void RenderBeforeWorld(Actor self); }
|
||||
public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); }
|
||||
public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); }
|
||||
|
||||
public struct Target // a target: either an actor, or a fixed location.
|
||||
{
|
||||
@@ -202,9 +239,10 @@ namespace OpenRA.Traits
|
||||
public static readonly Target None = new Target();
|
||||
|
||||
public bool IsValid { get { return valid && (actor == null || actor.IsInWorld); } }
|
||||
public float2 CenterLocation { get { return actor != null ? actor.CenterLocation : pos.ToInt2(); } }
|
||||
public int2 PxPosition { get { return IsActor ? actor.Trait<IHasLocation>().PxPosition : pos.ToInt2(); } }
|
||||
public float2 CenterLocation { get { return PxPosition; } }
|
||||
|
||||
public Actor Actor { get { return actor; } }
|
||||
public bool IsActor { get { return actor != null; } }
|
||||
public Actor Actor { get { return IsActor ? actor : null; } }
|
||||
public bool IsActor { get { return actor != null && !actor.Destroyed; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public static int GetFacing( float2 d, int currentFacing )
|
||||
{
|
||||
if( float2.WithinEpsilon( d, float2.Zero, 0.001f ) )
|
||||
if (float2.WithinEpsilon(d, float2.Zero, 0.001f))
|
||||
return currentFacing;
|
||||
|
||||
int highest = -1;
|
||||
@@ -82,14 +82,14 @@ namespace OpenRA.Traits
|
||||
ecc * (cosAngle * v.Y - sinAngle * v.X));
|
||||
}
|
||||
|
||||
public static float2 CenterOfCell(int2 loc)
|
||||
public static int2 CenterOfCell(int2 loc)
|
||||
{
|
||||
return new float2(12, 12) + Game.CellSize * (float2)loc;
|
||||
return new int2( Game.CellSize / 2, Game.CellSize / 2 ) + Game.CellSize * loc;
|
||||
}
|
||||
|
||||
public static float2 BetweenCells(int2 from, int2 to)
|
||||
public static int2 BetweenCells(int2 from, int2 to)
|
||||
{
|
||||
return 0.5f * (CenterOfCell(from) + CenterOfCell(to));
|
||||
return int2.Lerp( CenterOfCell( from ), CenterOfCell( to ), 1, 2 );
|
||||
}
|
||||
|
||||
public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); }
|
||||
@@ -100,13 +100,13 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var pal = self.Owner == null ? "player0" : self.Owner.Palette;
|
||||
var loc = location - 0.5f * s.size;
|
||||
return new Renderable(s, loc.Round(), pal);
|
||||
return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y);
|
||||
}
|
||||
|
||||
public static IActivity SequenceActivities(params IActivity[] acts)
|
||||
{
|
||||
return acts.Reverse().Aggregate(
|
||||
(next, a) => { a.NextActivity = next; return a; });
|
||||
(next, a) => { a.Queue( next ); return a; });
|
||||
}
|
||||
|
||||
public static Color ArrayToColor(int[] x) { return Color.FromArgb(x[0], x[1], x[2]); }
|
||||
|
||||
23
OpenRA.Game/Traits/Valued.cs
Executable file
23
OpenRA.Game/Traits/Valued.cs
Executable file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ValuedInfo : TraitInfo<Valued>
|
||||
{
|
||||
public readonly int Cost = 0;
|
||||
}
|
||||
|
||||
public class TooltipInfo : TraitInfo<Tooltip>
|
||||
{
|
||||
public readonly string Description = "";
|
||||
public readonly string Name = "";
|
||||
public readonly string Icon = null;
|
||||
public readonly string[] AlternateName = { };
|
||||
}
|
||||
|
||||
public class Valued { }
|
||||
public class Tooltip { }
|
||||
}
|
||||
27
OpenRA.Game/Traits/World/BibLayer.cs
Normal file → Executable file
27
OpenRA.Game/Traits/World/BibLayer.cs
Normal file → Executable file
@@ -6,14 +6,14 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -71,11 +71,10 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
var cliprect = Game.viewport.ShroudBounds().HasValue
|
||||
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
|
||||
|
||||
public void Render( WorldRenderer wr )
|
||||
{
|
||||
var cliprect = Game.viewport.ShroudBounds( world );
|
||||
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
|
||||
@@ -83,7 +82,7 @@ namespace OpenRA.Traits
|
||||
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.IsExplored(kv.Key))
|
||||
continue;
|
||||
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(bibSprites[kv.Value.type - 1][kv.Value.image],
|
||||
bibSprites[kv.Value.type - 1][kv.Value.image].DrawAt( wr,
|
||||
Game.CellSize * kv.Key, "terrain");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,35 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class PlayerColorPaletteInfo : TraitInfo<PlayerColorPalette>
|
||||
{
|
||||
public class PlayerColorPaletteInfo : ITraitInfo
|
||||
{
|
||||
public readonly string BasePalette = null;
|
||||
public readonly bool SplitRamp = false;
|
||||
public readonly string BaseName = "player";
|
||||
public readonly PaletteFormat PaletteFormat = PaletteFormat.ra;
|
||||
|
||||
public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); }
|
||||
}
|
||||
|
||||
public class PlayerColorPalette {}
|
||||
public class PlayerColorPalette : IPalette
|
||||
{
|
||||
readonly Player owner;
|
||||
readonly PlayerColorPaletteInfo info;
|
||||
public PlayerColorPalette( Player owner, PlayerColorPaletteInfo info )
|
||||
{
|
||||
this.owner = owner;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void InitPalette( WorldRenderer wr )
|
||||
{
|
||||
var paletteName = "{0}{1}".F( info.BaseName, owner.Index );
|
||||
var newpal = new Palette(wr.GetPalette(info.BasePalette),
|
||||
new PlayerColorRemap(owner.Color, owner.Color2, info.PaletteFormat));
|
||||
wr.AddPalette(paletteName, newpal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,23 +18,26 @@ namespace OpenRA.Traits
|
||||
public class ResourceLayerInfo : TraitInfo<ResourceLayer> { }
|
||||
|
||||
public class ResourceLayer: IRenderOverlay, IWorldLoaded
|
||||
{
|
||||
{
|
||||
World world;
|
||||
|
||||
public ResourceType[] resourceTypes;
|
||||
CellContents[,] content;
|
||||
|
||||
public void Render()
|
||||
public void Render( WorldRenderer wr )
|
||||
{
|
||||
var cliprect = Game.viewport.ShroudBounds().HasValue
|
||||
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
|
||||
|
||||
var cliprect = Game.viewport.ShroudBounds( world );
|
||||
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
|
||||
|
||||
var minx = cliprect.Left;
|
||||
var maxx = cliprect.Right;
|
||||
|
||||
var miny = cliprect.Top;
|
||||
var maxy = cliprect.Bottom;
|
||||
|
||||
foreach( var rt in world.WorldActor.TraitsImplementing<ResourceType>() )
|
||||
rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette);
|
||||
|
||||
for (int x = minx; x < maxx; x++)
|
||||
for (int y = miny; y < maxy; y++)
|
||||
{
|
||||
@@ -44,9 +47,9 @@ namespace OpenRA.Traits
|
||||
|
||||
var c = content[x, y];
|
||||
if (c.image != null)
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(c.image[c.density],
|
||||
c.image[c.density].DrawAt(
|
||||
Game.CellSize * new int2(x, y),
|
||||
c.type.info.Palette);
|
||||
c.type.info.PaletteIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +147,7 @@ namespace OpenRA.Traits
|
||||
content[p.X, p.Y].type = null;
|
||||
content[p.X, p.Y].image = null;
|
||||
content[p.X, p.Y].density = 0;
|
||||
world.Map.CustomTerrain[p.X, p.Y] = null;
|
||||
}
|
||||
|
||||
public ResourceType GetResource(int2 p) { return content[p.X, p.Y].type; }
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace OpenRA.Traits
|
||||
public readonly string TerrainType = "Ore";
|
||||
|
||||
public Sprite[][] Sprites;
|
||||
public int PaletteIndex;
|
||||
|
||||
public object Create(ActorInitializer init) { return new ResourceType(this); }
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenRA.Traits
|
||||
var cp = Game.viewport.Location
|
||||
+ .5f * new float2(Game.viewport.Width, Game.viewport.Height);
|
||||
|
||||
var intensity = 24 * 24 * 100 * shakeEffects.Sum(
|
||||
var intensity = Game.CellSize * Game.CellSize * 100 * shakeEffects.Sum(
|
||||
e => e.Intensity / (e.Position - cp).LengthSquared);
|
||||
|
||||
return Math.Min(intensity, 10);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user