1 package erland.game.tileadventure;
2
3 import erland.game.component.EPanel;
4 import erland.game.component.ETextField;
5 import erland.game.component.ELabel;
6 import erland.game.component.ENumberSpinner;
7 import erland.game.GameEnvironmentInterface;
8 import erland.game.tileadventure.rect.RectBlockContainerData;
9 import erland.util.ParameterSerializable;
10
11 import javax.swing.*;
12 import javax.swing.event.ChangeListener;
13 import javax.swing.event.ChangeEvent;
14 import java.awt.*;
15 import java.awt.event.ActionListener;
16 import java.awt.event.ActionEvent;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public abstract class TileMapEditor extends MapEditor {
38 /*** Block container for the editor area */
39 protected BlockContainerData cont;
40 /*** Block container for the block select area */
41 protected BlockContainerData contPalette;
42 /*** Blocks in the editor area */
43 protected MapObjectContainerInterface mapBlocks;
44 /*** Blocks in the select block area */
45 protected MapObjectContainerInterface paletteBlocks;
46 /*** Spinner that changes the current level/block edited */
47 protected ENumberSpinner levelNoSpinner;
48 /*** Currently edited level/block number */
49 protected int levelNo = 1;
50 /*** Extended information about the currently edited level/block */
51 protected ParameterSerializable extendedLevelInfo;
52 /*** Spinner that changes the current height level edited */
53 protected ENumberSpinner heightLevelSpinner;
54
55
56 public void init(GameEnvironmentInterface environment)
57 {
58 paletteBlocks = null;
59 mapBlocks = null;
60 cont = null;
61 contPalette = null;
62 super.init(environment);
63 }
64 /***
65 * Get the name that is used for a list of the currently edited object type
66 * when it is stored to file, for example "levels"
67 * @return The name of the currently edited object type used in storage
68 */
69 abstract protected String getLevelFileLabel();
70
71 /***
72 * Get the name that is used for the currently edited object type
73 * when it is stored to file, for example "level"
74 * @return The name of the currently edited object type used in storage
75 */
76 abstract protected String getLevelFileGroupLabel();
77
78 /***
79 * Get the horizontal number of blocks in main editor area
80 * @return The horizontal number of blocks
81 */
82 abstract protected int getSizeX();
83
84 /***
85 * Get the vertical number of blocks in the main editor area
86 * @return The vertical number of blocks
87 */
88 abstract protected int getSizeY();
89
90 /***
91 * Get the height number of blocks in the main editor area
92 * @return The height number of blocks
93 */
94 abstract protected int getSizeZ();
95
96 /***
97 * Get the horizontal number of blocks in the select block area
98 * @return The horizontal number of blocks
99 */
100 abstract protected int getSelectSizeX();
101 /***
102 * Get the vertical number of blocks in the select block area
103 * @return The vertical number of blocks
104 */
105 abstract protected int getSelectSizeY();
106
107 /***
108 * Get an image which is based on subimages of all blocks
109 * in the block select area
110 * @return
111 */
112 abstract protected Image getMapBlockImage();
113
114
115 protected IrregularBlockContainerInterface getMapContainer()
116 {
117 if(cont==null) {
118 cont = ((TileGameEnvironmentInterface)(getEnvironment().getCustomEnvironment())).createBlockContainer(10,10,getSizeX(),getSizeY(),getSizeZ());
119 cont.setScrollingOffsetY(cont.getPositionY(0,0,cont.getSizeZ()));
120 }
121 return cont;
122 }
123
124
125 protected IrregularBlockContainerInterface getPaletteContainer()
126 {
127 if(contPalette==null) {
128 TileGameEnvironmentInterface env = ((TileGameEnvironmentInterface)getEnvironment().getCustomEnvironment());
129 contPalette = env.createRectBlockContainer(getMapContainer().getOffsetX()+340,getMapContainer().getOffsetY(),getSelectSizeX(),getSelectSizeY(),1);
130 }
131 return contPalette;
132 }
133
134 /***
135 * Get a new block based on the specified block from the select block area
136 * @param blockNo Block number of the block to get
137 * @return A newly created block
138 */
139 protected MapObjectInterface getPaletteBlock(int blockNo)
140 {
141 if(blockNo>getFirstPaletteBlock()) {
142 MapEditorObject b = new MapEditorObject();
143 b.init(getEnvironment());
144 b.setContainer(getPaletteContainer());
145 b.setImage(getMapBlockImage(),blockNo-1);
146 b.setBlockType(blockNo);
147 return b;
148 }else {
149 return null;
150 }
151 }
152
153 /***
154 * Get block number of the first block in the select block area
155 * @return The block number
156 */
157 protected int getFirstPaletteBlock()
158 {
159 return 0;
160 }
161 /***
162 * Get the number of blocks in the select block area
163 * @return The number of blocks
164 */
165 protected int getNoOfPaletteBlocks()
166 {
167 return -1;
168 }
169 protected MapObjectContainerInterface getPaletteBlocks()
170 {
171 if(paletteBlocks==null) {
172 paletteBlocks = new MapBlockContainer(contPalette.getSizeX(),contPalette.getSizeY(),1);
173 int i=getFirstPaletteBlock();
174 for(int x=0;x<paletteBlocks.getSizeX();x++) {
175 for(int y=0;y<paletteBlocks.getSizeY();y++) {
176 if(getNoOfPaletteBlocks()==-1 || i<(getNoOfPaletteBlocks()+getFirstPaletteBlock())) {
177 MapObjectInterface b = getPaletteBlock(i);
178 if(b!=null) {
179 b.setContainer(contPalette);
180 b.setPos(x,y,0);
181 paletteBlocks.setBlock(b,x,y,0);
182 }
183 i++;
184 }else {
185 paletteBlocks.setBlock(null,x,y,0);
186 }
187 }
188 }
189 }
190 return paletteBlocks;
191 }
192
193 protected MapObjectContainerInterface getMapBlocks()
194 {
195 if(mapBlocks==null) {
196 LevelInfoInterface levelInfo = getLevelManager().getLevel(getLevelNo());
197 if(levelInfo==null) {
198 levelInfo = getLevelManager().createLevel(getLevelNo());
199 }
200 mapBlocks = levelInfo.getObjects();
201 setExtendedLevelInfo(levelInfo.getExtendedInfo());
202 }
203 return mapBlocks;
204 }
205
206
207 protected MapObjectInterface cloneBlock(MapObjectInterface block,IrregularBlockContainerInterface cont, int x, int y, int z)
208 {
209 MapObjectInterface b = (MapObjectInterface)block;
210 MapObjectInterface newBlock = null;
211 newBlock = (MapObjectInterface)b.clone();
212 newBlock.setPos(x,y,z);
213 newBlock.setContainer(cont);
214 return newBlock;
215 }
216
217 protected boolean isEmptyAllowed()
218 {
219 return true;
220 }
221
222 /***
223 * Get the text that should be shown to the user that indicates
224 * what short of object this editor makes it possible for the
225 * user to edit, for example "Level:"
226 * @return The name of the currently edited object type used in user interface
227 */
228 protected String getLevelLabelText()
229 {
230 return "Level:";
231 }
232
233 /***
234 * Get the text that should be shown to the user that indicates
235 * which height level of the map that is currently edited, for example "Height:"
236 * If this method returns null, no height spinner will be visible
237 * @return The name of the currently edited object type used in user interface
238 */
239 protected String getHeightLabelText()
240 {
241 return "Height:";
242 }
243
244 /***
245 * Get the maximum height levels of blocks
246 * @return The maximum numer of height levels of blocks
247 */
248 protected int getMaxHeight()
249 {
250 return mapBlocks!=null?mapBlocks.getSizeZ():0;
251 }
252
253 /***
254 * Get the maximum allowed number of levels/blocks
255 * @return The maximum numer of levels/blocks
256 */
257 protected int getMaxLevel()
258 {
259 return 10;
260 }
261
262 /***
263 * Creates buttons for changing currently edited level/blocks
264 * @param panel
265 */
266 protected void initLevelChangeButtons(EPanel panel)
267 {
268 EPanel p = EPanel.create(new FlowLayout());
269 ELabel label = ELabel.create(getLevelLabelText());
270 p.getContainer().add(label.getComponent());
271 levelNoSpinner = ENumberSpinner.create(levelNo,1,getMaxLevel(),1);
272 levelNoSpinner.addActionListener(new ActionListener() {
273 public void actionPerformed(ActionEvent e) {
274 loadButton();
275 }
276 });
277 p.getContainer().add(levelNoSpinner.getComponent());
278 panel.getContainer().add(p.getComponent());
279 }
280
281 /***
282 * Creates buttons for changing currently edited height level
283 * @param panel
284 */
285 protected void initHeightChangeButtons(EPanel panel)
286 {
287 EPanel p = EPanel.create(new FlowLayout());
288 ELabel label = ELabel.create(getHeightLabelText());
289 p.getContainer().add(label.getComponent());
290 heightLevelSpinner = ENumberSpinner.create(0,0,getMaxHeight(),1);
291 p.getContainer().add(heightLevelSpinner.getComponent());
292 panel.getContainer().add(p.getComponent());
293 }
294 protected void initButtons(EPanel panel)
295 {
296 initLevelChangeButtons(panel);
297 initHeightChangeButtons(panel);
298 }
299 /***
300 * Get currently edited level/block
301 * @return Block/level number of the currently edited block
302 */
303 protected int getLevelNo()
304 {
305 return levelNoSpinner.getValue();
306 }
307
308 /***
309 * Get extended information about the currently edited level/block
310 * @return Extended level/block information
311 */
312 protected ParameterSerializable getExtendedLevelInfo()
313 {
314 return extendedLevelInfo;
315 }
316 /***
317 * Set the extended information for the currently edited level/block
318 * @param info Extended level/block information
319 */
320 protected void setExtendedLevelInfo(ParameterSerializable info)
321 {
322 this.extendedLevelInfo = info;
323 }
324
325 /***
326 * Prepare the map container for save
327 * @param blocks The map container with all the blocks
328 * @return The new or unmodified map container which should be saved
329 */
330 protected MapObjectContainerInterface prepareForSave(MapObjectContainerInterface blocks)
331 {
332 return blocks;
333 }
334 protected void saveButton(MapObjectContainerInterface blocks)
335 {
336 MapObjectContainerInterface saveBlocks = prepareForSave(blocks);
337 getLevelManager().setLevel(getLevelNo(),saveBlocks,getExtendedLevelInfo());
338 }
339
340 /***
341 * Prepare the map container after loading new map data
342 * @param blocks The map container with all the blocks
343 * @return The new or unmodified map container which should be used
344 */
345 protected MapObjectContainerInterface prepareAfterLoad(MapObjectContainerInterface blocks)
346 {
347 return blocks;
348 }
349
350 protected void loadButton()
351 {
352 mapBlocks = null;
353 LevelInfoInterface levelInfo = getLevelManager().getLevel(getLevelNo());
354 if(levelInfo!=null) {
355 mapBlocks = prepareAfterLoad(levelInfo.getObjects());
356 setExtendedLevelInfo(levelInfo.getExtendedInfo());
357 }
358 updateBlocks();
359 }
360
361 protected void updateBlocks() {
362 super.updateBlocks();
363 heightLevelSpinner.setMax(mapBlocks.getSizeZ());
364 heightLevelSpinner.setValue(0);
365 }
366
367 protected int getMapPosZ() {
368 return heightLevelSpinner.getValue();
369 }
370
371 /***
372 * Gets the level manager or create a new one if it does not
373 * already exist
374 * @return The LevelManager object which we should use
375 */
376 protected abstract LevelManager getLevelManager();
377
378 public void drawSelectedFrame(Graphics g, MapObjectInterface selectedBlock) {
379 g.setColor(Color.WHITE);
380 int x1 = selectedBlock.getContainer().getPixelDrawingPositionX(selectedBlock.getPosX(),selectedBlock.getPosY(),selectedBlock.getPosZ());
381 int y1 = selectedBlock.getContainer().getPixelDrawingPositionY(selectedBlock.getPosX(),selectedBlock.getPosY(),selectedBlock.getPosZ());
382 int x2 = selectedBlock.getContainer().getPixelDrawingPositionX(selectedBlock.getPosX(),selectedBlock.getPosY()+1,selectedBlock.getPosZ());
383 int y2 = selectedBlock.getContainer().getPixelDrawingPositionY(selectedBlock.getPosX(),selectedBlock.getPosY()+1,selectedBlock.getPosZ());
384 int x3 = selectedBlock.getContainer().getPixelDrawingPositionX(selectedBlock.getPosX()+1,selectedBlock.getPosY(),selectedBlock.getPosZ());
385 int y3 = selectedBlock.getContainer().getPixelDrawingPositionY(selectedBlock.getPosX()+1,selectedBlock.getPosY(),selectedBlock.getPosZ());
386 int x4 = selectedBlock.getContainer().getPixelDrawingPositionX(selectedBlock.getPosX()+1,selectedBlock.getPosY()+1,selectedBlock.getPosZ());
387 int y4 = selectedBlock.getContainer().getPixelDrawingPositionY(selectedBlock.getPosX()+1,selectedBlock.getPosY()+1,selectedBlock.getPosZ());
388 g.drawLine(x1,y1,x2,y2);
389 g.drawLine(x1,y1,x3,y3);
390 g.drawLine(x4,y4,x2,y2);
391 g.drawLine(x4,y4,x3,y3);
392 }
393
394 public void drawHoveringFrame(Graphics g, int posX, int posY) {
395 g.setColor(Color.WHITE);
396 int x1 = getMapContainer().getPixelDrawingPositionX(posX,posY,getMapPosZ());
397 int y1 = getMapContainer().getPixelDrawingPositionY(posX,posY,getMapPosZ());
398 int x2 = getMapContainer().getPixelDrawingPositionX(posX,posY+1,getMapPosZ());
399 int y2 = getMapContainer().getPixelDrawingPositionY(posX,posY+1,getMapPosZ());
400 int x3 = getMapContainer().getPixelDrawingPositionX(posX+1,posY,getMapPosZ());
401 int y3 = getMapContainer().getPixelDrawingPositionY(posX+1,posY,getMapPosZ());
402 int x4 = getMapContainer().getPixelDrawingPositionX(posX+1,posY+1,getMapPosZ());
403 int y4 = getMapContainer().getPixelDrawingPositionY(posX+1,posY+1,getMapPosZ());
404 g.drawLine(x1,y1,x2,y2);
405 g.drawLine(x1,y1,x3,y3);
406 g.drawLine(x4,y4,x2,y2);
407 g.drawLine(x4,y4,x3,y3);
408 }
409 }