Store levels edited by the user in $HOME
[kball.git] / src / mapedit.cpp
blob4fa11fd68cf9c96eccb15fdc8f148f911625b23f
1 // -----------------------------------------------
2 // mapedit.cpp
3 // -----------------------------------------------
4 // Built-in map editor (totally l33t!)
5 // -----------------------------------------------
6 // By Kronoman - Copyright (c) 2003
7 // In loving memory of my father
8 // -----------------------------------------------
10 #include "mapedit.h"
11 #include "filehelp.h"
12 #include "sound.h"
13 #include "musiclvl.h"
15 CMapEditor::CMapEditor()
17 mtracer.add("CMapEditor::CMapEditor()");
19 tx = ty = 0;
20 ts = 1;
21 tl = 0;
23 dbuffer = NULL;
24 mcursor = NULL;
26 ykprint = ckprint = 0;
28 draw_grid = true;
32 CMapEditor::~CMapEditor()
34 // debug, source need here? maybe... somebody call 911
35 mtracer.add("CMapEditor::~CMapEditor()");
38 // -----------------------------------------------
39 // Helper functions
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()
49 ykprint = 0;
50 ckprint = makecol(255,255,0);
51 scare_mouse();
52 clear_bitmap(screen);
53 kprint("Map Editor - Help");
54 kprint("-----------------");
55 kprint("");
56 kprint("");
58 ckprint = makecol(128,128,255);
59 kprint("Copyright (c) 2003, 2004, Kronoman");
60 kprint("In loving memory of my father");
62 kprint("");
63 kprint("");
65 ckprint = makecol(255,255,255);
66 kprint("Reference:");
67 kprint("----------");
68 kprint("");
69 kprint("");
70 kprint("Arrow keys: scroll the map; press SHIFT+Arrow keys for faster scroll.");
71 kprint("");
72 kprint("Left mouse button or ENTER: set pointed tile to current selected tile type.");
73 kprint("");
74 kprint("Right mouse button or DELETE: delete tile on that area.");
75 kprint("");
76 kprint("Middle mouse button or SPACE: set start position for player.");
77 kprint("");
78 kprint("Z,X or mouse wheel: select tile type to use. (Mouse cursor will reflect changes)");
79 kprint("");
80 kprint("F: find player start position.");
81 kprint("");
82 kprint("G: toggle drawing of grid.");
83 kprint("");
84 kprint("C: clear current map.");
85 kprint("");
86 kprint("P: set map properties (TIME, etc)");
87 kprint("");
88 kprint("S: save current map to a file.");
89 kprint("");
90 kprint("L: load map from a file.");
91 kprint("");
92 kprint("V: toggle 'show only current layer'");
93 kprint("");
94 kprint("D: dump tile set configuration to text file \"TILE_SET_CFG.TXT\"");
95 kprint("");
96 kprint("I: show information about current selected tile");
97 kprint("");
98 kprint("B: select background image for this level.");
99 kprint("");
100 kprint("M: select background music for this level.");
101 kprint("");
102 kprint("PLUS (+) and MINUS (-): change current layer in edition");
103 kprint("");
104 kprint("ESC: exit map editor.");
105 kprint("");
106 kprint("F1: show this help");
107 kprint("");
108 kprint("");
109 ckprint = makecol(128,128,128);
110 kprint("-- Press any key to continue --");
111 unscare_mouse();
112 clear_keybuf();
113 readkey();
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
123 if (layer > -1)
125 game_map.draw_map(dbuffer, tx, ty, SCREEN_W, SCREEN_H, layer, grid); // draw it
127 else
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
134 scare_mouse();
135 blit(dbuffer, screen,0,0,0,0,dbuffer->w,dbuffer->h);
136 unscare_mouse();
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);
146 else
148 clear_to_color(mcursor, makecol(255,0,255));
150 if (ts == 0)
151 textout_ex(mcursor, font, "CLS", 0, 0, makecol(128,128,255), -1);
152 else
153 textprintf_ex(mcursor, font, 0,0,makecol(255,0,0),-1, "%d", ts);
155 set_mouse_sprite(mcursor);
156 show_mouse(screen);
159 // -----------------------------------------------
160 // Map edit entry point
161 // -----------------------------------------------
162 void CMapEditor::start_map_editor()
164 bool dirty = false;
165 bool finish = false;
166 bool socl = false;
167 int omx=0,omy=0,old_mouse_z;
168 char str[2048];
169 str[0] = '\0';
171 char *home = getenv("HOME");
172 if (home != NULL)
174 char dir[2048];
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);
181 else
183 usprintf(str, "levels");
186 mtracer.add("CMapEditor::start_map_editor()");
188 dbuffer = create_bitmap(SCREEN_W, SCREEN_H);
189 if (dbuffer == NULL)
190 raise_error("ERROR: unable to create doble buffer bitmap!\n");
192 mcursor = create_bitmap(32,32);
193 if (mcursor == NULL)
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;
221 // main editor loop
222 while (!finish)
225 if (dirty)
227 if (socl)
228 redraw_the_tile_map(tl,draw_grid);
229 else
230 redraw_the_tile_map(-1,draw_grid);
232 dirty = false;
235 // little 'HUD'
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())
242 poll_keyboard();
243 if (mouse_needs_poll())
244 poll_mouse();
245 //yield_timeslice(); // play nice with multitasking
247 // sub hud
248 if (omx != mouse_x/10 || omy != mouse_y/10)
250 scare_mouse();
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);
252 unscare_mouse();
253 // div by 10 to get few precission
254 omx = mouse_x/10;
255 omy = mouse_y/10;
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);
263 dirty = true;
264 while (mouse_b)
266 if (mouse_needs_poll())
267 poll_mouse();
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);
275 dirty = true;
276 while (mouse_b)
278 if (mouse_needs_poll())
279 poll_mouse();
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)
289 game_map.sxp = 0;
290 if (game_map.sxp > 255)
291 game_map.sxp = 255;
292 if (game_map.syp < 0)
293 game_map.syp = 0;
294 if (game_map.syp > 255)
295 game_map.syp = 255;
296 dirty = true;
297 while (mouse_b)
299 if (mouse_needs_poll())
300 poll_mouse();
302 ; // wait until mouse release
305 // with shift, you move faster
307 if (key_shifts & KB_SHIFT_FLAG)
309 if (key[KEY_LEFT] )
311 tx -= 64;
312 dirty = true;
314 if (key[KEY_RIGHT] )
316 tx += 64;
317 dirty = true;
319 if (key[KEY_UP ] )
321 ty -= 64;
322 dirty = true;
324 if (key[KEY_DOWN] )
326 ty += 64;
327 dirty = true;
330 else
332 // without it, slower
333 if (key[KEY_LEFT] )
335 tx -= 24;
336 dirty = true;
338 if (key[KEY_RIGHT] )
340 tx += 24;
341 dirty = true;
343 if (key[KEY_UP ] )
345 ty -= 24;
346 dirty = true;
348 if (key[KEY_DOWN] )
350 ty += 24;
351 dirty = true;
355 if (key[KEY_X] || mouse_z > old_mouse_z) // change tile selected
357 ts++;
358 if (ts > 255)
359 ts = 0;
360 do_change_mouse_cursor();
363 if (key[KEY_Z] || mouse_z < old_mouse_z) // change tile selected
365 ts--;
366 if (ts < 0)
367 ts = 255;
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)
375 finish = true;
376 do_change_mouse_cursor();
379 if (key[KEY_I]) // show info about current tile
381 set_mouse_sprite(NULL);
382 ykprint = 0;
383 ckprint = makecol(255,255,255);
384 scare_mouse();
385 clear_bitmap(screen);
386 kprint("Info about tile");
387 kprint("");
388 kprint("");
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 );
396 else
397 kprint("This tile don't has sprite defined");
399 kprint("");
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 );
404 kprint("");
406 if (game_map.tile_set[ts].exit_level)
407 kprint("Is a level exit block");
409 kprint("");
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 );
417 kprint("");
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");
425 kprint("");
427 textprintf_ex(screen, font, 0, ykprint+=text_height(font), ckprint,-1, "Score: %d", game_map.tile_set[ts].score);
430 kprint("");
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 );
434 kprint("");
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 );
438 kprint("");
439 kprint("");
440 kprint("");
441 kprint("-- Press any key to continue --");
443 clear_keybuf();
444 rest(100);
445 readkey();
447 unscare_mouse();
448 do_change_mouse_cursor();
449 dirty = true;
452 if (key[KEY_B]) // select background
454 int t = 0;
456 set_mouse_sprite(NULL);
457 ykprint = 0;
458 ckprint = makecol(255,255,0);
459 scare_mouse();
461 while (t != KEY_ENTER)
463 ykprint = 0;
464 clear_bitmap(screen);
465 kprint("Select background with arrow keys, and press ENTER");
466 kprint("");
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);
472 t = readkey() >> 8;
473 rest(100);
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++;
478 if (t == KEY_PGUP )
479 game_map.background_index-=10;
480 if (t == KEY_PGDN )
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;
488 unscare_mouse();
489 do_change_mouse_cursor();
490 dirty = true;
493 if (key[KEY_M]) // select music
495 int t = 0;
497 set_mouse_sprite(NULL);
498 ykprint = 0;
499 ckprint = makecol(255,255,0);
500 scare_mouse();
502 while (t != KEY_ENTER)
504 ykprint = 0;
505 clear_bitmap(screen);
506 kprint("Select music with arrow keys, and press ENTER ; hit SPACE to play/stop the song");
507 kprint("");
508 textprintf_ex(screen, font, 0, 32, makecol(255,255,255),-1,"Current: %d", game_map.music_index);
510 clear_keybuf();
511 t = readkey() >> 8;
512 rest(100);
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++;
520 if (t == KEY_PGUP )
521 game_map.music_index-=10;
523 if (t == KEY_PGDN )
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;
532 if (t == KEY_SPACE)
534 // play the tune...
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);
538 if (!mm)
540 clear(screen);
541 kprint("Sorry, can't play that tune ; must be non existant");
542 rest(100);
543 kprint("-- press any key --");
544 readkey();
545 rest(10);
547 else
549 clear(screen);
550 kprint("Now playing tune...");
551 kprint("-- press any key to stop--");
553 soundw.music_load(mm);
555 soundw.music_start();
557 clear_keybuf();
559 while (!keypressed())
560 soundw.music_poll();
562 clear_keybuf();
563 rest(100);
565 soundw.music_stop();
567 music_loader.free_memory();
572 unscare_mouse();
573 do_change_mouse_cursor();
574 dirty = true;
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();
583 dirty = true;
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))
595 // failed :(
596 alert("ERROR", "File saving failed :(", NULL, "OK", NULL, 0,0);
598 else
600 // ok!
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))
616 // failed :(
617 alert("ERROR", "File load failed :(", "Your MAP probably has garbage, clear it with 'C' key!", "Crap!", NULL, 0,0);
619 else
621 // ok!
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;
627 dirty = true;
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)
638 scare_mouse();
639 textout_centre_ex(screen, font, "Please wait... writing file...", SCREEN_W/2, SCREEN_H/2, makecol(255,255,255), makecol(128,0,0));
640 unscare_mouse();
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);
643 dirty = true;
646 do_change_mouse_cursor();
649 if (key[KEY_G] ) // toggle grid
651 draw_grid = !draw_grid;
652 dirty = true;
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;
659 dirty = true;
662 if (key[KEY_F1])
664 set_mouse_sprite(NULL);
665 map_editor_help_message();
666 do_change_mouse_cursor();
667 dirty = true;
670 if (key[KEY_V]) // toggle 'show only current layer'
672 socl = !socl;
673 dirty = true;
677 if (key[KEY_PLUS_PAD] || key[KEY_EQUALS]) // keypad plus + = change edit layer
679 tl++;
680 dirty = true;
683 if (key[KEY_MINUS_PAD] || key[KEY_MINUS]) // keypad plus - = change edit layer
685 tl--;
686 dirty = true;
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 }
709 // set initial data
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;
715 // do input dialog
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);
721 // validate new data
722 it1 = atoi(st1);
723 it2 = atoi(st2);
724 if (it1 >= 0 && it2 >= 0 && it1 < 256 && it2 <= 60)
726 // set new data
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);
732 else
734 alert("ERROR", "Range of input invalid", "Valid: 0 <= minutes <= 255, and 0 <= seconds <= 60", "OK", NULL, 0,0);
737 do_change_mouse_cursor();
738 dirty = true;
742 if (tl < 0)
743 tl = MAP_LAYERS-1;
744 if (tl > MAP_LAYERS-1)
745 tl = 0;
747 if (tx < 0)
748 tx = 0;
749 if (ty < 0)
750 ty = 0;
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;
756 clear_keybuf();
759 // free memory
760 destroy_bitmap(dbuffer);
761 destroy_bitmap(mcursor);
762 game_map.free_memory();
763 set_mouse_sprite(NULL);