X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Feditor.c;h=4b52fdb5d0f5d40be88edb9a59402e9b9eb4645c;hb=c795e57154a65ad24c99eff435a524a73f92e754;hp=fc81ebe09a6bee9e175a28daa927ee138172ebc5;hpb=e557b2b5d9951a4e692fd4e32a5cf45c84252c64;p=rocksndiamonds.git diff --git a/src/editor.c b/src/editor.c index fc81ebe0..4b52fdb5 100644 --- a/src/editor.c +++ b/src/editor.c @@ -18,11 +18,84 @@ #include "buttons.h" #include "files.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 + +/* delay value to avoid too fast scrolling etc. */ #define CHOICE_DELAY_VALUE 100 +/* how many steps can be cancelled */ +#define NUM_UNDO_STEPS (10 + 1) + +/* values for the control window */ +#define ED_CTRL_BUTTONS_GFX_YPOS 236 +#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) + +/* control button names */ +#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_ITEM_PROPERTIES 7 +#define ED_CTRL_ID_FLOOD_FILL 8 +#define ED_CTRL_ID_WRAP_LEFT 9 +#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_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 + +/* forward declaration for internal use */ +void HandleDrawingFunction(int, int, int); + +static struct GadgetInfo *control_button_gadget[ED_NUM_CTRL_BUTTONS]; +static boolean control_button_gadgets_created = FALSE; + +static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS; + +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 level_xpos,level_ypos; -static BOOL edit_mode; -static BOOL name_typing; +static boolean edit_mode; +static boolean name_typing; static int new_element1 = EL_MAUERWERK; static int new_element2 = EL_LEERRAUM; static int new_element3 = EL_ERDREICH; @@ -323,9 +396,356 @@ int editor_element[] = }; int elements_in_list = sizeof(editor_element)/sizeof(int); +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 HandlePressedControlButtons() +{ + static unsigned long button_delay = 0; + int i = 0; + + /* buttons with action when held pressed */ + int gadget_id[] = + { + ED_CTRL_ID_WRAP_UP, + ED_CTRL_ID_WRAP_LEFT, + ED_CTRL_ID_WRAP_RIGHT, + ED_CTRL_ID_WRAP_DOWN, + -1 + }; + + if (!DelayReached(&button_delay, CHOICE_DELAY_VALUE)) + return; + + while (gadget_id[i] != -1) + { + int id = gadget_id[i++]; + int state = control_button_gadget[id]->state; + int button = control_button_gadget[id]->event.button; + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + + if (state != GD_BUTTON_PRESSED) + continue; + + switch (id) + { + 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; + + default: + break; + } + } +} + +void HandleLevelEditorControlButtons(struct GadgetInfo *gi) +{ + int event_type = gi->event.type; + + /* + int button = gi->event.button; + */ + + int id; + int i, x, y; + + /* get the button id */ + for (i=0; iid == control_button_gadget[i]->id) + id = i; + + 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_RANDOM_PLACEMENT: + case ED_CTRL_ID_BRUSH: + drawing_function = id; + 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; xlev_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(); + HandleDrawingFunction(mx, my, button); if (use_floodfill) /********** FLOOD FILL **********/ { + + +#if 0 + if (button) { if (mx>=SX && mx=SY && my=SX && mx=SY && my=ED_COUNT_GADGET_XPOS && mx=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE && @@ -1251,3 +1681,337 @@ void LevelNameTyping(KeySym key) name_typing = FALSE; } } + +static void swap_numbers(int *i1, int *i2) +{ + int help = *i1; + + *i1 = *i2; + *i2 = help; +} + +static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) +{ + int help_x = *x1; + int help_y = *y1; + + *x1 = *x2; + *x2 = help_x; + + *y1 = *y2; + *y2 = help_y; +} + +static void DrawLineElement(int sx, int sy, int element, boolean change_level) +{ + int lx = sx + level_xpos; + int ly = sy + level_ypos; + + DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element)); + + if (change_level) + Feld[lx][ly] = element; +} + +void DrawLine(int from_x, int from_y, int to_x, int to_y, int element, + boolean change_level) +{ + if (from_y == to_y) /* horizontal line */ + { + int x; + int y = from_y; + + if (from_x > 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); + } + } + } +} + +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); +} + +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); +} + +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--; +} + +void HandleDrawingFunction(int mx, int my, int button) +{ + static int last_button = 0; + static int last_element = 0; + boolean button_press_event; + boolean button_release_event; + boolean copy_to_undo_buffer = FALSE; + int new_element; + int sx = (mx - SX) / MINI_TILEX; + int sy = (my - SY) / MINI_TILEY; + int lx = sx + level_xpos; + int ly = sy + level_ypos; + int x, y; + + button_press_event = (last_button == 0 && button != 0); + button_release_event = (last_button != 0 && button == 0); + last_button = button; + + if (mx < SX || mx >= SX + SXSIZE || my < SY || my >= SY + SYSIZE) + return; + + if (sx > lev_fieldx || sy > lev_fieldy || + (sx == 0 && level_xpos<0) || + (sx == 2*SCR_FIELDX - 1 && level_xpos > lev_fieldx - 2*SCR_FIELDX) || + (sy == 0 && level_ypos < 0) || + (sy == 2*SCR_FIELDY - 1 && level_ypos > lev_fieldy - 2*SCR_FIELDY)) + return; + + new_element = (button == 1 ? new_element1 : + button == 2 ? new_element2 : + button == 3 ? new_element3 : 0); + + switch (drawing_function) + { + case ED_CTRL_ID_SINGLE_ITEMS: + if (button_release_event) + copy_to_undo_buffer = TRUE; + + 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); + } + break; + + case ED_CTRL_ID_CONNECTED_ITEMS: + { + static int last_sx = -1; + static int last_sy = -1; + + if (button_release_event) + copy_to_undo_buffer = TRUE; + + 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: + { + 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 + draw_func = DrawFilledBox; + + if (button_press_event) + { + last_sx = start_sx = sx; + last_sy = start_sy = sy; + } + else if (button_release_event) + { + draw_func(start_sx, start_sy, sx, sy, last_element, TRUE); + copy_to_undo_buffer = TRUE; + } + 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 999: + { + static int last_sx = -1; + static int last_sy = -1; + + if (last_sx == -1) + { + Feld[lx][ly] = new_element; + DrawMiniElement(sx, sy, new_element); + + last_sx = sx; + last_sy = sy; + } + else if (last_sx != sx || last_sy != sy) + { + DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE); + + last_sx = -1; + last_sy = -1; + } + + /* + last_sx = sx; + last_sy = sy; + */ + } + break; + + case ED_CTRL_ID_FLOOD_FILL: + if (!button) + break; + + if (button_press_event && Feld[lx][ly] != new_element) + { + FloodFill(lx, ly, new_element); + DrawMiniLevel(level_xpos, level_ypos); + copy_to_undo_buffer = TRUE; + } + break; + + default: + break; + } + + last_element = new_element; + + if (copy_to_undo_buffer) + { + 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