diff options
-rw-r--r-- | entities/checkpoint.xml | 5 | ||||
-rw-r--r-- | res/entities.xml | 22 | ||||
-rw-r--r-- | res/maps.xml | 32 | ||||
-rw-r--r-- | res/platform.png | bin | 0 -> 135 bytes | |||
-rw-r--r-- | tools/mapedit/src/frame.cpp | 82 | ||||
-rw-r--r-- | tools/mapedit/src/frame.h | 1 | ||||
-rw-r--r-- | tools/mapedit/src/map.h | 18 | ||||
-rw-r--r-- | tools/mapedit/src/object.cpp | 304 | ||||
-rw-r--r-- | tools/mapedit/src/object.h | 91 | ||||
-rw-r--r-- | tools/mapedit/src/undo.cpp | 74 | ||||
-rw-r--r-- | tools/mapedit/src/undo.h | 30 | ||||
-rw-r--r-- | tools/mapedit/src/widget.cpp | 86 | ||||
-rw-r--r-- | tools/mapedit/src/widget.h | 7 | ||||
-rw-r--r-- | tools/mapedit/src/world.cpp | 109 |
14 files changed, 716 insertions, 145 deletions
diff --git a/entities/checkpoint.xml b/entities/checkpoint.xml deleted file mode 100644 index 84786ee..0000000 --- a/entities/checkpoint.xml +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | <entity-def> | ||
2 | <sprite>res/keyring.png</sprite> | ||
3 | <action>save</action> | ||
4 | <size>8,11</size> | ||
5 | </entity-def> \ No newline at end of file | ||
diff --git a/res/entities.xml b/res/entities.xml new file mode 100644 index 0000000..c3dd3f3 --- /dev/null +++ b/res/entities.xml | |||
@@ -0,0 +1,22 @@ | |||
1 | <?xml version="1.0" encoding="ISO-8859-1"?> | ||
2 | <entities> | ||
3 | <entity id="checkpoint" name="Checkpoint" sprite="res/keyring.png" width="8" height="11"> | ||
4 | <event name="touch"> | ||
5 | <action type="save" /> | ||
6 | </event> | ||
7 | </entity> | ||
8 | |||
9 | <entity id="movplat" name="Moving Platform" sprite="res/platform.png" action="carry" width="24" height="8"> | ||
10 | <input id="dir" name="Direction" type="choice"> | ||
11 | <value id="0">Left</value> | ||
12 | <value id="1">Right</value> | ||
13 | <value id="2">Up</value> | ||
14 | <value id="3">Down</value> | ||
15 | </input> | ||
16 | <input id="len" name="Length" type="slider" minvalue="0" maxvalue="320" /> | ||
17 | <input id="speed" name="Speed (px/s)" type="slider" minvalue="1" maxvalue="320" /> | ||
18 | <event name="touch"> | ||
19 | <action type="carry" /> | ||
20 | </event> | ||
21 | </entity> | ||
22 | </entities> | ||
diff --git a/res/maps.xml b/res/maps.xml index 444e59f..1f19dfa 100644 --- a/res/maps.xml +++ b/res/maps.xml | |||
@@ -1,5 +1,5 @@ | |||
1 | <?xml version="1.0" encoding="ISO-8859-1"?> | 1 | <?xml version="1.0" encoding="ISO-8859-1"?> |
2 | <world nextmap="5" lastmap="4" startx="203" starty="44" startmap="0"><root>0</root><map id="0" title="Everything Is Embarrassing" expanded="true"><environment type="0">0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,18,9,8,10,8,11,8,10,10,8,11,8,9,10,21,0, | 2 | <world nextmap="6" lastmap="5" startx="203" starty="44" startmap="0"><root>0</root><map id="0" expanded="true" title="Everything Is Embarrassing"><environment type="0">0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,18,9,8,10,8,11,8,10,10,8,11,8,9,10,21,0, |
3 | 0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,22,21, | 3 | 0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,22,21, |
4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, | 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, |
5 | 0,19,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, | 5 | 0,19,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, |
@@ -23,7 +23,7 @@ | |||
23 | 0,0,0,0,24,3,1,2,1,1,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,27,1,3,2,26,0,0,0,0,0,0, | 23 | 0,0,0,0,24,3,1,2,1,1,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,27,1,3,2,26,0,0,0,0,0,0, |
24 | 1,2,3,1,25,0,0,0,0,0,20,0,0,0,0,0,0,19,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,27,1,2,2,4,3,1, | 24 | 1,2,3,1,25,0,0,0,0,0,20,0,0,0,0,0,0,19,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,27,1,2,2,4,3,1, |
25 | 0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0, | 25 | 0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0, |
26 | </environment><adjacent dir="left" type="warp" map="1" /><child>1</child><child>4</child></map><map id="1" title="It's A Trap!"><environment type="0">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | 26 | </environment><adjacent dir="left" type="warp" map="1"/><child>1</child><child>4</child><child>5</child></map><map id="1" expanded="false" title="It's A Trap!"><environment type="0">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0, | 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0, |
28 | 0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0, | 28 | 0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0, |
29 | 0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | 29 | 0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
@@ -47,7 +47,7 @@ | |||
47 | 0,0,0,27,2,2,3,3,3,4,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | 47 | 0,0,0,27,2,2,3,3,3,4,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
48 | 0,20,0,0,0,0,0,19,0,0,27,1,1,1,2,2,2,26,0,0,0,0,0,0,0,0,0,0,24,4,2,2,1,3,2,2,1,2,2,3, | 48 | 0,20,0,0,0,0,0,19,0,0,27,1,1,1,2,2,2,26,0,0,0,0,0,0,0,0,0,0,24,4,2,2,1,3,2,2,1,2,2,3, |
49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,19,0,0,0,0,0, | 49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,19,0,0,0,0,0, |
50 | </environment><entity type="checkpoint" x="262" y="156" /><adjacent dir="right" type="warp" map="0" /><adjacent dir="down" type="warp" map="4" /></map><map id="4" title="The Visitors"><environment type="0">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | 50 | </environment><entity type="checkpoint" x="262" y="156"/><adjacent dir="right" type="warp" map="0"/><adjacent dir="down" type="warp" map="4"/></map><map id="4" expanded="false" title="The Visitors"><environment type="0">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, |
51 | 0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,20,0,0,0,0, | 51 | 0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,20,0,0,0,0, |
52 | 0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | 52 | 0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, |
53 | 0,0,0,0,19,0,0,0,0,0,0,0,0,0,20,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | 53 | 0,0,0,0,19,0,0,0,0,0,0,0,0,0,20,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, |
@@ -71,4 +71,28 @@ | |||
71 | 0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | 71 | 0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, |
72 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, | 72 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, |
73 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | 73 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, |
74 | </environment><adjacent dir="up" type="warp" map="1" /><adjacent dir="down" type="wrap" /></map></world> | 74 | </environment><adjacent dir="up" type="warp" map="1"/><adjacent dir="down" type="warp" map="5"/></map><map id="5" expanded="false" title="Now Is The Hour"><environment type="0">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, |
75 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, | ||
76 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,20,0,0,0,0,0,0,0, | ||
77 | 0,0,0,19,0,0,0,0,0,0,0,0,19,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,19,0,0,0,0,0, | ||
78 | 0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, | ||
79 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0, | ||
80 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | ||
81 | 0,0,0,19,0,0,0,0,0,0,0,20,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,19,0,0, | ||
82 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0, | ||
83 | 0,0,0,0,0,0,18,9,9,9,9,9,9,9,9,9,9,17,0,0,0,0,0,0,0,0,0,0,23,10,21,0,20,0,0,0,0,0,0,0, | ||
84 | 10,10,10,10,10,10,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0, | ||
85 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, | ||
86 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, | ||
87 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0, | ||
88 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,19,0,0,0,0, | ||
89 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, | ||
90 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0, | ||
91 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,20,0,0,0,20,0, | ||
92 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, | ||
93 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,19,0,0,0, | ||
94 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0, | ||
95 | 2,2,2,2,2,2,26,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,12,0,0,0,0,0,0,0,0,0, | ||
96 | 0,0,0,0,0,0,27,1,3,4,2,1,3,2,1,1,2,4,1,1,1,3,1,1,4,2,1,3,4,1,25,19,0,0,0,0,0,0,0,0, | ||
97 | 0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
98 | </environment><entity type="movplat" x="98" y="145"><item id="dir">1</item><item id="len">70</item><item id="speed">35</item></entity><adjacent dir="up" type="warp" map="4"/></map></world> | ||
diff --git a/res/platform.png b/res/platform.png new file mode 100644 index 0000000..a7462a4 --- /dev/null +++ b/res/platform.png | |||
Binary files differ | |||
diff --git a/tools/mapedit/src/frame.cpp b/tools/mapedit/src/frame.cpp index 06102f7..aad3294 100644 --- a/tools/mapedit/src/frame.cpp +++ b/tools/mapedit/src/frame.cpp | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "mapselect_combo.h" | 2 | #include "mapselect_combo.h" |
3 | #include <wx/statline.h> | 3 | #include <wx/statline.h> |
4 | #include <list> | 4 | #include <list> |
5 | #include <wx/valgen.h> | ||
5 | #include <exception> | 6 | #include <exception> |
6 | #include <sstream> | 7 | #include <sstream> |
7 | #include "widget.h" | 8 | #include "widget.h" |
@@ -29,6 +30,7 @@ enum { | |||
29 | TOOL_FILE_SAVE, | 30 | TOOL_FILE_SAVE, |
30 | TOOL_MAP_ADD_ROOT, | 31 | TOOL_MAP_ADD_ROOT, |
31 | TOOL_MAP_ADD_CHILD, | 32 | TOOL_MAP_ADD_CHILD, |
33 | MAP_EDITOR_WIDGET, | ||
32 | MAP_EDITOR_NOTEBOOK, | 34 | MAP_EDITOR_NOTEBOOK, |
33 | MAP_EDITOR_TREE, | 35 | MAP_EDITOR_TREE, |
34 | MAP_TITLE_TEXTBOX, | 36 | MAP_TITLE_TEXTBOX, |
@@ -45,7 +47,10 @@ enum { | |||
45 | UPMAP_TYPE_CHOICE, | 47 | UPMAP_TYPE_CHOICE, |
46 | UPMAP_MAP_CHOICE, | 48 | UPMAP_MAP_CHOICE, |
47 | DOWNMAP_TYPE_CHOICE, | 49 | DOWNMAP_TYPE_CHOICE, |
48 | DOWNMAP_MAP_CHOICE | 50 | DOWNMAP_MAP_CHOICE, |
51 | ENTITY_EDITOR, | ||
52 | ENTITY_PROPERTY_EDITOR, | ||
53 | PROPERTY_EDITOR | ||
49 | }; | 54 | }; |
50 | 55 | ||
51 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | 56 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) |
@@ -87,6 +92,7 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | |||
87 | EVT_COMBOBOX_CLOSEUP(RIGHTMAP_MAP_CHOICE, MapeditFrame::OnSetRightmapMap) | 92 | EVT_COMBOBOX_CLOSEUP(RIGHTMAP_MAP_CHOICE, MapeditFrame::OnSetRightmapMap) |
88 | EVT_COMBOBOX_CLOSEUP(UPMAP_MAP_CHOICE, MapeditFrame::OnSetUpmapMap) | 93 | EVT_COMBOBOX_CLOSEUP(UPMAP_MAP_CHOICE, MapeditFrame::OnSetUpmapMap) |
89 | EVT_COMBOBOX_CLOSEUP(DOWNMAP_MAP_CHOICE, MapeditFrame::OnSetDownmapMap) | 94 | EVT_COMBOBOX_CLOSEUP(DOWNMAP_MAP_CHOICE, MapeditFrame::OnSetDownmapMap) |
95 | EVT_COMMAND(wxID_ANY, EVT_MAP_SELECTED_ENTITY, MapeditFrame::OnSelectEntity) | ||
90 | wxEND_EVENT_TABLE() | 96 | wxEND_EVENT_TABLE() |
91 | 97 | ||
92 | MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | 98 | MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") |
@@ -171,7 +177,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
171 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); | 177 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); |
172 | notebook->AddPage(tileEditor, "Tile Chooser", false); | 178 | notebook->AddPage(tileEditor, "Tile Chooser", false); |
173 | 179 | ||
174 | mapEditor = new MapeditWidget(layout3, wxID_ANY, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); | 180 | mapEditor = new MapeditWidget(layout3, MAP_EDITOR_WIDGET, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); |
175 | mapEditor->frame = this; | 181 | mapEditor->frame = this; |
176 | 182 | ||
177 | // Set up property editor | 183 | // Set up property editor |
@@ -181,7 +187,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
181 | 187 | ||
182 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); | 188 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); |
183 | 189 | ||
184 | startposLabel = new wxStaticText(propertyEditor, wxID_ANY, "Starting Position:"); | 190 | startposLabel = new wxStaticText(propertyEditor, PROPERTY_EDITOR, "Starting Position:"); |
185 | 191 | ||
186 | setStartposButton = new wxButton(propertyEditor, SET_STARTPOS_BUTTON, "Set Starting Position"); | 192 | setStartposButton = new wxButton(propertyEditor, SET_STARTPOS_BUTTON, "Set Starting Position"); |
187 | cancelStartposButton = new wxButton(propertyEditor, CANCEL_STARTPOS_BUTTON, "Cancel"); | 193 | cancelStartposButton = new wxButton(propertyEditor, CANCEL_STARTPOS_BUTTON, "Cancel"); |
@@ -264,7 +270,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
264 | propertySizer->SetSizeHints(propertyEditor); | 270 | propertySizer->SetSizeHints(propertyEditor); |
265 | 271 | ||
266 | // Set up entity editor | 272 | // Set up entity editor |
267 | wxPanel* entityEditor = new wxPanel(notebook, wxID_ANY); | 273 | wxPanel* entityEditor = new wxPanel(notebook, ENTITY_EDITOR); |
268 | notebook->AddPage(entityEditor, "Entity Manager", false); | 274 | notebook->AddPage(entityEditor, "Entity Manager", false); |
269 | 275 | ||
270 | wxStaticText* entityHeader = new wxStaticText(entityEditor, wxID_ANY, "Add Entity"); | 276 | wxStaticText* entityHeader = new wxStaticText(entityEditor, wxID_ANY, "Add Entity"); |
@@ -275,9 +281,9 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
275 | wxStaticText* entityTypeLabel = new wxStaticText(entityEditor, wxID_ANY, "Entity Type:"); | 281 | wxStaticText* entityTypeLabel = new wxStaticText(entityEditor, wxID_ANY, "Entity Type:"); |
276 | 282 | ||
277 | entityTypeBox = new wxChoice(entityEditor, wxID_ANY); | 283 | entityTypeBox = new wxChoice(entityEditor, wxID_ANY); |
278 | for (auto entry : MapObject::getAllObjects()) | 284 | for (auto& entry : MapObject::getAllObjects()) |
279 | { | 285 | { |
280 | entityTypeBox->Append(entry.second->getType(), entry.second.get()); | 286 | entityTypeBox->Append(entry.second.getName(), (void*) &entry.second); |
281 | } | 287 | } |
282 | 288 | ||
283 | addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); | 289 | addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); |
@@ -286,6 +292,8 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
286 | 292 | ||
287 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); | 293 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); |
288 | 294 | ||
295 | wxPanel* entityPropertyEditor = new wxPanel(entityEditor, ENTITY_PROPERTY_EDITOR); | ||
296 | |||
289 | wxBoxSizer* entitySizer = new wxBoxSizer(wxVERTICAL); | 297 | wxBoxSizer* entitySizer = new wxBoxSizer(wxVERTICAL); |
290 | entitySizer->Add(entityHeader, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 298 | entitySizer->Add(entityHeader, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
291 | wxBoxSizer* entitySizer1 = new wxBoxSizer(wxHORIZONTAL); | 299 | wxBoxSizer* entitySizer1 = new wxBoxSizer(wxHORIZONTAL); |
@@ -298,6 +306,12 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
298 | entitySizer->Add(entitySizer2, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 306 | entitySizer->Add(entitySizer2, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
299 | entitySizer->Add(new wxStaticLine(entityEditor), 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 307 | entitySizer->Add(new wxStaticLine(entityEditor), 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
300 | entitySizer->Add(entityInfoLabel, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 308 | entitySizer->Add(entityInfoLabel, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
309 | entitySizer->Add(entityPropertyEditor, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP | wxALL, 5); | ||
310 | wxBoxSizer* entityPropertySizer = new wxBoxSizer(wxVERTICAL); | ||
311 | entityPropertySizer->Add(new wxStaticLine(entityPropertyEditor), 1, wxEXPAND, 0); | ||
312 | entityPropertyEditor->SetSizer(entityPropertySizer); | ||
313 | entityPropertySizer->SetSizeHints(entityPropertyEditor); | ||
314 | //entitySizer->Add(entityPropertySizer, 1, wxEXPAND, 0); | ||
301 | entityEditor->SetSizer(entitySizer); | 315 | entityEditor->SetSizer(entitySizer); |
302 | entitySizer->SetSizeHints(entityEditor); | 316 | entitySizer->SetSizeHints(entityEditor); |
303 | 317 | ||
@@ -840,6 +854,62 @@ void MapeditFrame::OnSetDownmapMap(wxCommandEvent&) | |||
840 | })); | 854 | })); |
841 | } | 855 | } |
842 | 856 | ||
857 | void MapeditFrame::OnSelectEntity(wxCommandEvent& event) | ||
858 | { | ||
859 | MapObjectEntry* entry = (MapObjectEntry*) event.GetClientData(); | ||
860 | wxPanel* entityPropertyEditor = (wxPanel*) wxWindow::FindWindowById(ENTITY_PROPERTY_EDITOR, this); | ||
861 | |||
862 | if (entry == nullptr) | ||
863 | { | ||
864 | entityPropertyEditor->GetSizer()->Clear(); | ||
865 | entityPropertyEditor->DestroyChildren(); | ||
866 | } else { | ||
867 | wxSizer* sizer = entityPropertyEditor->GetSizer(); | ||
868 | for (auto input : entry->getObject().getInputs()) | ||
869 | { | ||
870 | wxStaticText* inputText = new wxStaticText(entityPropertyEditor, wxID_ANY, input.second.name + ":"); | ||
871 | sizer->Add(inputText, 0, wxEXPAND | wxALIGN_LEFT | wxBOTTOM, 0); | ||
872 | |||
873 | MapObjectEntry::Item& item = entry->getItem(input.first); | ||
874 | |||
875 | wxWindow* inputObject = nullptr; | ||
876 | switch (input.second.type) | ||
877 | { | ||
878 | case MapObject::Input::Type::Choice: | ||
879 | { | ||
880 | UndoableChoice* thechoice = new UndoableChoice(entityPropertyEditor, wxID_ANY, this, wxDefaultPosition, wxDefaultSize, 0, NULL, 0, VariableChoiceValidator(*world, item), input.second.name); | ||
881 | int selected = 0; | ||
882 | for (auto choice : input.second.choices) | ||
883 | { | ||
884 | thechoice->Append(choice.second, (void*) choice.first); | ||
885 | |||
886 | if (item.intvalue == choice.first) | ||
887 | { | ||
888 | selected = thechoice->GetCount()-1; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | thechoice->SetSelection(selected); | ||
893 | inputObject = thechoice; | ||
894 | break; | ||
895 | } | ||
896 | |||
897 | case MapObject::Input::Type::Slider: | ||
898 | { | ||
899 | if (item.intvalue < input.second.minvalue) item.intvalue = input.second.minvalue; | ||
900 | if (item.intvalue > input.second.maxvalue) item.intvalue = input.second.maxvalue; | ||
901 | inputObject = new UndoableSlider(entityPropertyEditor, wxID_ANY, this, item.intvalue, input.second.minvalue, input.second.maxvalue, wxDefaultPosition, wxDefaultSize, wxHORIZONTAL | wxSL_LABELS, SliderItemValidator(*world, item), input.second.name); | ||
902 | break; | ||
903 | } | ||
904 | } | ||
905 | |||
906 | sizer->Add(inputObject, 0, wxEXPAND | wxALIGN_LEFT | wxBOTTOM, 10); | ||
907 | } | ||
908 | |||
909 | entityPropertyEditor->Layout(); | ||
910 | } | ||
911 | } | ||
912 | |||
843 | void MapeditFrame::NewWorld() | 913 | void MapeditFrame::NewWorld() |
844 | { | 914 | { |
845 | LaunchWindow(new World()); | 915 | LaunchWindow(new World()); |
diff --git a/tools/mapedit/src/frame.h b/tools/mapedit/src/frame.h index dd8424c..9f9ea1f 100644 --- a/tools/mapedit/src/frame.h +++ b/tools/mapedit/src/frame.h | |||
@@ -74,6 +74,7 @@ class MapeditFrame : public wxFrame { | |||
74 | void OnSetUpmapMap(wxCommandEvent& event); | 74 | void OnSetUpmapMap(wxCommandEvent& event); |
75 | void OnSetDownmapType(wxCommandEvent& event); | 75 | void OnSetDownmapType(wxCommandEvent& event); |
76 | void OnSetDownmapMap(wxCommandEvent& event); | 76 | void OnSetDownmapMap(wxCommandEvent& event); |
77 | void OnSelectEntity(wxCommandEvent& event); | ||
77 | 78 | ||
78 | World* world; | 79 | World* world; |
79 | Map* currentMap; | 80 | Map* currentMap; |
diff --git a/tools/mapedit/src/map.h b/tools/mapedit/src/map.h index c7f5b30..9c14218 100644 --- a/tools/mapedit/src/map.h +++ b/tools/mapedit/src/map.h | |||
@@ -8,10 +8,11 @@ | |||
8 | #include <memory> | 8 | #include <memory> |
9 | #include <wx/treectrl.h> | 9 | #include <wx/treectrl.h> |
10 | #include <map> | 10 | #include <map> |
11 | #include "object.h" | ||
11 | 12 | ||
12 | class MapObject; | ||
13 | class World; | 13 | class World; |
14 | class MapeditFrame; | 14 | class MapeditFrame; |
15 | class MapEntryObject; | ||
15 | 16 | ||
16 | class MapLoadException: public std::exception | 17 | class MapLoadException: public std::exception |
17 | { | 18 | { |
@@ -41,21 +42,6 @@ class MapWriteException: public std::exception | |||
41 | std::string mapname; | 42 | std::string mapname; |
42 | }; | 43 | }; |
43 | 44 | ||
44 | struct MapObjectEntry { | ||
45 | MapObject* object; | ||
46 | std::pair<int, int> position; | ||
47 | |||
48 | bool operator==(MapObjectEntry& other) const | ||
49 | { | ||
50 | return (object == other.object) && (position == other.position); | ||
51 | } | ||
52 | |||
53 | bool operator!=(MapObjectEntry& other) const | ||
54 | { | ||
55 | return (object != other.object) && (position != other.position); | ||
56 | } | ||
57 | }; | ||
58 | |||
59 | class Map { | 45 | class Map { |
60 | public: | 46 | public: |
61 | Map(int id, World* world); | 47 | Map(int id, World* world); |
diff --git a/tools/mapedit/src/object.cpp b/tools/mapedit/src/object.cpp index a783691..8ed29af 100644 --- a/tools/mapedit/src/object.cpp +++ b/tools/mapedit/src/object.cpp | |||
@@ -2,29 +2,130 @@ | |||
2 | #include <dirent.h> | 2 | #include <dirent.h> |
3 | #include <libxml/parser.h> | 3 | #include <libxml/parser.h> |
4 | #include <memory> | 4 | #include <memory> |
5 | #include "world.h" | ||
5 | 6 | ||
6 | static std::map<std::string, std::shared_ptr<MapObject>> allObjects; | 7 | static std::map<std::string, MapObject> allObjects; |
7 | static bool objsInit = false; | 8 | static bool objsInit = false; |
8 | 9 | ||
9 | const std::map<std::string, std::shared_ptr<MapObject>> MapObject::getAllObjects() | 10 | const std::map<std::string, MapObject>& MapObject::getAllObjects() |
10 | { | 11 | { |
11 | if (!objsInit) | 12 | if (!objsInit) |
12 | { | 13 | { |
13 | DIR* dir = opendir("entities/"); | 14 | try |
14 | if (dir != NULL) | ||
15 | { | 15 | { |
16 | struct dirent* ent; | 16 | xmlDocPtr doc = xmlParseFile("res/entities.xml"); |
17 | while ((ent = readdir(dir)) != NULL) | 17 | if (doc == nullptr) |
18 | { | 18 | { |
19 | std::string path = ent->d_name; | 19 | throw MapObjectLoadException("can't open file"); |
20 | if ((path.length() >= 4) && (path.substr(path.length() - 4, 4) == ".xml")) | 20 | } |
21 | |||
22 | xmlNodePtr top = xmlDocGetRootElement(doc); | ||
23 | if (top == nullptr) | ||
24 | { | ||
25 | throw MapObjectLoadException("missing root element"); | ||
26 | } | ||
27 | |||
28 | if (xmlStrcmp(top->name, (const xmlChar*) "entities")) | ||
29 | { | ||
30 | throw MapObjectLoadException("root element is not entities"); | ||
31 | } | ||
32 | |||
33 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | ||
34 | { | ||
35 | if (!xmlStrcmp(node->name, (const xmlChar*) "entity")) | ||
21 | { | 36 | { |
22 | std::string name = path.substr(0, path.length() - 4); | 37 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); |
23 | auto obj = std::make_shared<MapObject>(name.c_str()); | 38 | if (idKey == 0) throw MapObjectLoadException("entity missing id"); |
24 | 39 | std::string theID = (char*) idKey; | |
25 | allObjects[name] = obj; | 40 | xmlFree(idKey); |
41 | |||
42 | allObjects.emplace(theID, theID); | ||
43 | MapObject& mapObject = allObjects.at(theID); | ||
44 | |||
45 | xmlChar* nameKey = xmlGetProp(node, (xmlChar*) "name"); | ||
46 | if (nameKey == 0) throw MapObjectLoadException("entity missing name"); | ||
47 | mapObject.name = (char*) nameKey; | ||
48 | xmlFree(nameKey); | ||
49 | |||
50 | xmlChar* spriteKey = xmlGetProp(node, (xmlChar*) "sprite"); | ||
51 | if (spriteKey == 0) throw MapObjectLoadException("entity missing sprite"); | ||
52 | mapObject.sprite = wxImage((char*) spriteKey); | ||
53 | xmlFree(spriteKey); | ||
54 | |||
55 | xmlChar* widthKey = xmlGetProp(node, (xmlChar*) "width"); | ||
56 | if (widthKey == 0) throw MapObjectLoadException("entity missing width"); | ||
57 | mapObject.width = atoi((char*) widthKey); | ||
58 | xmlFree(widthKey); | ||
59 | |||
60 | xmlChar* heightKey = xmlGetProp(node, (xmlChar*) "height"); | ||
61 | if (heightKey == 0) throw MapObjectLoadException("entity missing height"); | ||
62 | mapObject.height = atoi((char*) heightKey); | ||
63 | xmlFree(heightKey); | ||
64 | |||
65 | for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) | ||
66 | { | ||
67 | if (!xmlStrcmp(entityNode->name, (const xmlChar*) "input")) | ||
68 | { | ||
69 | xmlChar* key = xmlGetProp(entityNode, (xmlChar*) "id"); | ||
70 | if (key == 0) throw MapObjectLoadException("input missing id"); | ||
71 | std::string inputID = (char*) key; | ||
72 | xmlFree(key); | ||
73 | |||
74 | Input& input = mapObject.inputs[inputID]; | ||
75 | |||
76 | key = xmlGetProp(entityNode, (xmlChar*) "name"); | ||
77 | if (key == 0) throw MapObjectLoadException("input missing name"); | ||
78 | input.name = (char*) key; | ||
79 | xmlFree(key); | ||
80 | |||
81 | key = xmlGetProp(entityNode, (xmlChar*) "type"); | ||
82 | if (key == 0) throw MapObjectLoadException("input missing type"); | ||
83 | std::string inputType = (char*) key; | ||
84 | xmlFree(key); | ||
85 | |||
86 | if (inputType == "choice") | ||
87 | { | ||
88 | input.type = Input::Type::Choice; | ||
89 | |||
90 | for (xmlNodePtr choiceNode = entityNode->xmlChildrenNode; choiceNode != NULL; choiceNode = choiceNode->next) | ||
91 | { | ||
92 | if (!xmlStrcmp(choiceNode->name, (xmlChar*) "value")) | ||
93 | { | ||
94 | key = xmlGetProp(choiceNode, (xmlChar*) "id"); | ||
95 | if (key == 0) throw MapObjectLoadException("input value missing id"); | ||
96 | int valueId = atoi((char*) key); | ||
97 | xmlFree(key); | ||
98 | |||
99 | key = xmlNodeGetContent(choiceNode); | ||
100 | if (key == 0) throw MapObjectLoadException("input value missing content"); | ||
101 | std::string choiceText = (char*) key; | ||
102 | xmlFree(key); | ||
103 | |||
104 | input.choices[valueId] = choiceText; | ||
105 | } | ||
106 | } | ||
107 | } else if (inputType == "slider") | ||
108 | { | ||
109 | input.type = Input::Type::Slider; | ||
110 | |||
111 | key = xmlGetProp(entityNode, (xmlChar*) "minvalue"); | ||
112 | if (key == 0) throw MapObjectLoadException("integer input missing minvalue"); | ||
113 | input.minvalue = atoi((char*) key); | ||
114 | xmlFree(key); | ||
115 | |||
116 | key = xmlGetProp(entityNode, (xmlChar*) "maxvalue"); | ||
117 | if (key == 0) throw MapObjectLoadException("integer input missing maxvalue"); | ||
118 | input.maxvalue = atoi((char*) key); | ||
119 | xmlFree(key); | ||
120 | } | ||
121 | } | ||
122 | } | ||
26 | } | 123 | } |
27 | } | 124 | } |
125 | } catch (std::exception& ex) | ||
126 | { | ||
127 | wxMessageBox(ex.what(), "Error loading objects", wxOK | wxCENTRE | wxICON_ERROR); | ||
128 | exit(3); | ||
28 | } | 129 | } |
29 | 130 | ||
30 | objsInit = true; | 131 | objsInit = true; |
@@ -33,67 +134,170 @@ const std::map<std::string, std::shared_ptr<MapObject>> MapObject::getAllObjects | |||
33 | return allObjects; | 134 | return allObjects; |
34 | } | 135 | } |
35 | 136 | ||
36 | MapObject::MapObject(const char* filename) | 137 | MapObject::MapObject(std::string id) : id(id) |
37 | { | 138 | { |
38 | type = filename; | ||
39 | 139 | ||
40 | xmlDocPtr doc = xmlParseFile(("entities/" + std::string(filename) + ".xml").c_str()); | 140 | } |
41 | if (doc == nullptr) throw MapObjectLoadException(filename); | ||
42 | 141 | ||
43 | xmlNodePtr top = xmlDocGetRootElement(doc); | 142 | std::string MapObject::getID() const |
44 | if (top == nullptr) throw MapObjectLoadException(filename); | 143 | { |
144 | return id; | ||
145 | } | ||
45 | 146 | ||
46 | if (xmlStrcmp(top->name, (const xmlChar*) "entity-def")) | 147 | std::string MapObject::getName() const |
47 | { | 148 | { |
48 | throw MapObjectLoadException(filename); | 149 | return name; |
49 | } | 150 | } |
151 | |||
152 | wxBitmap MapObject::getSprite() const | ||
153 | { | ||
154 | return sprite; | ||
155 | } | ||
156 | |||
157 | int MapObject::getWidth() const | ||
158 | { | ||
159 | return width; | ||
160 | } | ||
161 | |||
162 | int MapObject::getHeight() const | ||
163 | { | ||
164 | return height; | ||
165 | } | ||
166 | |||
167 | const std::map<std::string, MapObject::Input>& MapObject::getInputs() const | ||
168 | { | ||
169 | return inputs; | ||
170 | } | ||
171 | |||
172 | const MapObject::Input& MapObject::getInput(std::string id) const | ||
173 | { | ||
174 | return inputs.at(id); | ||
175 | } | ||
176 | |||
177 | bool MapObject::operator==(const MapObject& other) const | ||
178 | { | ||
179 | return id == other.id; | ||
180 | } | ||
181 | |||
182 | bool MapObject::operator!=(const MapObject& other) const | ||
183 | { | ||
184 | return id != other.id; | ||
185 | } | ||
186 | |||
187 | MapObjectEntry::MapObjectEntry(const MapObject& object, int posx, int posy) : object(object) | ||
188 | { | ||
189 | position = std::make_pair(posx, posy); | ||
190 | } | ||
191 | |||
192 | const MapObject& MapObjectEntry::getObject() const | ||
193 | { | ||
194 | return object; | ||
195 | } | ||
196 | |||
197 | std::pair<int, int> MapObjectEntry::getPosition() const | ||
198 | { | ||
199 | return position; | ||
200 | } | ||
201 | |||
202 | MapObjectEntry::Item& MapObjectEntry::getItem(std::string str) | ||
203 | { | ||
204 | return items[str]; | ||
205 | } | ||
206 | |||
207 | const std::map<std::string, MapObjectEntry::Item>& MapObjectEntry::getItems() const | ||
208 | { | ||
209 | return items; | ||
210 | } | ||
211 | |||
212 | void MapObjectEntry::addItem(std::string id, Item& item) | ||
213 | { | ||
214 | items[id] = item; | ||
215 | } | ||
216 | |||
217 | void MapObjectEntry::setPosition(int x, int y) | ||
218 | { | ||
219 | position = std::make_pair(x, y); | ||
220 | } | ||
221 | |||
222 | bool MapObjectEntry::operator==(const MapObjectEntry& other) const | ||
223 | { | ||
224 | return (object == other.object) && (position == other.position); | ||
225 | } | ||
226 | |||
227 | bool MapObjectEntry::operator!=(const MapObjectEntry& other) const | ||
228 | { | ||
229 | return (object != other.object) && (position != other.position); | ||
230 | } | ||
231 | |||
232 | VariableChoiceValidator::VariableChoiceValidator(World& world, MapObjectEntry::Item& item) : world(world), item(item) | ||
233 | { | ||
234 | |||
235 | } | ||
50 | 236 | ||
51 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | 237 | wxObject* VariableChoiceValidator::Clone() const |
238 | { | ||
239 | return new VariableChoiceValidator(world, item); | ||
240 | } | ||
241 | |||
242 | bool VariableChoiceValidator::TransferFromWindow() | ||
243 | { | ||
244 | wxChoice* choice = (wxChoice*) GetWindow(); | ||
245 | int sel = choice->GetSelection(); | ||
246 | int val = (intptr_t) choice->GetClientData(sel); | ||
247 | item.intvalue = val; | ||
248 | world.setDirty(true); | ||
249 | |||
250 | return true; | ||
251 | } | ||
252 | |||
253 | bool VariableChoiceValidator::TransferToWindow() | ||
254 | { | ||
255 | wxChoice* choice = (wxChoice*) GetWindow(); | ||
256 | for (size_t i=0; i<choice->GetCount(); i++) | ||
52 | { | 257 | { |
53 | if (!xmlStrcmp(node->name, (const xmlChar*) "sprite")) | 258 | if ((intptr_t) choice->GetClientData(i) == item.intvalue) |
54 | { | ||
55 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
56 | std::string spriteFile = (char*) key; | ||
57 | xmlFree(key); | ||
58 | |||
59 | sprite = wxImage(spriteFile); | ||
60 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "action")) | ||
61 | { | 259 | { |
62 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | 260 | choice->SetSelection(i); |
63 | action = (char*) key; | 261 | return true; |
64 | xmlFree(key); | ||
65 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "size")) | ||
66 | { | ||
67 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
68 | sscanf((char*) key, "%d,%d", &width, &height); | ||
69 | xmlFree(key); | ||
70 | } | 262 | } |
71 | } | 263 | } |
264 | |||
265 | return false; | ||
266 | } | ||
72 | 267 | ||
73 | xmlFreeDoc(doc); | 268 | bool VariableChoiceValidator::Validate(wxWindow*) |
269 | { | ||
270 | return true; | ||
74 | } | 271 | } |
75 | 272 | ||
76 | wxBitmap MapObject::getSprite() const | 273 | SliderItemValidator::SliderItemValidator(World& world, MapObjectEntry::Item& item) : world(world), item(item) |
77 | { | 274 | { |
78 | return sprite; | 275 | |
79 | } | 276 | } |
80 | 277 | ||
81 | std::string MapObject::getAction() const | 278 | wxObject* SliderItemValidator::Clone() const |
82 | { | 279 | { |
83 | return action; | 280 | return new SliderItemValidator(world, item); |
84 | } | 281 | } |
85 | 282 | ||
86 | int MapObject::getWidth() const | 283 | bool SliderItemValidator::TransferFromWindow() |
87 | { | 284 | { |
88 | return width; | 285 | wxSlider* slider = (wxSlider*) GetWindow(); |
286 | item.intvalue = slider->GetValue(); | ||
287 | world.setDirty(true); | ||
288 | |||
289 | return true; | ||
89 | } | 290 | } |
90 | 291 | ||
91 | int MapObject::getHeight() const | 292 | bool SliderItemValidator::TransferToWindow() |
92 | { | 293 | { |
93 | return height; | 294 | wxSlider* slider = (wxSlider*) GetWindow(); |
295 | slider->SetValue(item.intvalue); | ||
296 | |||
297 | return true; | ||
94 | } | 298 | } |
95 | 299 | ||
96 | std::string MapObject::getType() const | 300 | bool SliderItemValidator::Validate(wxWindow*) |
97 | { | 301 | { |
98 | return type; | 302 | return true; |
99 | } | 303 | } |
diff --git a/tools/mapedit/src/object.h b/tools/mapedit/src/object.h index bfb493c..a870a2e 100644 --- a/tools/mapedit/src/object.h +++ b/tools/mapedit/src/object.h | |||
@@ -10,38 +10,111 @@ | |||
10 | #include <string> | 10 | #include <string> |
11 | #include <map> | 11 | #include <map> |
12 | 12 | ||
13 | class World; | ||
14 | |||
13 | class MapObjectLoadException: public std::exception | 15 | class MapObjectLoadException: public std::exception |
14 | { | 16 | { |
15 | public: | 17 | public: |
16 | MapObjectLoadException(std::string mapname) : mapname(mapname) {} | 18 | MapObjectLoadException(std::string stuff) : stuff(stuff) {} |
17 | 19 | ||
18 | virtual const char* what() const throw() | 20 | virtual const char* what() const throw() |
19 | { | 21 | { |
20 | return ("An error occured loading map object " + mapname).c_str(); | 22 | return ("An error occured loading map objects: " + stuff).c_str(); |
21 | } | 23 | } |
22 | 24 | ||
23 | private: | 25 | private: |
24 | std::string mapname; | 26 | std::string stuff; |
25 | }; | 27 | }; |
26 | 28 | ||
27 | class MapObject { | 29 | class MapObject { |
28 | public: | 30 | public: |
29 | MapObject(const char* filename); | 31 | MapObject(std::string id); |
32 | |||
33 | static const std::map<std::string, MapObject>& getAllObjects(); | ||
30 | 34 | ||
31 | static const std::map<std::string, std::shared_ptr<MapObject>> getAllObjects(); | 35 | struct Input { |
36 | enum class Type { | ||
37 | Slider, | ||
38 | Choice | ||
39 | }; | ||
40 | |||
41 | std::string name; | ||
42 | Type type; | ||
43 | int minvalue; | ||
44 | int maxvalue; | ||
45 | std::map<int, std::string> choices; | ||
46 | }; | ||
32 | 47 | ||
33 | std::string getType() const; | 48 | std::string getID() const; |
49 | std::string getName() const; | ||
34 | wxBitmap getSprite() const; | 50 | wxBitmap getSprite() const; |
35 | std::string getAction() const; | ||
36 | int getWidth() const; | 51 | int getWidth() const; |
37 | int getHeight() const; | 52 | int getHeight() const; |
53 | const std::map<std::string, Input>& getInputs() const; | ||
54 | const Input& getInput(std::string id) const; | ||
55 | |||
56 | bool operator==(const MapObject& other) const; | ||
57 | bool operator!=(const MapObject& other) const; | ||
38 | 58 | ||
39 | private: | 59 | private: |
40 | std::string type; | 60 | const std::string id; |
61 | std::string name; | ||
41 | wxBitmap sprite; | 62 | wxBitmap sprite; |
42 | std::string action; | ||
43 | int width; | 63 | int width; |
44 | int height; | 64 | int height; |
65 | std::map<std::string, Input> inputs; | ||
66 | }; | ||
67 | |||
68 | class MapObjectEntry { | ||
69 | public: | ||
70 | MapObjectEntry(const MapObject& object, int posx, int posy); | ||
71 | |||
72 | struct Item { | ||
73 | MapObject::Input::Type type; | ||
74 | int intvalue; | ||
75 | }; | ||
76 | |||
77 | const MapObject& getObject() const; | ||
78 | std::pair<int, int> getPosition() const; | ||
79 | Item& getItem(std::string str); | ||
80 | const std::map<std::string, Item>& getItems() const; | ||
81 | |||
82 | void setPosition(int x, int y); | ||
83 | void addItem(std::string id, Item& item); | ||
84 | |||
85 | bool operator==(const MapObjectEntry& other) const; | ||
86 | bool operator!=(const MapObjectEntry& other) const; | ||
87 | |||
88 | private: | ||
89 | const MapObject& object; | ||
90 | std::pair<int, int> position; | ||
91 | std::map<std::string, Item> items; | ||
92 | }; | ||
93 | |||
94 | class VariableChoiceValidator : public wxValidator { | ||
95 | public: | ||
96 | VariableChoiceValidator(World& world, MapObjectEntry::Item& item); | ||
97 | wxObject* Clone() const; | ||
98 | bool TransferFromWindow(); | ||
99 | bool TransferToWindow(); | ||
100 | bool Validate(wxWindow* parent); | ||
101 | |||
102 | private: | ||
103 | World& world; | ||
104 | MapObjectEntry::Item& item; | ||
105 | }; | ||
106 | |||
107 | class SliderItemValidator : public wxValidator { | ||
108 | public: | ||
109 | SliderItemValidator(World& world, MapObjectEntry::Item& item); | ||
110 | wxObject* Clone() const; | ||
111 | bool TransferFromWindow(); | ||
112 | bool TransferToWindow(); | ||
113 | bool Validate(wxWindow* parent); | ||
114 | |||
115 | private: | ||
116 | World& world; | ||
117 | MapObjectEntry::Item& item; | ||
45 | }; | 118 | }; |
46 | 119 | ||
47 | #endif | 120 | #endif |
diff --git a/tools/mapedit/src/undo.cpp b/tools/mapedit/src/undo.cpp index bcf7b92..12cafc9 100644 --- a/tools/mapedit/src/undo.cpp +++ b/tools/mapedit/src/undo.cpp | |||
@@ -28,7 +28,7 @@ wxBEGIN_EVENT_TABLE(UndoableTextBox, wxTextCtrl) | |||
28 | EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) | 28 | EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) |
29 | wxEND_EVENT_TABLE() | 29 | wxEND_EVENT_TABLE() |
30 | 30 | ||
31 | UndoableTextBox::UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos, wxSize size, long style) : wxTextCtrl(parent, id, startText, pos, size, style) | 31 | UndoableTextBox::UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, const wxPoint& pos, const wxSize& size, long style) : wxTextCtrl(parent, id, startText, pos, size, style) |
32 | { | 32 | { |
33 | this->undoText = undoType; | 33 | this->undoText = undoType; |
34 | this->realParent = realParent; | 34 | this->realParent = realParent; |
@@ -93,3 +93,75 @@ void UndoableTextBox::Undo::endChanges() | |||
93 | { | 93 | { |
94 | parent.undo.reset(); | 94 | parent.undo.reset(); |
95 | } | 95 | } |
96 | |||
97 | UndoableChoice::UndoableChoice() | ||
98 | { | ||
99 | Init(); | ||
100 | } | ||
101 | |||
102 | UndoableChoice::UndoableChoice(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, const wxPoint& pos, const wxSize& size, int n, const wxString choices[], long style, const wxValidator& validator, const wxString& name) : wxChoice(parent, id, pos, size, n, choices, style, validator, name) | ||
103 | { | ||
104 | this->realParent = realParent; | ||
105 | |||
106 | Init(); | ||
107 | } | ||
108 | |||
109 | void UndoableChoice::Init() | ||
110 | { | ||
111 | Bind(wxEVT_CHOICE, &UndoableChoice::OnChoose, this); | ||
112 | } | ||
113 | |||
114 | void UndoableChoice::OnChoose(wxCommandEvent& event) | ||
115 | { | ||
116 | int new_selection = GetSelection(); | ||
117 | GetValidator()->TransferToWindow(); | ||
118 | int old_selection = GetSelection(); | ||
119 | |||
120 | realParent->commitAction(std::make_shared<Undoable>(("Set " + GetName()).ToStdString(), [=] () { | ||
121 | SetSelection(new_selection); | ||
122 | GetValidator()->TransferFromWindow(); | ||
123 | }, [=] () { | ||
124 | SetSelection(old_selection); | ||
125 | GetValidator()->TransferFromWindow(); | ||
126 | })); | ||
127 | |||
128 | event.Skip(); | ||
129 | } | ||
130 | |||
131 | wxBEGIN_EVENT_TABLE(UndoableSlider, wxSlider) | ||
132 | EVT_SCROLL(UndoableSlider::OnSlide) | ||
133 | wxEND_EVENT_TABLE() | ||
134 | |||
135 | UndoableSlider::UndoableSlider() | ||
136 | { | ||
137 | Init(); | ||
138 | } | ||
139 | |||
140 | UndoableSlider::UndoableSlider(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, int value, int minvalue, int maxvalue, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) : wxSlider(parent, id, value, minvalue, maxvalue, pos, size, style, validator, name) | ||
141 | { | ||
142 | this->realParent = realParent; | ||
143 | |||
144 | Init(); | ||
145 | } | ||
146 | |||
147 | void UndoableSlider::Init() | ||
148 | { | ||
149 | |||
150 | } | ||
151 | |||
152 | void UndoableSlider::OnSlide(wxScrollEvent& event) | ||
153 | { | ||
154 | int new_value = GetValue(); | ||
155 | GetValidator()->TransferToWindow(); | ||
156 | int old_value = GetValue(); | ||
157 | |||
158 | realParent->commitAction(std::make_shared<Undoable>(("Set " + GetName()).ToStdString(), [=] () { | ||
159 | SetValue(new_value); | ||
160 | GetValidator()->TransferFromWindow(); | ||
161 | }, [=] () { | ||
162 | SetValue(old_value); | ||
163 | GetValidator()->TransferFromWindow(); | ||
164 | })); | ||
165 | |||
166 | event.Skip(); | ||
167 | } | ||
diff --git a/tools/mapedit/src/undo.h b/tools/mapedit/src/undo.h index 794f993..621f42c 100644 --- a/tools/mapedit/src/undo.h +++ b/tools/mapedit/src/undo.h | |||
@@ -32,7 +32,7 @@ class Undoable { | |||
32 | class UndoableTextBox : public wxTextCtrl { | 32 | class UndoableTextBox : public wxTextCtrl { |
33 | public: | 33 | public: |
34 | UndoableTextBox(); | 34 | UndoableTextBox(); |
35 | UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, long style = 0); | 35 | UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0); |
36 | 36 | ||
37 | private: | 37 | private: |
38 | class Undo : public Undoable { | 38 | class Undo : public Undoable { |
@@ -60,4 +60,32 @@ class UndoableTextBox : public wxTextCtrl { | |||
60 | wxDECLARE_EVENT_TABLE(); | 60 | wxDECLARE_EVENT_TABLE(); |
61 | }; | 61 | }; |
62 | 62 | ||
63 | class UndoableChoice : public wxChoice { | ||
64 | public: | ||
65 | UndoableChoice(); | ||
66 | UndoableChoice(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, int n = 0, const wxString choices[] = NULL, long style = 0, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxChoiceNameStr); | ||
67 | |||
68 | protected: | ||
69 | void Init(); | ||
70 | void OnChoose(wxCommandEvent& event); | ||
71 | |||
72 | private: | ||
73 | MapeditFrame* realParent; | ||
74 | }; | ||
75 | |||
76 | class UndoableSlider : public wxSlider { | ||
77 | public: | ||
78 | UndoableSlider(); | ||
79 | UndoableSlider(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, int value, int minvalue, int maxvalue, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxSliderNameStr); | ||
80 | |||
81 | protected: | ||
82 | void Init(); | ||
83 | void OnSlide(wxScrollEvent& event); | ||
84 | |||
85 | private: | ||
86 | MapeditFrame* realParent; | ||
87 | |||
88 | wxDECLARE_EVENT_TABLE(); | ||
89 | }; | ||
90 | |||
63 | #endif | 91 | #endif |
diff --git a/tools/mapedit/src/widget.cpp b/tools/mapedit/src/widget.cpp index fa0af39..8d74b39 100644 --- a/tools/mapedit/src/widget.cpp +++ b/tools/mapedit/src/widget.cpp | |||
@@ -16,6 +16,8 @@ BEGIN_EVENT_TABLE(MapeditWidget, wxScrolledCanvas) | |||
16 | EVT_LEAVE_WINDOW(MapeditWidget::OnMouseOut) | 16 | EVT_LEAVE_WINDOW(MapeditWidget::OnMouseOut) |
17 | EVT_SCROLLWIN(MapeditWidget::OnScroll) | 17 | EVT_SCROLLWIN(MapeditWidget::OnScroll) |
18 | END_EVENT_TABLE() | 18 | END_EVENT_TABLE() |
19 | |||
20 | wxDEFINE_EVENT(EVT_MAP_SELECTED_ENTITY, wxCommandEvent); | ||
19 | 21 | ||
20 | MapeditWidget::MapeditWidget() | 22 | MapeditWidget::MapeditWidget() |
21 | { | 23 | { |
@@ -107,12 +109,12 @@ void MapeditWidget::OnPaint(wxPaintEvent&) | |||
107 | { | 109 | { |
108 | tiles_dc.SelectObject(wxNullBitmap); | 110 | tiles_dc.SelectObject(wxNullBitmap); |
109 | 111 | ||
110 | wxBitmap sprite = object->object->getSprite(); | 112 | wxBitmap sprite = object->getObject().getSprite(); |
111 | tiles_dc.SelectObject(sprite); | 113 | tiles_dc.SelectObject(sprite); |
112 | 114 | ||
113 | wxPoint pos {(object->position.first + EDITOR_SPACING_X)*scale-vX, (object->position.second + EDITOR_SPACING_Y)*scale-vY}; | 115 | wxPoint pos {(object->getPosition().first + EDITOR_SPACING_X)*scale-vX, (object->getPosition().second + EDITOR_SPACING_Y)*scale-vY}; |
114 | wxSize size {object->object->getWidth()*scale, object->object->getHeight()*scale}; | 116 | wxSize size {object->getObject().getWidth()*scale, object->getObject().getHeight()*scale}; |
115 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, object->object->getWidth(), object->object->getHeight()); | 117 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, object->getObject().getWidth(), object->getObject().getHeight()); |
116 | 118 | ||
117 | if (editMode == EditEntities) | 119 | if (editMode == EditEntities) |
118 | { | 120 | { |
@@ -197,14 +199,14 @@ void MapeditWidget::OnPaint(wxPaintEvent&) | |||
197 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); | 199 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); |
198 | } else if ((editMode == EditEntities) && (movingEntity != nullptr)) | 200 | } else if ((editMode == EditEntities) && (movingEntity != nullptr)) |
199 | { | 201 | { |
200 | wxBitmap sprite = movingEntity->object->getSprite(); | 202 | wxBitmap sprite = movingEntity->getObject().getSprite(); |
201 | tiles_dc.SelectObject(wxNullBitmap); | 203 | tiles_dc.SelectObject(wxNullBitmap); |
202 | tiles_dc.SelectObject(sprite); | 204 | tiles_dc.SelectObject(sprite); |
203 | 205 | ||
204 | wxPoint pos {mousePos.x - movingEntity->object->getWidth()/2*scale, mousePos.y - movingEntity->object->getHeight()/2*scale}; | 206 | wxPoint pos {mousePos.x - movingEntity->getObject().getWidth()/2*scale, mousePos.y - movingEntity->getObject().getHeight()/2*scale}; |
205 | wxSize size {movingEntity->object->getWidth()*scale, movingEntity->object->getHeight()*scale}; | 207 | wxSize size {movingEntity->getObject().getWidth()*scale, movingEntity->getObject().getHeight()*scale}; |
206 | 208 | ||
207 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->object->getWidth(), movingEntity->object->getHeight()); | 209 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->getObject().getWidth(), movingEntity->getObject().getHeight()); |
208 | 210 | ||
209 | wxPen pen(*wxGREEN, 2); | 211 | wxPen pen(*wxGREEN, 2); |
210 | dc.SetPen(pen); | 212 | dc.SetPen(pen); |
@@ -254,17 +256,23 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
254 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (addingEntity->getWidth() / 2); | 256 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (addingEntity->getWidth() / 2); |
255 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (addingEntity->getHeight() / 2); | 257 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (addingEntity->getHeight() / 2); |
256 | 258 | ||
257 | auto data = std::make_shared<MapObjectEntry>(); | 259 | auto data = std::make_shared<MapObjectEntry>(*addingEntity, x, y); |
258 | data->object = addingEntity; | 260 | frame->commitAction(std::make_shared<Undoable>("Add " + addingEntity->getName(), [=] () { |
259 | data->position = std::make_pair(x,y); | ||
260 | |||
261 | frame->commitAction(std::make_shared<Undoable>("Add " + addingEntity->getType(), [=] () { | ||
262 | map->addObject(data); | 261 | map->addObject(data); |
263 | 262 | ||
264 | Refresh(); | 263 | Refresh(); |
265 | }, [=] () { | 264 | }, [=] () { |
266 | map->removeObject(data); | 265 | map->removeObject(data); |
267 | 266 | ||
267 | if (data == selectedEntity) | ||
268 | { | ||
269 | selectedEntity.reset(); | ||
270 | |||
271 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
272 | sev.SetClientData(0); | ||
273 | ProcessEvent(sev); | ||
274 | } | ||
275 | |||
268 | Refresh(); | 276 | Refresh(); |
269 | })); | 277 | })); |
270 | 278 | ||
@@ -272,17 +280,17 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
272 | addingEntity = nullptr; | 280 | addingEntity = nullptr; |
273 | } else if (movingEntity != nullptr) | 281 | } else if (movingEntity != nullptr) |
274 | { | 282 | { |
275 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (movingEntity->object->getWidth() / 2); | 283 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (movingEntity->getObject().getWidth() / 2); |
276 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (movingEntity->object->getHeight() / 2); | 284 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (movingEntity->getObject().getHeight() / 2); |
277 | auto oldPos = movingEntity->position; | 285 | auto oldPos = movingEntity->getPosition(); |
278 | MapObjectEntry* me = movingEntity; | 286 | MapObjectEntry* me = movingEntity; |
279 | 287 | ||
280 | frame->commitAction(std::make_shared<Undoable>("Move " + movingEntity->object->getType(), [=] () { | 288 | frame->commitAction(std::make_shared<Undoable>("Move " + movingEntity->getObject().getName(), [=] () { |
281 | me->position = std::make_pair(x,y); | 289 | me->setPosition(x, y); |
282 | 290 | ||
283 | Refresh(); | 291 | Refresh(); |
284 | }, [=] () { | 292 | }, [=] () { |
285 | me->position = oldPos; | 293 | me->setPosition(oldPos.first, oldPos.second); |
286 | 294 | ||
287 | Refresh(); | 295 | Refresh(); |
288 | })); | 296 | })); |
@@ -295,24 +303,34 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
295 | 303 | ||
296 | if (selectedEntity) | 304 | if (selectedEntity) |
297 | { | 305 | { |
298 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) | 306 | if ((x > selectedEntity->getPosition().first) |
299 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) | 307 | && (x < selectedEntity->getPosition().first + selectedEntity->getObject().getWidth()) |
308 | && (y > selectedEntity->getPosition().second) | ||
309 | && (y < selectedEntity->getPosition().second + selectedEntity->getObject().getHeight())) | ||
300 | { | 310 | { |
301 | movingEntity = selectedEntity.get(); | 311 | movingEntity = selectedEntity.get(); |
302 | frame->SetIsAddingEntity(true); | 312 | frame->SetIsAddingEntity(true); |
303 | } else { | 313 | } else { |
304 | selectedEntity.reset(); | 314 | selectedEntity.reset(); |
315 | |||
316 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
317 | sev.SetClientData(0); | ||
318 | ProcessEvent(sev); | ||
305 | } | 319 | } |
306 | 320 | ||
307 | Refresh(); | 321 | Refresh(); |
308 | } else { | 322 | } else { |
309 | for (auto object : map->getObjects()) | 323 | for (auto object : map->getObjects()) |
310 | { | 324 | { |
311 | if ((x >= object->position.first) && (x <= object->position.first + object->object->getWidth()) | 325 | if ((x >= object->getPosition().first) && (x <= object->getPosition().first + object->getObject().getWidth()) |
312 | && (y >= object->position.second) && (y <= object->position.second + object->object->getHeight())) | 326 | && (y >= object->getPosition().second) && (y <= object->getPosition().second + object->getObject().getHeight())) |
313 | { | 327 | { |
314 | selectedEntity = object; | 328 | selectedEntity = object; |
315 | 329 | ||
330 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
331 | sev.SetClientData(object.get()); | ||
332 | ProcessEvent(sev); | ||
333 | |||
316 | Refresh(); | 334 | Refresh(); |
317 | 335 | ||
318 | break; | 336 | break; |
@@ -364,12 +382,18 @@ void MapeditWidget::OnRightClick(wxMouseEvent& event) | |||
364 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale; | 382 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale; |
365 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale; | 383 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale; |
366 | 384 | ||
367 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) | 385 | if ((x > selectedEntity->getPosition().first) |
368 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) | 386 | && (x < selectedEntity->getPosition().first + selectedEntity->getObject().getWidth()) |
387 | && (y > selectedEntity->getPosition().second) | ||
388 | && (y < selectedEntity->getPosition().second + selectedEntity->getObject().getHeight())) | ||
369 | { | 389 | { |
370 | map->removeObject(selectedEntity); | 390 | map->removeObject(selectedEntity); |
371 | selectedEntity.reset(); | 391 | selectedEntity.reset(); |
372 | 392 | ||
393 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
394 | sev.SetClientData(0); | ||
395 | ProcessEvent(sev); | ||
396 | |||
373 | Refresh(); | 397 | Refresh(); |
374 | } | 398 | } |
375 | } | 399 | } |
@@ -494,6 +518,10 @@ void MapeditWidget::StartAddingEntity(MapObject* object) | |||
494 | selectedEntity = nullptr; | 518 | selectedEntity = nullptr; |
495 | isSettingPos = false; | 519 | isSettingPos = false; |
496 | frame->SetIsSettingStart(false); | 520 | frame->SetIsSettingStart(false); |
521 | |||
522 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
523 | sev.SetClientData(0); | ||
524 | ProcessEvent(sev); | ||
497 | } | 525 | } |
498 | 526 | ||
499 | void MapeditWidget::CancelAddingEntity() | 527 | void MapeditWidget::CancelAddingEntity() |
@@ -511,6 +539,10 @@ void MapeditWidget::SetIsSettingStart(bool isSetting) | |||
511 | frame->SetIsAddingEntity(false); | 539 | frame->SetIsAddingEntity(false); |
512 | addingEntity = nullptr; | 540 | addingEntity = nullptr; |
513 | selectedEntity = nullptr; | 541 | selectedEntity = nullptr; |
542 | |||
543 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
544 | sev.SetClientData(0); | ||
545 | ProcessEvent(sev); | ||
514 | } else { | 546 | } else { |
515 | isSettingPos = false; | 547 | isSettingPos = false; |
516 | } | 548 | } |
@@ -524,6 +556,10 @@ void MapeditWidget::SetMap(Map* map) | |||
524 | movingEntity = nullptr; | 556 | movingEntity = nullptr; |
525 | isSettingPos = false; | 557 | isSettingPos = false; |
526 | 558 | ||
559 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
560 | sev.SetClientData(0); | ||
561 | ProcessEvent(sev); | ||
562 | |||
527 | Refresh(); | 563 | Refresh(); |
528 | } | 564 | } |
529 | 565 | ||
diff --git a/tools/mapedit/src/widget.h b/tools/mapedit/src/widget.h index 864e299..937b699 100644 --- a/tools/mapedit/src/widget.h +++ b/tools/mapedit/src/widget.h | |||
@@ -16,7 +16,7 @@ class MapeditFrame; | |||
16 | class TileWidget; | 16 | class TileWidget; |
17 | class Map; | 17 | class Map; |
18 | class MapObject; | 18 | class MapObject; |
19 | struct MapObjectEntry; | 19 | class MapObjectEntry; |
20 | 20 | ||
21 | #include "consts.h" | 21 | #include "consts.h" |
22 | 22 | ||
@@ -76,5 +76,10 @@ class MapeditWidget : public wxScrolledCanvas { | |||
76 | DECLARE_DYNAMIC_CLASS(MapeditWidget) | 76 | DECLARE_DYNAMIC_CLASS(MapeditWidget) |
77 | DECLARE_EVENT_TABLE() | 77 | DECLARE_EVENT_TABLE() |
78 | }; | 78 | }; |
79 | |||
80 | // sends when an entity is selected OR deselected. | ||
81 | // client data will be a pointer to the MapObjectEntry if selection. | ||
82 | // client data will be nullptr if deselection. | ||
83 | wxDECLARE_EVENT(EVT_MAP_SELECTED_ENTITY, wxCommandEvent); | ||
79 | 84 | ||
80 | #endif | 85 | #endif |
diff --git a/tools/mapedit/src/world.cpp b/tools/mapedit/src/world.cpp index 01225cf..79f5a58 100644 --- a/tools/mapedit/src/world.cpp +++ b/tools/mapedit/src/world.cpp | |||
@@ -22,18 +22,18 @@ World::World(std::string filename) | |||
22 | xmlDocPtr doc = xmlParseFile(filename.c_str()); | 22 | xmlDocPtr doc = xmlParseFile(filename.c_str()); |
23 | if (doc == nullptr) | 23 | if (doc == nullptr) |
24 | { | 24 | { |
25 | throw MapLoadException(filename); | 25 | throw MapLoadException("file not found"); |
26 | } | 26 | } |
27 | 27 | ||
28 | xmlNodePtr top = xmlDocGetRootElement(doc); | 28 | xmlNodePtr top = xmlDocGetRootElement(doc); |
29 | if (top == nullptr) | 29 | if (top == nullptr) |
30 | { | 30 | { |
31 | throw MapLoadException(filename); | 31 | throw MapLoadException("no root element"); |
32 | } | 32 | } |
33 | 33 | ||
34 | if (xmlStrcmp(top->name, (const xmlChar*) "world")) | 34 | if (xmlStrcmp(top->name, (const xmlChar*) "world")) |
35 | { | 35 | { |
36 | throw MapLoadException(filename); | 36 | throw MapLoadException("no world element"); |
37 | } | 37 | } |
38 | 38 | ||
39 | xmlChar* nextmapKey = xmlGetProp(top, (xmlChar*) "nextmap"); | 39 | xmlChar* nextmapKey = xmlGetProp(top, (xmlChar*) "nextmap"); |
@@ -51,17 +51,17 @@ World::World(std::string filename) | |||
51 | xmlFree(lastmapKey); | 51 | xmlFree(lastmapKey); |
52 | 52 | ||
53 | xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); | 53 | xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); |
54 | if (startxKey == 0) throw MapLoadException(filename); | 54 | if (startxKey == 0) throw MapLoadException("world missing startx attribute"); |
55 | startingPosition.first = atoi((char*) startxKey); | 55 | startingPosition.first = atoi((char*) startxKey); |
56 | xmlFree(startxKey); | 56 | xmlFree(startxKey); |
57 | 57 | ||
58 | xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); | 58 | xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); |
59 | if (startyKey == 0) throw MapLoadException(filename); | 59 | if (startyKey == 0) throw MapLoadException("world missing starty attribute"); |
60 | startingPosition.second = atoi((char*) startyKey); | 60 | startingPosition.second = atoi((char*) startyKey); |
61 | xmlFree(startyKey); | 61 | xmlFree(startyKey); |
62 | 62 | ||
63 | xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); | 63 | xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); |
64 | if (startxKey == 0) throw MapLoadException(filename); | 64 | if (startxKey == 0) throw MapLoadException("world missing startmap attribute"); |
65 | startingMap = atoi((char*) startmapKey); | 65 | startingMap = atoi((char*) startmapKey); |
66 | xmlFree(startmapKey); | 66 | xmlFree(startmapKey); |
67 | 67 | ||
@@ -69,14 +69,14 @@ World::World(std::string filename) | |||
69 | { | 69 | { |
70 | if (!xmlStrcmp(node->name, (const xmlChar*) "root")) | 70 | if (!xmlStrcmp(node->name, (const xmlChar*) "root")) |
71 | { | 71 | { |
72 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | 72 | xmlChar* key = xmlNodeGetContent(node); |
73 | if (key == 0) throw MapLoadException(filename); | 73 | if (key == 0) throw MapLoadException("root missing content"); |
74 | rootChildren.push_back(atoi((char*) key)); | 74 | rootChildren.push_back(atoi((char*) key)); |
75 | xmlFree(key); | 75 | xmlFree(key); |
76 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) | 76 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) |
77 | { | 77 | { |
78 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); | 78 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); |
79 | if (idKey == 0) throw MapLoadException(filename); | 79 | if (idKey == 0) throw MapLoadException("map missing id attribute"); |
80 | int id = atoi((char*) idKey); | 80 | int id = atoi((char*) idKey); |
81 | xmlFree(idKey); | 81 | xmlFree(idKey); |
82 | 82 | ||
@@ -90,7 +90,7 @@ World::World(std::string filename) | |||
90 | xmlFree(expandKey); | 90 | xmlFree(expandKey); |
91 | 91 | ||
92 | xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); | 92 | xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); |
93 | if (titleKey == 0) throw MapLoadException(filename); | 93 | if (titleKey == 0) throw MapLoadException("map missing title attribute"); |
94 | map->setTitle((char*) titleKey, false); | 94 | map->setTitle((char*) titleKey, false); |
95 | xmlFree(titleKey); | 95 | xmlFree(titleKey); |
96 | 96 | ||
@@ -98,7 +98,8 @@ World::World(std::string filename) | |||
98 | { | 98 | { |
99 | if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) | 99 | if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) |
100 | { | 100 | { |
101 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | 101 | xmlChar* key = xmlNodeGetContent(mapNode); |
102 | if (key == 0) throw MapLoadException("map missing environment content"); | ||
102 | int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | 103 | int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); |
103 | mapdata[0] = atoi(strtok((char*) key, ",\n")); | 104 | mapdata[0] = atoi(strtok((char*) key, ",\n")); |
104 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) | 105 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) |
@@ -109,24 +110,52 @@ World::World(std::string filename) | |||
109 | xmlFree(key); | 110 | xmlFree(key); |
110 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity")) | 111 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity")) |
111 | { | 112 | { |
112 | auto data = std::make_shared<MapObjectEntry>(); | ||
113 | |||
114 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); | 113 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); |
115 | if (typeKey == 0) throw MapLoadException(filename); | 114 | if (typeKey == 0) throw MapLoadException("entity missing type attribute"); |
116 | data->object = MapObject::getAllObjects().at((char*) typeKey).get(); | 115 | const MapObject& obj = MapObject::getAllObjects().at((char*) typeKey); |
117 | xmlFree(typeKey); | 116 | xmlFree(typeKey); |
118 | 117 | ||
119 | xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x"); | 118 | xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x"); |
120 | if (xKey == 0) throw MapLoadException(filename); | 119 | if (xKey == 0) throw MapLoadException("entity missing x attribute"); |
121 | data->position.first = atoi((char*) xKey); | 120 | int xpos = atoi((char*) xKey); |
122 | xmlFree(xKey); | 121 | xmlFree(xKey); |
123 | 122 | ||
124 | xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y"); | 123 | xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y"); |
125 | if (yKey == 0) throw MapLoadException(filename); | 124 | if (yKey == 0) throw MapLoadException("entity missing y attribute"); |
126 | data->position.second = atoi((char*) yKey); | 125 | int ypos = atoi((char*) yKey); |
127 | xmlFree(yKey); | 126 | xmlFree(yKey); |
128 | 127 | ||
128 | auto data = std::make_shared<MapObjectEntry>(obj, xpos, ypos); | ||
129 | |||
129 | map->addObject(data, false); | 130 | map->addObject(data, false); |
131 | |||
132 | for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; objectNode != NULL; objectNode = objectNode->next) | ||
133 | { | ||
134 | if (!xmlStrcmp(objectNode->name, (const xmlChar*) "item")) | ||
135 | { | ||
136 | xmlChar* key = xmlGetProp(objectNode, (const xmlChar*) "id"); | ||
137 | if (key == 0) throw MapLoadException("item missing id attribute"); | ||
138 | std::string itemID = (char*) key; | ||
139 | xmlFree(key); | ||
140 | |||
141 | MapObjectEntry::Item item; | ||
142 | item.type = data->getObject().getInput(itemID).type; | ||
143 | |||
144 | key = xmlNodeGetContent(objectNode); | ||
145 | if (key == 0) throw MapLoadException("item missing content"); | ||
146 | switch (item.type) | ||
147 | { | ||
148 | case MapObject::Input::Type::Choice: | ||
149 | case MapObject::Input::Type::Slider: | ||
150 | { | ||
151 | item.intvalue = atoi((char*) key); | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | data->addItem(itemID, item); | ||
157 | } | ||
158 | } | ||
130 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent")) | 159 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent")) |
131 | { | 160 | { |
132 | Map::MoveDir direction; | 161 | Map::MoveDir direction; |
@@ -134,12 +163,12 @@ World::World(std::string filename) | |||
134 | int mapId = 0; | 163 | int mapId = 0; |
135 | 164 | ||
136 | xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir"); | 165 | xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir"); |
137 | if (dirKey == 0) throw MapLoadException(filename); | 166 | if (dirKey == 0) throw MapLoadException("adjacent missing dir attribute"); |
138 | direction = Map::moveDirForShort((char*) dirKey); | 167 | direction = Map::moveDirForShort((char*) dirKey); |
139 | xmlFree(dirKey); | 168 | xmlFree(dirKey); |
140 | 169 | ||
141 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); | 170 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); |
142 | if (typeKey == 0) throw MapLoadException(filename); | 171 | if (typeKey == 0) throw MapLoadException("adjacent missing type attribute"); |
143 | moveType = Map::moveTypeForShort((char*) typeKey); | 172 | moveType = Map::moveTypeForShort((char*) typeKey); |
144 | xmlFree(typeKey); | 173 | xmlFree(typeKey); |
145 | 174 | ||
@@ -153,7 +182,7 @@ World::World(std::string filename) | |||
153 | map->setAdjacent(direction, moveType, mapId, false); | 182 | map->setAdjacent(direction, moveType, mapId, false); |
154 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) | 183 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) |
155 | { | 184 | { |
156 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | 185 | xmlChar* key = xmlNodeGetContent(mapNode); |
157 | if (key != 0) | 186 | if (key != 0) |
158 | { | 187 | { |
159 | map->addChild(atoi((char*) key)); | 188 | map->addChild(atoi((char*) key)); |
@@ -281,7 +310,7 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
281 | } | 310 | } |
282 | 311 | ||
283 | // title= | 312 | // title= |
284 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "name", (xmlChar*) map.getTitle().c_str()); | 313 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "title", (xmlChar*) map.getTitle().c_str()); |
285 | if (rc < 0) throw MapWriteException(name); | 314 | if (rc < 0) throw MapWriteException(name); |
286 | 315 | ||
287 | // <environment | 316 | // <environment |
@@ -304,7 +333,7 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
304 | mapdata_out << std::endl; | 333 | mapdata_out << std::endl; |
305 | } | 334 | } |
306 | 335 | ||
307 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "environment", (xmlChar*) mapdata_out.str().c_str()); | 336 | rc = xmlTextWriterWriteString(writer, (xmlChar*) mapdata_out.str().c_str()); |
308 | if (rc < 0) throw MapWriteException(name); | 337 | if (rc < 0) throw MapWriteException(name); |
309 | 338 | ||
310 | // </environment> | 339 | // </environment> |
@@ -318,16 +347,42 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
318 | if (rc < 0) throw MapWriteException(name); | 347 | if (rc < 0) throw MapWriteException(name); |
319 | 348 | ||
320 | // type= | 349 | // type= |
321 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "type", (xmlChar*) object->object->getType().c_str()); | 350 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "type", (xmlChar*) object->getObject().getID().c_str()); |
322 | if (rc < 0) throw MapWriteException(name); | 351 | if (rc < 0) throw MapWriteException(name); |
323 | 352 | ||
324 | // x= | 353 | // x= |
325 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "x", "%d", object->position.first); | 354 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "x", "%d", object->getPosition().first); |
326 | if (rc < 0) throw MapWriteException(name); | 355 | if (rc < 0) throw MapWriteException(name); |
327 | 356 | ||
328 | // y= | 357 | // y= |
329 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "y", "%d", object->position.second); | 358 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "y", "%d", object->getPosition().second); |
330 | if (rc < 0) throw MapWriteException(name); | 359 | if (rc < 0) throw MapWriteException(name); |
360 | |||
361 | for (auto item : object->getItems()) | ||
362 | { | ||
363 | // <item | ||
364 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "item"); | ||
365 | if (rc < 0) throw MapWriteException(name); | ||
366 | |||
367 | // id= | ||
368 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "id", (xmlChar*) item.first.c_str()); | ||
369 | if (rc < 0) throw MapWriteException(name); | ||
370 | |||
371 | // > | ||
372 | switch (item.second.type) | ||
373 | { | ||
374 | case MapObject::Input::Type::Slider: | ||
375 | case MapObject::Input::Type::Choice: | ||
376 | { | ||
377 | rc = xmlTextWriterWriteFormatString(writer, "%d", item.second.intvalue); | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | // </item> | ||
383 | rc = xmlTextWriterEndElement(writer); | ||
384 | if (rc < 0) throw MapWriteException(name); | ||
385 | } | ||
331 | 386 | ||
332 | // </entity> | 387 | // </entity> |
333 | rc = xmlTextWriterEndElement(writer); | 388 | rc = xmlTextWriterEndElement(writer); |