X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Feditor.c;h=bcecaa8848529d57450a55acb412473da730a1b5;hb=b5d58347438b481c0f071df7281a1453566951ba;hp=17677e8dec42d4520c39a2d481f87a50c5f0f030;hpb=1256664ceac31f448a0139edd3bd0dc8fa5a8697;p=rocksndiamonds.git diff --git a/src/editor.c b/src/editor.c index 17677e8d..bcecaa88 100644 --- a/src/editor.c +++ b/src/editor.c @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * editor.c * ***********************************************************/ @@ -19,9 +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 + +/* 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; @@ -84,6 +158,11 @@ int editor_element[] = EL_CHAR_A + ('N' - 'A'), EL_CHAR_A + ('E' - 'A'), + EL_SPIELER1, + EL_SPIELER2, + EL_SPIELER3, + EL_SPIELER4, + EL_SPIELFIGUR, EL_LEERRAUM, EL_ERDREICH, @@ -200,9 +279,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'), @@ -317,9 +396,339 @@ 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_CLEAR: + if (Request("Are you sure to clear this level ?", REQ_ASK)) + { + 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 && my0) || (choice == ED_BUTTON_EDOWN && element_shift=0) { - if (!DelayReached(&choice_delay,10)) + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -763,7 +1163,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,10)) + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -780,7 +1180,7 @@ void LevelEd(int mx, int my, int button) case ED_BUTTON_UP: if (level_ypos>=0) { - if (!DelayReached(&choice_delay,10)) + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -797,7 +1197,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,10)) + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -815,6 +1215,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,10)) + if (choice >= 0 && choice < 36 && + DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) { if (!(choice % 2)) step = -step; @@ -989,6 +1401,10 @@ void LevelEd(int mx, int my, int button) XFlush(display); } + + +#if 0 + switch(CheckCtrlButtons(mx,my,button)) { case ED_BUTTON_EDIT: @@ -1003,7 +1419,7 @@ void LevelEd(int mx, int my, int button) edit_mode = TRUE; 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 && @@ -1244,3 +1664,333 @@ 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) + undo_buffer_steps++; + + for(x=0; x