1 // -----------------------------------------------
3 // -----------------------------------------------
4 // Built-in map editor (totally l33t!)
5 // -----------------------------------------------
6 // By Kronoman - Copyright (c) 2003
7 // In loving memory of my father
8 // -----------------------------------------------
15 CMapEditor::CMapEditor()
17 mtracer
.add("CMapEditor::CMapEditor()");
26 ykprint
= ckprint
= 0;
32 CMapEditor::~CMapEditor()
34 // debug, source need here? maybe... somebody call 911
35 mtracer
.add("CMapEditor::~CMapEditor()");
38 // -----------------------------------------------
40 // -----------------------------------------------
41 void CMapEditor::kprint(char *msg
)
43 textout_ex(screen
, font
, msg
, 0, ykprint
, ckprint
, -1);
44 ykprint
+= text_height(font
);
47 void CMapEditor::map_editor_help_message()
50 ckprint
= makecol(255,255,0);
53 kprint("Map Editor - Help");
54 kprint("-----------------");
58 ckprint
= makecol(128,128,255);
59 kprint("Copyright (c) 2003, 2004, Kronoman");
60 kprint("In loving memory of my father");
65 ckprint
= makecol(255,255,255);
70 kprint("Arrow keys: scroll the map; press SHIFT+Arrow keys for faster scroll.");
72 kprint("Left mouse button or ENTER: set pointed tile to current selected tile type.");
74 kprint("Right mouse button or DELETE: delete tile on that area.");
76 kprint("Middle mouse button or SPACE: set start position for player.");
78 kprint("Z,X or mouse wheel: select tile type to use. (Mouse cursor will reflect changes)");
80 kprint("F: find player start position.");
82 kprint("G: toggle drawing of grid.");
84 kprint("C: clear current map.");
86 kprint("P: set map properties (TIME, etc)");
88 kprint("S: save current map to a file.");
90 kprint("L: load map from a file.");
92 kprint("V: toggle 'show only current layer'");
94 kprint("D: dump tile set configuration to text file \"TILE_SET_CFG.TXT\"");
96 kprint("I: show information about current selected tile");
98 kprint("B: select background image for this level.");
100 kprint("M: select background music for this level.");
102 kprint("PLUS (+) and MINUS (-): change current layer in edition");
104 kprint("ESC: exit map editor.");
106 kprint("F1: show this help");
109 ckprint
= makecol(128,128,128);
110 kprint("-- Press any key to continue --");
116 // layer = layer to redraw, or -1 for full layers
117 // grid = true/false (draw or not the grid)
118 void CMapEditor::redraw_the_tile_map(int layer
, bool grid
)
120 clear_bitmap(dbuffer
);
122 clear_scene(dbuffer
); // clear 3D scene zbuffer
125 game_map
.draw_map(dbuffer
, tx
, ty
, SCREEN_W
, SCREEN_H
, layer
, grid
); // draw it
129 for (int l
=0; l
< MAP_LAYERS
; l
++)
130 game_map
.draw_map(dbuffer
, tx
, ty
, SCREEN_W
, SCREEN_H
, l
, grid
); // draw it
132 render_scene(); // render the 3D scene to the bitmap
135 blit(dbuffer
, screen
,0,0,0,0,dbuffer
->w
,dbuffer
->h
);
139 void CMapEditor::do_change_mouse_cursor()
141 // set mouse cursor on the tile to put, and also, show it
142 if (game_map
.tile_set
[ts
].spr
!= NULL
)
144 stretch_blit(game_map
.tile_set
[ts
].spr
, mcursor
, 0,0,game_map
.tile_set
[ts
].spr
->w
, game_map
.tile_set
[ts
].spr
->h
,0,0, mcursor
->w
,mcursor
->h
);
148 clear_to_color(mcursor
, makecol(255,0,255));
151 textout_ex(mcursor
, font
, "CLS", 0, 0, makecol(128,128,255), -1);
153 textprintf_ex(mcursor
, font
, 0,0,makecol(255,0,0),-1, "%d", ts
);
155 set_mouse_sprite(mcursor
);
159 // -----------------------------------------------
160 // Map edit entry point
161 // -----------------------------------------------
162 void CMapEditor::start_map_editor()
167 int omx
=0,omy
=0,old_mouse_z
;
170 usprintf(str
, "levels");
172 mtracer
.add("CMapEditor::start_map_editor()");
174 dbuffer
= create_bitmap(SCREEN_W
, SCREEN_H
);
176 raise_error("ERROR: unable to create doble buffer bitmap!\n");
178 mcursor
= create_bitmap(32,32);
180 raise_error("ERROR: unable to create mouse cursor!\n");
182 clear_bitmap(screen
);
183 clear_bitmap(mcursor
);
184 clear_bitmap(dbuffer
);
188 textout_centre_ex(screen
, font
, "[Map Editor]-[ Please wait... loading... ]", SCREEN_W
/2, SCREEN_H
/2, makecol(255,255,255), makecol(0,64,0));
190 char tmp_file_buf
[2048];
191 if (game_map
.load_tile_set_from_file(where_is_the_filename(tmp_file_buf
,TILESET_FILE
)) )
192 raise_error("ERROR! Can't load \"%s\" file!\n", TILESET_FILE
); // load tileset
194 game_map
.empty_the_map(); // reset the map
195 tx
= 0, ty
= 0; // current scroll in the map
196 ts
= 1; // current tile selected from the tile set (1..255)
197 tl
= 0; // current layer of map selected 0..MAP_LAYERS-1 (MAP_LAYERS in tmap.h)
199 redraw_the_tile_map(-1, draw_grid
);
200 textout_centre_ex(screen
, font
, "[ Map editor - Press F1 for help ]", SCREEN_W
/2, SCREEN_H
/2, makecol(255,255,0),makecol(128,0,0));
201 do_change_mouse_cursor();
203 // go to map start point
204 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
205 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
214 redraw_the_tile_map(tl
,draw_grid
);
216 redraw_the_tile_map(-1,draw_grid
);
222 textprintf_ex(screen
, font
, 0,0,makecol(255,255,255), makecol(0,0,0), "[%03d,%03d]-[%3d]-[L:%2d(%c)]", tx
/TMAPS_W
,ty
/TMAPS_H
,ts
,tl
, socl
? 'X' : ' ');
224 old_mouse_z
= mouse_z
;
225 while (!keypressed() && !mouse_b
&&mouse_z
== old_mouse_z
) // wait until user action
227 if (keyboard_needs_poll())
229 if (mouse_needs_poll())
231 //yield_timeslice(); // play nice with multitasking
234 if (omx
!= mouse_x
/10 || omy
!= mouse_y
/10)
237 textprintf_ex(screen
, font
, 0,text_height(font
),makecol(128,255,128), makecol(0,0,0), "[%03d,%03d]", (tx
+mouse_x
)/TMAPS_W
, (ty
+mouse_y
)/TMAPS_H
);
239 // div by 10 to get few precission
245 if (mouse_b
& 1 || key
[KEY_ENTER
]) // click of left mouse == set the tile
247 // DEBUG : NOTICE : if the tile is a prize, it always go on tile 1, so the player can pickup it
248 game_map
.set_tile_type((tx
+mouse_x
)/TMAPS_W
, (ty
+mouse_y
)/TMAPS_H
, (game_map
.tile_set
[ts
].is_a_prize
) ? 1 : tl
, ts
);
252 if (mouse_needs_poll())
255 ; // wait until mouse release
258 if (mouse_b
& 2 || key
[KEY_DEL
]) // click of right mouse == clear the tile
260 game_map
.set_tile_type((tx
+mouse_x
)/TMAPS_W
, (ty
+mouse_y
)/TMAPS_H
,tl
, 0);
264 if (mouse_needs_poll())
267 ; // wait until mouse release
270 if (mouse_b
& 4 || key
[KEY_SPACE
]) // change the start pos of the player
272 game_map
.sxp
= (tx
+mouse_x
)/TMAPS_W
;
273 game_map
.syp
= (ty
+mouse_y
)/TMAPS_H
;
274 if (game_map
.sxp
< 0)
276 if (game_map
.sxp
> 255)
278 if (game_map
.syp
< 0)
280 if (game_map
.syp
> 255)
285 if (mouse_needs_poll())
288 ; // wait until mouse release
291 // with shift, you move faster
293 if (key_shifts
& KB_SHIFT_FLAG
)
318 // without it, slower
341 if (key
[KEY_X
] || mouse_z
> old_mouse_z
) // change tile selected
346 do_change_mouse_cursor();
349 if (key
[KEY_Z
] || mouse_z
< old_mouse_z
) // change tile selected
354 do_change_mouse_cursor();
357 if (key
[KEY_ESC
] ) // exit editor
359 set_mouse_sprite(NULL
);
360 if (alert("Exit map editor", "Are you sure?", NULL
, "Yes", "No", 'y', 'n') == 1)
362 do_change_mouse_cursor();
365 if (key
[KEY_I
]) // show info about current tile
367 set_mouse_sprite(NULL
);
369 ckprint
= makecol(255,255,255);
371 clear_bitmap(screen
);
372 kprint("Info about tile");
376 if (game_map
.tile_set
[ts
].spr
!= NULL
)
378 draw_sprite(screen
, game_map
.tile_set
[ts
].spr
, 0, ykprint
);
379 ykprint
+= (int)(game_map
.tile_set
[ts
].spr
->w
*1.1);
380 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Sprite: %s", game_map
.tile_set
[ts
].spr_name
);
383 kprint("This tile don't has sprite defined");
387 if (game_map
.tile_set
[ts
].sound
!= NULL
)
388 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
, -1, "Sound: %s", game_map
.tile_set
[ts
].sound_name
);
392 if (game_map
.tile_set
[ts
].exit_level
)
393 kprint("Is a level exit block");
397 if (game_map
.tile_set
[ts
].solid
)
399 kprint("Is a solid wall");
400 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Bounce factor: %f", game_map
.tile_set
[ts
].bounce_factor
);
405 if (game_map
.tile_set
[ts
].is_a_prize
)
407 kprint("Is a prize");
408 if (game_map
.tile_set
[ts
].indispensable
)
409 kprint("Is indispensable for grant level exit");
413 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Score: %d", game_map
.tile_set
[ts
].score
);
418 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Add factor : x:%f, y:%f, z:%f", game_map
.tile_set
[ts
].adx
, game_map
.tile_set
[ts
].ady
, game_map
.tile_set
[ts
].adz
);
422 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Multiplier factor: x:%f, y:%f, z:%f", game_map
.tile_set
[ts
].mdx
, game_map
.tile_set
[ts
].mdy
, game_map
.tile_set
[ts
].mdz
);
427 kprint("-- Press any key to continue --");
434 do_change_mouse_cursor();
438 if (key
[KEY_B
]) // select background
442 set_mouse_sprite(NULL
);
444 ckprint
= makecol(255,255,0);
447 while (t
!= KEY_ENTER
)
450 clear_bitmap(screen
);
451 kprint("Select background with arrow keys, and press ENTER");
453 textprintf_ex(screen
, font
, 0, 32, makecol(255,255,255),-1,"Current: %d", game_map
.background_index
);
455 // show the current one
456 blit(background
.get_background("backgr.dat", game_map
.background_index
), screen
, 0,0,0,64,SCREEN_W
, SCREEN_H
);
460 if (t
== KEY_UP
|| t
== KEY_LEFT
)
461 game_map
.background_index
--;
462 if (t
== KEY_DOWN
|| t
== KEY_RIGHT
)
463 game_map
.background_index
++;
465 game_map
.background_index
-=10;
467 game_map
.background_index
+=10;
468 if (game_map
.background_index
< 0)
469 game_map
.background_index
= 255;
470 if (game_map
.background_index
> 255)
471 game_map
.background_index
= 0;
475 do_change_mouse_cursor();
479 if (key
[KEY_M
]) // select music
483 set_mouse_sprite(NULL
);
485 ckprint
= makecol(255,255,0);
488 while (t
!= KEY_ENTER
)
491 clear_bitmap(screen
);
492 kprint("Select music with arrow keys, and press ENTER ; hit SPACE to play/stop the song");
494 textprintf_ex(screen
, font
, 0, 32, makecol(255,255,255),-1,"Current: %d", game_map
.music_index
);
500 if (t
== KEY_UP
|| t
== KEY_LEFT
)
501 game_map
.music_index
--;
503 if (t
== KEY_DOWN
|| t
== KEY_RIGHT
)
504 game_map
.music_index
++;
507 game_map
.music_index
-=10;
510 game_map
.music_index
+=10;
512 if (game_map
.music_index
< 0)
513 game_map
.music_index
= 255;
515 if (game_map
.music_index
> 255)
516 game_map
.music_index
= 0;
521 CSoundWrapper soundw
; // sound system
522 CMusicLvl music_loader
; // loader system for music from datafile
523 DUH
*mm
= music_loader
.get_music("music_l.dat", game_map
.music_index
);
527 kprint("Sorry, can't play that tune ; must be non existant");
529 kprint("-- press any key --");
536 kprint("Now playing tune...");
537 kprint("-- press any key to stop--");
539 soundw
.music_load(mm
);
541 soundw
.music_start();
545 while (!keypressed())
553 music_loader
.free_memory();
559 do_change_mouse_cursor();
563 if (key
[KEY_C
] ) // clear map with C
565 set_mouse_sprite(NULL
);
566 if (alert("Clear the map", "Are you sure?", NULL
, "Yes", "No", 'y', 'n') == 1)
568 game_map
.empty_the_map();
571 do_change_mouse_cursor();
574 if (key
[KEY_S
]) // save map
576 set_mouse_sprite(NULL
);
577 if (file_select_ex("Save map to file", str
, NULL
, 2048, (int)(SCREEN_W
*0.85), (int)(SCREEN_H
*0.85)))
579 if (game_map
.save_map_to_file(str
))
582 alert("ERROR", "File saving failed :(", NULL
, "OK", NULL
, 0,0);
587 alert("SUCESS", "File saved! :^D", NULL
, "Great!", NULL
, 0,0);
590 do_change_mouse_cursor();
593 if (key
[KEY_L
]) // load map - THIS IS DESTRUCTIVE, IF FAILS, IT WILL CORRUPT CURRENT MAP!!!
595 set_mouse_sprite(NULL
);
596 if (alert("Warning!", "If file load fails,", "your MAP will be reset to empty!", "Continue", "Cancel", 0,0) == 1)
598 if (file_select_ex("Load map from file", str
, NULL
, 2048, (int)(SCREEN_W
*0.85), (int)(SCREEN_H
*0.85)))
600 if (game_map
.load_map_from_file(str
))
603 alert("ERROR", "File load failed :(", "Your MAP probably has garbage, clear it with 'C' key!", "Crap!", NULL
, 0,0);
608 alert("SUCESS", "File loaded! :^D", NULL
, "Great!", NULL
, 0,0);
609 // go to map entry point
610 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
611 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
616 do_change_mouse_cursor();
619 if (key
[KEY_D
]) // dump tile settings to file
621 set_mouse_sprite(NULL
);
622 if (alert("Dump tile settings", "Dump tile set settings to file?","File will be TILE_SET_CFG.TXT", "Do it", "Cancel", 0,0) == 1)
625 textout_centre_ex(screen
, font
, "Please wait... writing file...", SCREEN_W
/2, SCREEN_H
/2, makecol(255,255,255), makecol(128,0,0));
627 game_map
.save_tile_set_config_to_file("TILE_SET_CFG.TXT");
628 alert("SUCESS", "File saved as TILE_SET_CFG.TXT", NULL
, "OK", NULL
, 0,0);
632 do_change_mouse_cursor();
635 if (key
[KEY_G
] ) // toggle grid
637 draw_grid
= !draw_grid
;
641 if (key
[KEY_F
] ) // goto player's start point
643 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
644 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
650 set_mouse_sprite(NULL
);
651 map_editor_help_message();
652 do_change_mouse_cursor();
656 if (key
[KEY_V
]) // toggle 'show only current layer'
663 if (key
[KEY_PLUS_PAD
] || key
[KEY_EQUALS
]) // keypad plus + = change edit layer
669 if (key
[KEY_MINUS_PAD
] || key
[KEY_MINUS
]) // keypad plus - = change edit layer
676 if (key
[KEY_P
]) // set map properties (time, etc)
678 char st1
[255], st2
[255]; // d_edit_buffers
679 int it1
= 0, it2
= 0;
680 // dialog to set time
681 DIALOG set_time_dlg
[] =
683 /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
684 { d_box_proc
, 0, 0, 216, 104, 0, 0, 0, 0, 0, 0, NULL
, NULL
, NULL
},
685 { d_text_proc
, 8, 8, 144, 8, 0, 0, 0, 0, 0, 0, (void *)"Set map properties", NULL
, NULL
},
686 { d_text_proc
, 8, 24, 40, 16, 0, 0, 0, 0, 0, 0, (void *)"Time to complete the map:", NULL
, NULL
},
687 { d_text_proc
, 8, 40, 56, 16, 0, 0, 0, 0, 0, 0, (void *)"Minutes:", NULL
, NULL
},
688 { d_text_proc
, 8, 56, 56, 16, 0, 0, 0, 0, 0, 0, (void *)"Seconds:", NULL
, NULL
},
689 { d_edit_proc
, 88, 40, 56, 16, 0, 0, 0, 0, 3, 0, (void *)"edit", NULL
, NULL
},
690 { d_edit_proc
, 88, 56, 56, 16, 0, 0, 0, 0, 2, 0, (void *)"edit", NULL
, NULL
},
691 { d_button_proc
, 8, 72, 200, 24, 0, 0, 0, D_EXIT
, 0, 0, (void *)"OK", NULL
, NULL
},
692 { NULL
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL
, NULL
, NULL
}
696 usprintf(st1
, "%d", game_map
.time_m
);
697 usprintf(st2
, "%d", game_map
.time_s
);
698 set_time_dlg
[5].dp
= st1
;
699 set_time_dlg
[6].dp
= st2
;
702 set_mouse_sprite(NULL
);
703 set_dialog_color(set_time_dlg
, makecol(0,0,0), makecol(255,255,255));
704 centre_dialog(set_time_dlg
);
705 popup_dialog(set_time_dlg
, -1);
710 if (it1
>= 0 && it2
>= 0 && it1
< 256 && it2
<= 60)
713 game_map
.time_m
= it1
;
714 game_map
.time_s
= it2
;
715 usprintf(st1
, "Time of map set to %d:%d", game_map
.time_m
, game_map
.time_s
);
716 alert("Done", st1
, NULL
, "OK", NULL
, 0,0);
720 alert("ERROR", "Range of input invalid", "Valid: 0 <= minutes <= 255, and 0 <= seconds <= 60", "OK", NULL
, 0,0);
723 do_change_mouse_cursor();
730 if (tl
> MAP_LAYERS
-1)
737 if (tx
> TMAP_SIZE
*TMAPS_W
-SCREEN_W
)
738 tx
= TMAP_SIZE
* TMAPS_W
-SCREEN_W
;
739 if (ty
> TMAP_SIZE
*TMAPS_H
-SCREEN_H
)
740 ty
= TMAP_SIZE
* TMAPS_H
-SCREEN_H
;
746 destroy_bitmap(dbuffer
);
747 destroy_bitmap(mcursor
);
748 game_map
.free_memory();
749 set_mouse_sprite(NULL
);