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
;
171 char *home
= getenv("HOME");
175 snprintf(dir
, sizeof(dir
), "%s/.kball", home
);
176 mkdir(dir
, S_IRWXU
| S_IRWXG
| S_IROTH
| S_IXOTH
);
177 snprintf(dir
, sizeof(dir
), "%s/.kball/levels", home
);
178 mkdir(dir
, S_IRWXU
| S_IRWXG
| S_IROTH
| S_IXOTH
);
179 usprintf(str
, "%s/.kball/levels/", home
);
183 usprintf(str
, "levels");
186 mtracer
.add("CMapEditor::start_map_editor()");
188 dbuffer
= create_bitmap(SCREEN_W
, SCREEN_H
);
190 raise_error("ERROR: unable to create doble buffer bitmap!\n");
192 mcursor
= create_bitmap(32,32);
194 raise_error("ERROR: unable to create mouse cursor!\n");
196 clear_bitmap(screen
);
197 clear_bitmap(mcursor
);
198 clear_bitmap(dbuffer
);
202 textout_centre_ex(screen
, font
, "[Map Editor]-[ Please wait... loading... ]", SCREEN_W
/2, SCREEN_H
/2, makecol(255,255,255), makecol(0,64,0));
204 char tmp_file_buf
[2048];
205 if (game_map
.load_tile_set_from_file(where_is_the_filename(tmp_file_buf
,TILESET_FILE
)) )
206 raise_error("ERROR! Can't load \"%s\" file!\n", TILESET_FILE
); // load tileset
208 game_map
.empty_the_map(); // reset the map
209 tx
= 0, ty
= 0; // current scroll in the map
210 ts
= 1; // current tile selected from the tile set (1..255)
211 tl
= 0; // current layer of map selected 0..MAP_LAYERS-1 (MAP_LAYERS in tmap.h)
213 redraw_the_tile_map(-1, draw_grid
);
214 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));
215 do_change_mouse_cursor();
217 // go to map start point
218 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
219 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
228 redraw_the_tile_map(tl
,draw_grid
);
230 redraw_the_tile_map(-1,draw_grid
);
236 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' : ' ');
238 old_mouse_z
= mouse_z
;
239 while (!keypressed() && !mouse_b
&&mouse_z
== old_mouse_z
) // wait until user action
241 if (keyboard_needs_poll())
243 if (mouse_needs_poll())
245 //yield_timeslice(); // play nice with multitasking
248 if (omx
!= mouse_x
/10 || omy
!= mouse_y
/10)
251 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
);
253 // div by 10 to get few precission
259 if (mouse_b
& 1 || key
[KEY_ENTER
]) // click of left mouse == set the tile
261 // DEBUG : NOTICE : if the tile is a prize, it always go on tile 1, so the player can pickup it
262 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
);
266 if (mouse_needs_poll())
269 ; // wait until mouse release
272 if (mouse_b
& 2 || key
[KEY_DEL
]) // click of right mouse == clear the tile
274 game_map
.set_tile_type((tx
+mouse_x
)/TMAPS_W
, (ty
+mouse_y
)/TMAPS_H
,tl
, 0);
278 if (mouse_needs_poll())
281 ; // wait until mouse release
284 if (mouse_b
& 4 || key
[KEY_SPACE
]) // change the start pos of the player
286 game_map
.sxp
= (tx
+mouse_x
)/TMAPS_W
;
287 game_map
.syp
= (ty
+mouse_y
)/TMAPS_H
;
288 if (game_map
.sxp
< 0)
290 if (game_map
.sxp
> 255)
292 if (game_map
.syp
< 0)
294 if (game_map
.syp
> 255)
299 if (mouse_needs_poll())
302 ; // wait until mouse release
305 // with shift, you move faster
307 if (key_shifts
& KB_SHIFT_FLAG
)
332 // without it, slower
355 if (key
[KEY_X
] || mouse_z
> old_mouse_z
) // change tile selected
360 do_change_mouse_cursor();
363 if (key
[KEY_Z
] || mouse_z
< old_mouse_z
) // change tile selected
368 do_change_mouse_cursor();
371 if (key
[KEY_ESC
] ) // exit editor
373 set_mouse_sprite(NULL
);
374 if (alert("Exit map editor", "Are you sure?", NULL
, "Yes", "No", 'y', 'n') == 1)
376 do_change_mouse_cursor();
379 if (key
[KEY_I
]) // show info about current tile
381 set_mouse_sprite(NULL
);
383 ckprint
= makecol(255,255,255);
385 clear_bitmap(screen
);
386 kprint("Info about tile");
390 if (game_map
.tile_set
[ts
].spr
!= NULL
)
392 draw_sprite(screen
, game_map
.tile_set
[ts
].spr
, 0, ykprint
);
393 ykprint
+= (int)(game_map
.tile_set
[ts
].spr
->w
*1.1);
394 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Sprite: %s", game_map
.tile_set
[ts
].spr_name
);
397 kprint("This tile don't has sprite defined");
401 if (game_map
.tile_set
[ts
].sound
!= NULL
)
402 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
, -1, "Sound: %s", game_map
.tile_set
[ts
].sound_name
);
406 if (game_map
.tile_set
[ts
].exit_level
)
407 kprint("Is a level exit block");
411 if (game_map
.tile_set
[ts
].solid
)
413 kprint("Is a solid wall");
414 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Bounce factor: %f", game_map
.tile_set
[ts
].bounce_factor
);
419 if (game_map
.tile_set
[ts
].is_a_prize
)
421 kprint("Is a prize");
422 if (game_map
.tile_set
[ts
].indispensable
)
423 kprint("Is indispensable for grant level exit");
427 textprintf_ex(screen
, font
, 0, ykprint
+=text_height(font
), ckprint
,-1, "Score: %d", game_map
.tile_set
[ts
].score
);
432 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
);
436 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
);
441 kprint("-- Press any key to continue --");
448 do_change_mouse_cursor();
452 if (key
[KEY_B
]) // select background
456 set_mouse_sprite(NULL
);
458 ckprint
= makecol(255,255,0);
461 while (t
!= KEY_ENTER
)
464 clear_bitmap(screen
);
465 kprint("Select background with arrow keys, and press ENTER");
467 textprintf_ex(screen
, font
, 0, 32, makecol(255,255,255),-1,"Current: %d", game_map
.background_index
);
469 // show the current one
470 blit(background
.get_background("backgr.dat", game_map
.background_index
), screen
, 0,0,0,64,SCREEN_W
, SCREEN_H
);
474 if (t
== KEY_UP
|| t
== KEY_LEFT
)
475 game_map
.background_index
--;
476 if (t
== KEY_DOWN
|| t
== KEY_RIGHT
)
477 game_map
.background_index
++;
479 game_map
.background_index
-=10;
481 game_map
.background_index
+=10;
482 if (game_map
.background_index
< 0)
483 game_map
.background_index
= 255;
484 if (game_map
.background_index
> 255)
485 game_map
.background_index
= 0;
489 do_change_mouse_cursor();
493 if (key
[KEY_M
]) // select music
497 set_mouse_sprite(NULL
);
499 ckprint
= makecol(255,255,0);
502 while (t
!= KEY_ENTER
)
505 clear_bitmap(screen
);
506 kprint("Select music with arrow keys, and press ENTER ; hit SPACE to play/stop the song");
508 textprintf_ex(screen
, font
, 0, 32, makecol(255,255,255),-1,"Current: %d", game_map
.music_index
);
514 if (t
== KEY_UP
|| t
== KEY_LEFT
)
515 game_map
.music_index
--;
517 if (t
== KEY_DOWN
|| t
== KEY_RIGHT
)
518 game_map
.music_index
++;
521 game_map
.music_index
-=10;
524 game_map
.music_index
+=10;
526 if (game_map
.music_index
< 0)
527 game_map
.music_index
= 255;
529 if (game_map
.music_index
> 255)
530 game_map
.music_index
= 0;
535 CSoundWrapper soundw
; // sound system
536 CMusicLvl music_loader
; // loader system for music from datafile
537 DUH
*mm
= music_loader
.get_music("music_l.dat", game_map
.music_index
);
541 kprint("Sorry, can't play that tune ; must be non existant");
543 kprint("-- press any key --");
550 kprint("Now playing tune...");
551 kprint("-- press any key to stop--");
553 soundw
.music_load(mm
);
555 soundw
.music_start();
559 while (!keypressed())
567 music_loader
.free_memory();
573 do_change_mouse_cursor();
577 if (key
[KEY_C
] ) // clear map with C
579 set_mouse_sprite(NULL
);
580 if (alert("Clear the map", "Are you sure?", NULL
, "Yes", "No", 'y', 'n') == 1)
582 game_map
.empty_the_map();
585 do_change_mouse_cursor();
588 if (key
[KEY_S
]) // save map
590 set_mouse_sprite(NULL
);
591 if (file_select_ex("Save map to file", str
, NULL
, 2048, (int)(SCREEN_W
*0.85), (int)(SCREEN_H
*0.85)))
593 if (game_map
.save_map_to_file(str
))
596 alert("ERROR", "File saving failed :(", NULL
, "OK", NULL
, 0,0);
601 alert("SUCESS", "File saved! :^D", NULL
, "Great!", NULL
, 0,0);
604 do_change_mouse_cursor();
607 if (key
[KEY_L
]) // load map - THIS IS DESTRUCTIVE, IF FAILS, IT WILL CORRUPT CURRENT MAP!!!
609 set_mouse_sprite(NULL
);
610 if (alert("Warning!", "If file load fails,", "your MAP will be reset to empty!", "Continue", "Cancel", 0,0) == 1)
612 if (file_select_ex("Load map from file", str
, NULL
, 2048, (int)(SCREEN_W
*0.85), (int)(SCREEN_H
*0.85)))
614 if (game_map
.load_map_from_file(str
))
617 alert("ERROR", "File load failed :(", "Your MAP probably has garbage, clear it with 'C' key!", "Crap!", NULL
, 0,0);
622 alert("SUCESS", "File loaded! :^D", NULL
, "Great!", NULL
, 0,0);
623 // go to map entry point
624 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
625 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
630 do_change_mouse_cursor();
633 if (key
[KEY_D
]) // dump tile settings to file
635 set_mouse_sprite(NULL
);
636 if (alert("Dump tile settings", "Dump tile set settings to file?","File will be TILE_SET_CFG.TXT", "Do it", "Cancel", 0,0) == 1)
639 textout_centre_ex(screen
, font
, "Please wait... writing file...", SCREEN_W
/2, SCREEN_H
/2, makecol(255,255,255), makecol(128,0,0));
641 game_map
.save_tile_set_config_to_file("TILE_SET_CFG.TXT");
642 alert("SUCESS", "File saved as TILE_SET_CFG.TXT", NULL
, "OK", NULL
, 0,0);
646 do_change_mouse_cursor();
649 if (key
[KEY_G
] ) // toggle grid
651 draw_grid
= !draw_grid
;
655 if (key
[KEY_F
] ) // goto player's start point
657 tx
= (game_map
.sxp
-(SCREEN_W
/2/TMAPS_W
)) * TMAPS_W
;
658 ty
= (game_map
.syp
-(SCREEN_H
/2/TMAPS_H
)) * TMAPS_H
;
664 set_mouse_sprite(NULL
);
665 map_editor_help_message();
666 do_change_mouse_cursor();
670 if (key
[KEY_V
]) // toggle 'show only current layer'
677 if (key
[KEY_PLUS_PAD
] || key
[KEY_EQUALS
]) // keypad plus + = change edit layer
683 if (key
[KEY_MINUS_PAD
] || key
[KEY_MINUS
]) // keypad plus - = change edit layer
690 if (key
[KEY_P
]) // set map properties (time, etc)
692 char st1
[255], st2
[255]; // d_edit_buffers
693 int it1
= 0, it2
= 0;
694 // dialog to set time
695 DIALOG set_time_dlg
[] =
697 /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
698 { d_box_proc
, 0, 0, 216, 104, 0, 0, 0, 0, 0, 0, NULL
, NULL
, NULL
},
699 { d_text_proc
, 8, 8, 144, 8, 0, 0, 0, 0, 0, 0, (void *)"Set map properties", NULL
, NULL
},
700 { d_text_proc
, 8, 24, 40, 16, 0, 0, 0, 0, 0, 0, (void *)"Time to complete the map:", NULL
, NULL
},
701 { d_text_proc
, 8, 40, 56, 16, 0, 0, 0, 0, 0, 0, (void *)"Minutes:", NULL
, NULL
},
702 { d_text_proc
, 8, 56, 56, 16, 0, 0, 0, 0, 0, 0, (void *)"Seconds:", NULL
, NULL
},
703 { d_edit_proc
, 88, 40, 56, 16, 0, 0, 0, 0, 3, 0, (void *)"edit", NULL
, NULL
},
704 { d_edit_proc
, 88, 56, 56, 16, 0, 0, 0, 0, 2, 0, (void *)"edit", NULL
, NULL
},
705 { d_button_proc
, 8, 72, 200, 24, 0, 0, 0, D_EXIT
, 0, 0, (void *)"OK", NULL
, NULL
},
706 { NULL
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL
, NULL
, NULL
}
710 usprintf(st1
, "%d", game_map
.time_m
);
711 usprintf(st2
, "%d", game_map
.time_s
);
712 set_time_dlg
[5].dp
= st1
;
713 set_time_dlg
[6].dp
= st2
;
716 set_mouse_sprite(NULL
);
717 set_dialog_color(set_time_dlg
, makecol(0,0,0), makecol(255,255,255));
718 centre_dialog(set_time_dlg
);
719 popup_dialog(set_time_dlg
, -1);
724 if (it1
>= 0 && it2
>= 0 && it1
< 256 && it2
<= 60)
727 game_map
.time_m
= it1
;
728 game_map
.time_s
= it2
;
729 usprintf(st1
, "Time of map set to %d:%d", game_map
.time_m
, game_map
.time_s
);
730 alert("Done", st1
, NULL
, "OK", NULL
, 0,0);
734 alert("ERROR", "Range of input invalid", "Valid: 0 <= minutes <= 255, and 0 <= seconds <= 60", "OK", NULL
, 0,0);
737 do_change_mouse_cursor();
744 if (tl
> MAP_LAYERS
-1)
751 if (tx
> TMAP_SIZE
*TMAPS_W
-SCREEN_W
)
752 tx
= TMAP_SIZE
* TMAPS_W
-SCREEN_W
;
753 if (ty
> TMAP_SIZE
*TMAPS_H
-SCREEN_H
)
754 ty
= TMAP_SIZE
* TMAPS_H
-SCREEN_H
;
760 destroy_bitmap(dbuffer
);
761 destroy_bitmap(mcursor
);
762 game_map
.free_memory();
763 set_mouse_sprite(NULL
);