X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Feditor.c;h=a18b397617d2a493834a076fed51bd86ec7176ee;hb=caf79a7cd47eeeb43746bdeae08ec5f738d3bf61;hp=3434b4c2219731c842b9c7eadc82276f21d7b07e;hpb=823bddb0d9cc63ddda17a2cd20266aa3b82bde38;p=rocksndiamonds.git diff --git a/src/editor.c b/src/editor.c index 3434b4c2..a18b3976 100644 --- a/src/editor.c +++ b/src/editor.c @@ -17,12 +17,163 @@ #include "misc.h" #include "buttons.h" #include "files.h" +#include "game.h" + +/* positions in the level editor */ +#define ED_WIN_MB_LEFT_XPOS 7 +#define ED_WIN_MB_LEFT_YPOS 6 +#define ED_WIN_LEVELNR_XPOS 77 +#define ED_WIN_LEVELNR_YPOS 7 +#define ED_WIN_MB_MIDDLE_XPOS 7 +#define ED_WIN_MB_MIDDLE_YPOS 258 +#define ED_WIN_MB_RIGHT_XPOS 77 +#define ED_WIN_MB_RIGHT_YPOS 258 + +/* other constants for the editor */ +#define ED_SCROLL_NO 0 +#define ED_SCROLL_LEFT 1 +#define ED_SCROLL_RIGHT 2 +#define ED_SCROLL_UP 4 +#define ED_SCROLL_DOWN 8 + +/* screens in the level editor */ +#define ED_MODE_DRAWING 0 +#define ED_MODE_INFO 1 +#define ED_MODE_PROPERTIES 2 + +/* how many steps can be cancelled */ +#define NUM_UNDO_STEPS (10 + 1) + +/* values for random placement */ +#define RANDOM_USE_PERCENTAGE 0 +#define RANDOM_USE_NUM_OBJECTS 1 + +/* values for elements with content */ +#define MAX_ELEMCONT 8 + +/* values for the control window */ +#define ED_CTRL_BUTTONS_GFX_YPOS 236 +#define ED_CTRL_BUTTONS_ALT_GFX_YPOS 142 + +#define ED_CTRL1_BUTTONS_HORIZ 4 +#define ED_CTRL1_BUTTONS_VERT 4 +#define ED_CTRL1_BUTTON_XSIZE 22 +#define ED_CTRL1_BUTTON_YSIZE 22 +#define ED_CTRL1_BUTTONS_XPOS 6 +#define ED_CTRL1_BUTTONS_YPOS 6 +#define ED_CTRL2_BUTTONS_HORIZ 3 +#define ED_CTRL2_BUTTONS_VERT 2 +#define ED_CTRL2_BUTTON_XSIZE 30 +#define ED_CTRL2_BUTTON_YSIZE 20 +#define ED_CTRL2_BUTTONS_XPOS 5 +#define ED_CTRL2_BUTTONS_YPOS 100 +#define ED_NUM_CTRL1_BUTTONS (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT) +#define ED_NUM_CTRL2_BUTTONS (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT) +#define ED_NUM_CTRL_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS) + +/* values for counter gadgets */ +#define ED_COUNT_VALUE_XOFFSET 5 +#define ED_COUNT_VALUE_YOFFSET 3 +#define ED_COUNT_SCORE_XPOS (TILEX) +#define ED_COUNT_SCORE_YPOS (14 * MINI_TILEY) +#define ED_COUNT_ELEMCONT_XPOS (TILEX) +#define ED_COUNT_ELEMCONT_YPOS (17 * MINI_TILEY) + +/* values for element content drawing areas */ +#define ED_AREA_ELEMCONT_XPOS (TILEX) +#define ED_AREA_ELEMCONT_YPOS (10 * TILEY) + +/* control button identifiers */ +#define ED_CTRL_ID_SINGLE_ITEMS 0 +#define ED_CTRL_ID_CONNECTED_ITEMS 1 +#define ED_CTRL_ID_LINE 2 +#define ED_CTRL_ID_TEXT 3 +#define ED_CTRL_ID_RECTANGLE 4 +#define ED_CTRL_ID_FILLED_BOX 5 +#define ED_CTRL_ID_WRAP_UP 6 +#define ED_CTRL_ID_PROPERTIES 7 +#define ED_CTRL_ID_FLOOD_FILL 8 +#define ED_CTRL_ID_WRAP_LEFT 9 +#define ED_CTRL_ID_UNUSED1 10 +#define ED_CTRL_ID_WRAP_RIGHT 11 +#define ED_CTRL_ID_RANDOM_PLACEMENT 12 +#define ED_CTRL_ID_BRUSH 13 +#define ED_CTRL_ID_WRAP_DOWN 14 +#define ED_CTRL_ID_UNUSED2 15 +#define ED_CTRL_ID_UNDO 16 +#define ED_CTRL_ID_INFO 17 +#define ED_CTRL_ID_SAVE 18 +#define ED_CTRL_ID_CLEAR 19 +#define ED_CTRL_ID_TEST 20 +#define ED_CTRL_ID_EXIT 21 + +/* counter button identifiers */ +#define ED_CTRL_ID_SCORE_DOWN 22 +#define ED_CTRL_ID_SCORE_UP 23 +#define ED_CTRL_ID_ELEMCONT_DOWN 24 +#define ED_CTRL_ID_ELEMCONT_UP 25 + +/* drawing area identifiers */ +#define ED_CTRL_ID_DRAWING_LEVEL 26 +#define ED_CTRL_ID_ELEMCONT_0 27 +#define ED_CTRL_ID_ELEMCONT_7 34 +#define ED_CTRL_ID_AMOEBA_CONTENT 35 + +#define ED_NUM_GADGETS 36 + +/* values for counter gadgets */ +#define ED_COUNTER_SCORE 0 +#define ED_COUNTER_ELEMCONT 1 + +#define ED_NUM_COUNTERS 2 + +static struct +{ + int x, y; + int gadget_id; +} counter_info[ED_NUM_COUNTERS] = +{ + { ED_COUNT_SCORE_XPOS, ED_COUNT_SCORE_YPOS, + ED_CTRL_ID_SCORE_DOWN }, + { ED_COUNT_ELEMCONT_XPOS, ED_COUNT_ELEMCONT_YPOS, + ED_CTRL_ID_ELEMCONT_DOWN } +}; + +/* forward declaration for internal use */ +static void DrawDrawingWindow(); +static void DrawPropertiesWindow(); +static void CopyLevelToUndoBuffer(); +static void HandleDrawingAreas(struct GadgetInfo *); +static void HandleCounterButtons(struct GadgetInfo *); +static void HandleControlButtons(struct GadgetInfo *); + +static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS]; +static boolean level_editor_gadgets_created = FALSE; + +static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS; +static int properties_element = 0; + +static short ElementContent[MAX_ELEMCONT][3][3]; +static short OrigBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +static int undo_buffer_position = 0; +static int undo_buffer_steps = 0; + +static int random_placement_percentage = 10; +static int random_placement_num_objects = 10; +#if 0 +static int random_placement_method = RANDOM_USE_PERCENTAGE; +#else +static int random_placement_method = RANDOM_USE_NUM_OBJECTS; +#endif -#define CHOICE_DELAY_VALUE 100 +/* pointer to score value */ +static int *gadget_score_value; +static int *gadget_areas_value; static int level_xpos,level_ypos; -static BOOL edit_mode; -static BOOL name_typing; +static int edit_mode; +static boolean name_typing; static int new_element1 = EL_MAUERWERK; static int new_element2 = EL_LEERRAUM; static int new_element3 = EL_ERDREICH; @@ -206,9 +357,9 @@ int editor_element[] = EL_DRACHE, EL_SONDE, - EL_LEERRAUM, - EL_LEERRAUM, - EL_LEERRAUM, + EL_MAUER_X, + EL_MAUER_Y, + EL_MAUER_XY, EL_CHAR_A + ('S' - 'A'), EL_CHAR_A + ('O' - 'A'), @@ -323,17 +474,341 @@ int editor_element[] = }; int elements_in_list = sizeof(editor_element)/sizeof(int); +static void ScrollMiniLevel(int from_x, int from_y, int scroll) +{ + int x,y; + int dx = (scroll==ED_SCROLL_LEFT ? -1 : scroll==ED_SCROLL_RIGHT ? 1 : 0); + int dy = (scroll==ED_SCROLL_UP ? -1 : scroll==ED_SCROLL_DOWN ? 1 : 0); + + XCopyArea(display,drawto,drawto,gc, + SX+MINI_TILEX*(dx==-1),SY+MINI_TILEY*(dy==-1), + SXSIZE-MINI_TILEX*ABS(dx),SYSIZE-MINI_TILEY*ABS(dy), + SX+MINI_TILEX*(dx==+1),SY+MINI_TILEY*(dy==+1)); + if (dx) + { + x = (dx==1 ? 0 : 2*SCR_FIELDX-1); + for(y=0;y<2*SCR_FIELDY;y++) + DrawMiniElementOrWall(x,y,from_x,from_y); + } + else if (dy) + { + y = (dy==1 ? 0 : 2*SCR_FIELDY-1); + for(x=0;x<2*SCR_FIELDX;x++) + DrawMiniElementOrWall(x,y,from_x,from_y); + } + + redraw_mask |= REDRAW_FIELD; + BackToFront(); +} + +void InitLevelEditorGadgets() +{ + int i; + + for (i=0; ilev_fieldx-2*SCR_FIELDX+1) - level_xpos = lev_fieldx-2*SCR_FIELDX+1; - if (lev_fieldx<2*SCR_FIELDX-2) + if (level_xpos > lev_fieldx - 2*SCR_FIELDX + 1) + level_xpos = lev_fieldx - 2*SCR_FIELDX + 1; + if (lev_fieldx < 2*SCR_FIELDX - 2) level_xpos = -1; - if (level_ypos<-1) + if (level_ypos < -1) level_ypos = -1; - if (level_ypos>lev_fieldy-2*SCR_FIELDY+1) - level_ypos = lev_fieldy-2*SCR_FIELDY+1; - if (lev_fieldy<2*SCR_FIELDY-2) + if (level_ypos > lev_fieldy - 2*SCR_FIELDY + 1) + level_ypos = lev_fieldy - 2*SCR_FIELDY + 1; + if (lev_fieldy < 2*SCR_FIELDY - 2) level_ypos = -1; } -void FloodFill(int from_x, int from_y, int fill_element) -{ - int i,x,y; - int old_element; - static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} }; - static int safety = 0; - - safety++; - - if (safety>lev_fieldx*lev_fieldy) - { - fprintf(stderr,"Something went wrong in 'FloodFill()'. Please debug.\n"); - exit(-1); - } - - old_element = Feld[from_x][from_y]; - Feld[from_x][from_y] = fill_element; - - for(i=0;i<4;i++) - { - x = from_x+check[i][0]; - y = from_y+check[i][1]; - - if (IN_LEV_FIELD(x,y) && Feld[x][y]==old_element) - FloodFill(x,y,fill_element); - } - - safety--; -} - void LevelEd(int mx, int my, int button) { static int last_button = 0; static int in_field_pressed = FALSE; - static BOOL use_floodfill = FALSE; + static boolean use_floodfill = FALSE; + + + /* int x = (mx-SX)/MINI_TILEX; int y = (my-SY)/MINI_TILEY; + */ + + /* + HandlePressedControlButtons(); + HandleDrawingFunctions(mx, my, button); + */ if (use_floodfill) /********** FLOOD FILL **********/ { + + +#if 0 + if (button) { if (mx>=SX && mx=SY && my0) || (choice == ED_BUTTON_EDOWN && element_shiftelements_in_list-MAX_ELEM_X*MAX_ELEM_Y) @@ -728,10 +1196,22 @@ void LevelEd(int mx, int my, int button) DY+ED_WIN_MB_RIGHT_YPOS, el2gfx(new_element3)); redraw_mask |= REDRAW_DOOR_1; + + /* + properties_element = new_element; + if (edit_mode == ED_MODE_PROPERTIES) + DrawPropertiesWindow(); + */ + } - if (edit_mode) /********** EDIT-FENSTER **********/ + if (edit_mode == ED_MODE_DRAWING) /********** EDIT-FENSTER **********/ { + + + +#if 0 + switch(CheckEditButtons(mx,my,button)) { case ED_BUTTON_CTRL: @@ -742,17 +1222,17 @@ void LevelEd(int mx, int my, int button) VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2); OpenDoor(DOOR_OPEN_2); - edit_mode = FALSE; + edit_mode = ED_MODE_INFO; break; case ED_BUTTON_FILL: - AreYouSure("Caution ! Flood fill mode ! Choose area !",AYS_OPEN); + Request("Caution ! Flood fill mode ! Choose area !",REQ_OPEN); use_floodfill = TRUE; return; break; case ED_BUTTON_LEFT: if (level_xpos>=0) { - if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY)) break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -769,7 +1249,7 @@ void LevelEd(int mx, int my, int button) case ED_BUTTON_RIGHT: if (level_xpos<=lev_fieldx-2*SCR_FIELDX) { - if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY)) break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -786,7 +1266,7 @@ void LevelEd(int mx, int my, int button) case ED_BUTTON_UP: if (level_ypos>=0) { - if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY)) break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -803,7 +1283,7 @@ void LevelEd(int mx, int my, int button) case ED_BUTTON_DOWN: if (level_ypos<=lev_fieldy-2*SCR_FIELDY) { - if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY)) break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -821,6 +1301,12 @@ void LevelEd(int mx, int my, int button) break; } +#endif + + + +#if 0 + if (mx>=SX && mx=SY && my= 0 && choice < 36 && - DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + DelayReached(&choice_delay, GADGET_FRAME_DELAY)) { if (!(choice % 2)) step = -step; @@ -996,6 +1487,10 @@ void LevelEd(int mx, int my, int button) XFlush(display); } + + +#if 0 + switch(CheckCtrlButtons(mx,my,button)) { case ED_BUTTON_EDIT: @@ -1007,10 +1502,10 @@ void LevelEd(int mx, int my, int button) VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2); OpenDoor(DOOR_OPEN_2); - edit_mode = TRUE; + edit_mode = ED_MODE_DRAWING; break; case ED_BUTTON_CLEAR: - if (AreYouSure("Are you sure to clear this level ?",AYS_ASK)) + if (Request("Are you sure to clear this level ?",REQ_ASK)) { for(x=0;x=ED_COUNT_GADGET_XPOS && mx=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE && @@ -1251,3 +1750,1140 @@ void LevelNameTyping(KeySym key) name_typing = FALSE; } } + +static void DrawCounterValueField(int counter_id, int value) +{ + int x = SX + counter_info[counter_id].x + ED_WIN_COUNT_XPOS; + int y = SY + counter_info[counter_id].y; + + XCopyArea(display, pix[PIX_DOOR], drawto, gc, + DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS, + DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS, + ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE, + x, y); + + DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET, + int2str(value, 3), FS_SMALL, FC_YELLOW); +} + +#define TEXT_COLLECTING "Score for collecting" +#define TEXT_SMASHING "Score for smashing" +#define TEXT_CRACKING "Score for cracking" +#define TEXT_SPEED "Speed of growth" +#define TEXT_DURATION "Duration when activated" + +static void DrawDrawingWindow() +{ + ClearWindow(); + UnmapLevelEditorWindowGadgets(); + MapMainDrawingArea(); + AdjustLevelScrollPosition(); + DrawMiniLevel(level_xpos, level_ypos); +} + +static void DrawElementContentAreas() +{ + static int num_areas = MAX_ELEMCONT; + int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX; + int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY; + int area_sx = SX + ED_AREA_ELEMCONT_XPOS; + int area_sy = SY + ED_AREA_ELEMCONT_YPOS; + int i, x, y; + + for (i=0; i to_x) + swap_numbers(&from_x, &to_x); + + for (x=from_x; x<=to_x; x++) + DrawLineElement(x, y, element, change_level); + } + else if (from_x == to_x) /* vertical line */ + { + int x = from_x; + int y; + + if (from_y > to_y) + swap_numbers(&from_y, &to_y); + + for (y=from_y; y<=to_y; y++) + DrawLineElement(x, y, element, change_level); + } + else /* diagonal line */ + { + int len_x = ABS(to_x - from_x); + int len_y = ABS(to_y - from_y); + int x, y; + + if (len_y < len_x) /* a < 1 */ + { + float a = (float)len_y / (float)len_x; + + if (from_x > to_x) + swap_number_pairs(&from_x, &from_y, &to_x, &to_y); + + for (x=0; x<=len_x; x++) + { + int y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1); + + DrawLineElement(from_x + x, from_y + y, element, change_level); + } + } + else /* a >= 1 */ + { + float a = (float)len_x / (float)len_y; + + if (from_y > to_y) + swap_number_pairs(&from_x, &from_y, &to_x, &to_y); + + for (y=0; y<=len_y; y++) + { + int x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1); + + DrawLineElement(from_x + x, from_y + y, element, change_level); + } + } + } +} + +static void DrawRectangle(int from_x, int from_y, int to_x, int to_y, + int element, boolean change_level) +{ + DrawLine(from_x, from_y, from_x, to_y, element, change_level); + DrawLine(from_x, to_y, to_x, to_y, element, change_level); + DrawLine(to_x, to_y, to_x, from_y, element, change_level); + DrawLine(to_x, from_y, from_x, from_y, element, change_level); +} + +static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y, + int element, boolean change_level) +{ + int y; + + if (from_y > to_y) + swap_number_pairs(&from_x, &from_y, &to_x, &to_y); + + for (y=from_y; y<=to_y; y++) + DrawLine(from_x, y, to_x, y, element, change_level); +} + +static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y) +{ + int from_sx, from_sy; + int to_sx, to_sy; + + if (from_x > to_x) + swap_numbers(&from_x, &to_x); + + if (from_y > to_y) + swap_numbers(&from_y, &to_y); + + from_sx = SX + from_x * MINI_TILEX; + from_sy = SY + from_y * MINI_TILEY; + to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1; + to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1; + + XSetForeground(display, gc, WhitePixel(display, screen)); + + XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy); + XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy); + XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy); + XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy); + + XSetForeground(display, gc, BlackPixel(display, screen)); + + if (from_x == to_x && from_y == to_y) + MarkTileDirty(from_x/2, from_y/2); + else + redraw_mask |= REDRAW_FIELD; +} + +static void SelectArea(int from_x, int from_y, int to_x, int to_y, + int element, boolean change_level) +{ + if (element == -1 || change_level) + DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE); + else + DrawAreaBorder(from_x, from_y, to_x, to_y); +} + +/* values for CopyBrushExt() */ +#define CB_AREA_TO_BRUSH 0 +#define CB_BRUSH_TO_LEVEL 1 + +static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int mode) +{ + static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; + static brush_from_x, brush_from_y; + static brush_to_x, brush_to_y; + int x, y; + + if (from_x > to_x) + swap_numbers(&from_x, &to_x); + + if (from_y > to_y) + swap_numbers(&from_y, &to_y); + + if (mode == CB_AREA_TO_BRUSH) + { + for (y=from_y; y<=to_y; y++) + for (x=from_x; x<=to_x; x++) + brush_buffer[x][y] = Feld[x][y]; + + brush_from_x = from_x; + brush_from_y = from_y; + brush_to_x = to_x; + brush_to_y = to_y; + } + else + { + for (y=brush_from_y; y<=brush_to_y; y++) + for (x=brush_from_x; x<=brush_to_x; x++) + Feld[x][y] = brush_buffer[x][y]; + CopyLevelToUndoBuffer(); + } +} + +static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y) +{ + CopyBrushExt(from_x, from_y, to_x, to_y, CB_AREA_TO_BRUSH); +} + +#if 0 +static void CopyBrushToLevel() +{ + CopyBrushExt(0, 0, 0, 0, CB_BRUSH_TO_LEVEL); +} +#endif + +static void FloodFill(int from_x, int from_y, int fill_element) +{ + int i,x,y; + int old_element; + static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} }; + static int safety = 0; + + /* check if starting field still has the desired content */ + if (Feld[from_x][from_y] == fill_element) + return; + + safety++; + + if (safety > lev_fieldx*lev_fieldy) + Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug."); + + old_element = Feld[from_x][from_y]; + Feld[from_x][from_y] = fill_element; + + for(i=0;i<4;i++) + { + x = from_x + check[i][0]; + y = from_y + check[i][1]; + + if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element) + FloodFill(x, y, fill_element); + } + + safety--; +} + +/* values for DrawLevelText() modes */ +#define TEXT_INIT 0 +#define TEXT_SETCURSOR 1 +#define TEXT_WRITECHAR 2 +#define TEXT_BACKSPACE 3 +#define TEXT_NEWLINE 4 +#define TEXT_END 5 + +static void DrawLevelText(int sx, int sy, char letter, int mode) +{ + static short delete_buffer[MAX_LEV_FIELDX]; + static int start_sx, start_sy; + static int last_sx, last_sy; + static boolean typing = FALSE; + int letter_element = EL_CHAR_ASCII0 + letter; + int lx, ly; + + if (mode != TEXT_INIT) + { + if (!typing) + return; + + if (mode != TEXT_SETCURSOR) + { + sx = last_sx; + sy = last_sy; + } + + lx = last_sx + level_xpos; + ly = last_sy + level_ypos; + } + + switch (mode) + { + case TEXT_INIT: + if (typing) + DrawLevelText(0, 0, 0, TEXT_END); + + typing = TRUE; + start_sx = last_sx = sx; + start_sy = last_sy = sy; + DrawLevelText(sx, sy, 0, TEXT_SETCURSOR); + break; + + case TEXT_SETCURSOR: + DrawMiniElement(last_sx, last_sy, Feld[lx][ly]); + DrawAreaBorder(sx, sy, sx, sy); + last_sx = sx; + last_sy = sy; + break; + + case TEXT_WRITECHAR: + if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END) + { + delete_buffer[sx - start_sx] = Feld[lx][ly]; + Feld[lx][ly] = letter_element; + + if (sx + 1 < 2*SCR_FIELDX && lx + 1 < lev_fieldx) + DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR); + else if (sy + 1 < 2*SCR_FIELDY && ly + 1 < lev_fieldy) + DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); + else + DrawLevelText(0, 0, 0, TEXT_END); + } + break; + + case TEXT_BACKSPACE: + if (sx > start_sx) + { + Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1]; + DrawMiniElement(sx - 1, sy, new_element3); + DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR); + } + break; + + case TEXT_NEWLINE: + if (sy + 1 < 2*SCR_FIELDY - 1 && ly + 1 < lev_fieldy - 1) + DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); + else + DrawLevelText(0, 0, 0, TEXT_END); + break; + + case TEXT_END: + CopyLevelToUndoBuffer(); + DrawMiniElement(sx, sy, Feld[lx][ly]); + typing = FALSE; + break; + + default: + break; + } +} + +static void CopyLevelToUndoBuffer() +{ + int x, y; + + undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS; + + if (undo_buffer_steps < NUM_UNDO_STEPS - 1) + undo_buffer_steps++; + + for(x=0; x 0) + { + x = RND(lev_fieldx); + y = RND(lev_fieldy); + + if (Feld[x][y] != new_element) + { + Feld[x][y] = new_element; + elements_left--; + } + } + } + + DrawMiniLevel(level_xpos, level_ypos); + CopyLevelToUndoBuffer(); +} + +static void HandleDrawingAreas(struct GadgetInfo *gi) +{ + static boolean started_inside_drawing_area = FALSE; + static boolean draw_with_brush = FALSE; + boolean inside_drawing_area = !gi->event.off_borders; + boolean button_press_event; + boolean button_release_event; + boolean draw_level = (gi->custom_id == ED_CTRL_ID_DRAWING_LEVEL); + int new_element; + int button = gi->event.button; + int sx = gi->event.x, sy = gi->event.y; + int lx, ly; + int x, y; + + /* + if (edit_mode != ED_MODE_DRAWING) + return; + */ + + button_press_event = (gi->event.type == GD_EVENT_PRESSED); + button_release_event = (gi->event.type == GD_EVENT_RELEASED); + + if (draw_level) + { + sx = (sx < 0 ? 0 : sx > 2*SCR_FIELDX - 1 ? 2*SCR_FIELDX - 1 : sx); + sy = (sy < 0 ? 0 : sy > 2*SCR_FIELDY - 1 ? 2*SCR_FIELDY - 1 : sy); + lx = sx + level_xpos; + ly = sy + level_ypos; + + lx = (lx < 0 ? 0 : lx > lev_fieldx - 1 ? lev_fieldx - 1 : lx); + ly = (ly < 0 ? 0 : ly > lev_fieldy - 1 ? lev_fieldy - 1 : ly); + sx = lx - level_xpos; + sy = ly - level_ypos; + } + else + { + sx = (sx < 0 ? 0 : sx > 2 ? 2 : sx); + sy = (sy < 0 ? 0 : sy > 2 ? 2 : sy); + } + + if (button_press_event) + started_inside_drawing_area = inside_drawing_area; + + if (!started_inside_drawing_area) + return; + + if (!button && !button_release_event) + return; + + new_element = (button == 1 ? new_element1 : + button == 2 ? new_element2 : + button == 3 ? new_element3 : 0); + + if (!draw_level && drawing_function != ED_CTRL_ID_SINGLE_ITEMS) + return; + + switch (drawing_function) + { + case ED_CTRL_ID_SINGLE_ITEMS: + if (draw_level) + { + if (button_release_event) + CopyLevelToUndoBuffer(); + + if (!button) + break; + + if (new_element != Feld[lx][ly]) + { + if (new_element == EL_SPIELFIGUR) + { + /* remove player at old position */ + for(y=0; y= 0 && x - level_xpos < 2*SCR_FIELDX && + y - level_ypos >= 0 && y - level_ypos < 2*SCR_FIELDY) + DrawMiniElement(x - level_xpos, y - level_ypos, + EL_LEERRAUM); + } + } + } + } + + Feld[lx][ly] = new_element; + DrawMiniElement(sx, sy, new_element); + } + } + else + { + DrawMiniGraphicExt(drawto, gc, + gi->x + sx * MINI_TILEX, + gi->y + sy * MINI_TILEY, + el2gfx(new_element)); + DrawMiniGraphicExt(window, gc, + gi->x + sx * MINI_TILEX, + gi->y + sy * MINI_TILEY, + el2gfx(new_element)); + } + break; + + case ED_CTRL_ID_CONNECTED_ITEMS: + { + static int last_sx = -1; + static int last_sy = -1; + + if (button_release_event) + CopyLevelToUndoBuffer(); + + if (button) + { + if (!button_press_event) + DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE); + + last_sx = sx; + last_sy = sy; + } + } + break; + + case ED_CTRL_ID_LINE: + case ED_CTRL_ID_RECTANGLE: + case ED_CTRL_ID_FILLED_BOX: + case ED_CTRL_ID_BRUSH: + { + static int last_sx = -1; + static int last_sy = -1; + static int start_sx = -1; + static int start_sy = -1; + void (*draw_func)(int, int, int, int, int, boolean); + + if (drawing_function == ED_CTRL_ID_LINE) + draw_func = DrawLine; + else if (drawing_function == ED_CTRL_ID_RECTANGLE) + draw_func = DrawRectangle; + else if (drawing_function == ED_CTRL_ID_FILLED_BOX) + draw_func = DrawFilledBox; + else + draw_func = SelectArea; + + if (button_press_event) + { + draw_func(sx, sy, sx, sy, new_element, FALSE); + start_sx = last_sx = sx; + start_sy = last_sy = sy; + } + else if (button_release_event) + { + draw_func(start_sx, start_sy, sx, sy, new_element, TRUE); + if (drawing_function == ED_CTRL_ID_BRUSH) + { + CopyAreaToBrush(start_sx, start_sy, sx, sy); + draw_with_brush = TRUE; + } + else + CopyLevelToUndoBuffer(); + } + else if (last_sx != sx || last_sy != sy) + { + draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE); + draw_func(start_sx, start_sy, sx, sy, new_element, FALSE); + last_sx = sx; + last_sy = sy; + } + } + break; + + case ED_CTRL_ID_TEXT: + if (button_press_event) + DrawLevelText(sx, sy, 0, TEXT_INIT); + break; + + case ED_CTRL_ID_FLOOD_FILL: + if (button_press_event && Feld[lx][ly] != new_element) + { + FloodFill(lx, ly, new_element); + DrawMiniLevel(level_xpos, level_ypos); + CopyLevelToUndoBuffer(); + } + break; + + default: + break; + } +} + +static void HandleCounterButtons(struct GadgetInfo *gi) +{ + int id = gi->custom_id; + int button = gi->event.button; + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + + switch (id) + { + case ED_CTRL_ID_SCORE_DOWN: + case ED_CTRL_ID_SCORE_UP: + *gadget_score_value += (id == ED_CTRL_ID_SCORE_DOWN ? -step : step); + if (*gadget_score_value < 0) + *gadget_score_value = 0; + else if (*gadget_score_value > 255) + *gadget_score_value = 255; + + DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value); + break; + + case ED_CTRL_ID_ELEMCONT_DOWN: + case ED_CTRL_ID_ELEMCONT_UP: + *gadget_areas_value += (id == ED_CTRL_ID_ELEMCONT_DOWN ? -step : step); + if (*gadget_areas_value < 1) + *gadget_areas_value = 1; + else if (*gadget_areas_value > MAX_ELEMCONT) + *gadget_areas_value = MAX_ELEMCONT; + + DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value); + DrawElementContentAreas(); + break; + + default: + break; + } +} + +static void HandleControlButtons(struct GadgetInfo *gi) +{ + int id = gi->custom_id; + int button = gi->event.button; + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int new_element; + int player_present = FALSE; + int level_changed = FALSE; + int x, y; + + new_element = (button == 1 ? new_element1 : + button == 2 ? new_element2 : + button == 3 ? new_element3 : 0); + + if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT) + DrawLevelText(0, 0, 0, TEXT_END); + + if (id < ED_NUM_CTRL1_BUTTONS && edit_mode != ED_MODE_DRAWING) + { + DrawDrawingWindow(); + edit_mode = ED_MODE_DRAWING; + } + + switch (id) + { + case ED_CTRL_ID_SINGLE_ITEMS: + case ED_CTRL_ID_CONNECTED_ITEMS: + case ED_CTRL_ID_LINE: + case ED_CTRL_ID_TEXT: + case ED_CTRL_ID_RECTANGLE: + case ED_CTRL_ID_FILLED_BOX: + case ED_CTRL_ID_FLOOD_FILL: + case ED_CTRL_ID_BRUSH: + drawing_function = id; + break; + + case ED_CTRL_ID_WRAP_LEFT: + if (level_xpos >= 0) + { + if (lev_fieldx < 2*SCR_FIELDX - 2) + break; + + level_xpos -= step; + if (level_xpos <- 1) + level_xpos = -1; + if (button == 1) + ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT); + else + DrawMiniLevel(level_xpos, level_ypos); + } + break; + + case ED_CTRL_ID_WRAP_RIGHT: + if (level_xpos <= lev_fieldx - 2*SCR_FIELDX) + { + if (lev_fieldx < 2*SCR_FIELDX - 2) + break; + + level_xpos += step; + if (level_xpos > lev_fieldx - 2*SCR_FIELDX + 1) + level_xpos = lev_fieldx - 2*SCR_FIELDX + 1; + if (button == 1) + ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT); + else + DrawMiniLevel(level_xpos, level_ypos); + } + break; + + case ED_CTRL_ID_WRAP_UP: + if (level_ypos >= 0) + { + if (lev_fieldy < 2*SCR_FIELDY - 2) + break; + + level_ypos -= step; + if (level_ypos < -1) + level_ypos = -1; + if (button == 1) + ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN); + else + DrawMiniLevel(level_xpos, level_ypos); + } + break; + + case ED_CTRL_ID_WRAP_DOWN: + if (level_ypos <= lev_fieldy - 2*SCR_FIELDY) + { + if (lev_fieldy < 2*SCR_FIELDY - 2) + break; + + level_ypos += step; + if (level_ypos > lev_fieldy - 2*SCR_FIELDY + 1) + level_ypos = lev_fieldy - 2*SCR_FIELDY + 1; + if (button == 1) + ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP); + else + DrawMiniLevel(level_xpos, level_ypos); + } + break; + + case ED_CTRL_ID_PROPERTIES: + properties_element = new_element; + DrawPropertiesWindow(); + edit_mode = ED_MODE_PROPERTIES; + break; + + case ED_CTRL_ID_RANDOM_PLACEMENT: + RandomPlacement(button); + break; + + case ED_CTRL_ID_UNDO: + if (undo_buffer_steps == 0) + { + Request("Undo buffer empty !", REQ_CONFIRM); + break; + } + + undo_buffer_position = + (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS; + undo_buffer_steps--; + + for(x=0; xevent.type == GD_EVENT_PRESSED) + printf("default: HandleControlButtons: GD_EVENT_PRESSED\n"); + else if (gi->event.type == GD_EVENT_RELEASED) + printf("default: HandleControlButtons: GD_EVENT_RELEASED\n"); + else if (gi->event.type == GD_EVENT_MOVING) + printf("default: HandleControlButtons: GD_EVENT_MOVING\n"); + else + printf("default: HandleControlButtons: ?\n"); + break; + } +} + +void HandleLevelEditorKeyInput(KeySym key) +{ + if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT) + { + char *keyname = getKeyNameFromKeySym(key); + char letter = 0; + + if (strlen(keyname) == 1) + letter = keyname[0]; + else if (strcmp(keyname, "space") == 0) + letter = ' '; + else if (strcmp(keyname, "less") == 0) + letter = '<'; + else if (strcmp(keyname, "equal") == 0) + letter = '='; + else if (strcmp(keyname, "greater") == 0) + letter = '>'; + + /* map lower case letters to upper case */ + if (letter >= 'a' && letter <= 'z') + letter += (int)('A' - 'a'); + else if (letter == 'ä') + letter = 'Ä'; + else if (letter == 'ä') + letter = 'Ö'; + else if (letter == 'ä') + letter = 'Ü'; + + if (letter) + DrawLevelText(0, 0, letter, TEXT_WRITECHAR); + else if (key == XK_Delete || key == XK_BackSpace) + DrawLevelText(0, 0, 0, TEXT_BACKSPACE); + else if (key == XK_Return) + DrawLevelText(0, 0, 0, TEXT_NEWLINE); + } +}