+
+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<lev_fieldy; y++)
+ {
+ for(x=0; x<lev_fieldx; x++)
+ {
+ if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
+ {
+ Feld[x][y] = EL_LEERRAUM;
+ if (x - level_xpos >= 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<lev_fieldx; x++)
+ for(y=0; y<lev_fieldy; y++)
+ UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
+
+ copy_to_undo_buffer = FALSE;
+
+ printf("state saved to undo buffer %d\n", undo_buffer_position);
+ }
+}