/*********************************************************** * Mirror Magic -- McDuffin's Revenge * *----------------------------------------------------------* * (c) 1994-2001 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tools.c * ***********************************************************/ #include #ifdef __FreeBSD__ #include #endif #include "libgame/libgame.h" #include "tools.h" #include "game.h" #include "events.h" #include "cartoons.h" #ifdef MSDOS extern boolean wait_for_vsync; #endif /* tool button identifiers */ #define TOOL_CTRL_ID_YES 0 #define TOOL_CTRL_ID_NO 1 #define TOOL_CTRL_ID_CONFIRM 2 #define NUM_TOOL_BUTTONS 3 /* forward declaration for internal use */ static int getGraphicAnimationPhase(int, int, int); static void UnmapToolButtons(); static void HandleToolButtons(struct GadgetInfo *); static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS]; static int request_gadget_id = -1; void SetDrawtoField(int mode) { /* DRAW_DIRECT, DRAW_BACKBUFFER */ FX = SX; FY = SY; BX1 = 0; BY1 = 0; BX2 = SCR_FIELDX - 1; BY2 = SCR_FIELDY - 1; redraw_x1 = 0; redraw_y1 = 0; drawto_field = backbuffer; } void BackToFront() { int x,y; DrawBuffer *buffer = drawto_field; if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD) redraw_mask |= REDRAW_FIELD; if (redraw_mask & REDRAW_FIELD) redraw_mask &= ~REDRAW_TILES; if (!redraw_mask) return; if (global.fps_slowdown && game_status == PLAYING) { static boolean last_frame_skipped = FALSE; boolean skip_even_when_not_scrolling = TRUE; boolean just_scrolling = (ScreenMovDir != 0); boolean verbose = FALSE; if (global.fps_slowdown_factor > 1 && (FrameCounter % global.fps_slowdown_factor) && (just_scrolling || skip_even_when_not_scrolling)) { redraw_mask &= ~REDRAW_MAIN; last_frame_skipped = TRUE; if (verbose) printf("FRAME SKIPPED\n"); } else { if (last_frame_skipped) redraw_mask |= REDRAW_FIELD; last_frame_skipped = FALSE; if (verbose) printf("frame not skipped\n"); } } /* synchronize X11 graphics at this point; if we would synchronize the display immediately after the buffer switching (after the XFlush), this could mean that we have to wait for the graphics to complete, although we could go on doing calculations for the next frame */ SyncDisplay(); if (redraw_mask & REDRAW_ALL) { BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); redraw_mask = 0; } if (redraw_mask & REDRAW_FIELD) { BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); redraw_mask &= ~REDRAW_MAIN; } if (redraw_mask & REDRAW_DOORS) { if (redraw_mask & REDRAW_DOOR_1) BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY); redraw_mask &= ~REDRAW_DOORS; } if (redraw_mask & REDRAW_MICROLEVEL) { BlitBitmap(backbuffer, window, MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE, MICROLEV_XPOS, MICROLEV_YPOS); redraw_mask &= ~REDRAW_MICROLEVEL; } if (redraw_mask & REDRAW_MICROLABEL) { BlitBitmap(backbuffer, window, MICROLABEL_XPOS, MICROLABEL_YPOS, MICROLABEL_XSIZE, MICROLABEL_YSIZE, MICROLABEL_XPOS, MICROLABEL_YPOS); redraw_mask &= ~REDRAW_MICROLABEL; } if (redraw_mask & REDRAW_TILES) { for(x=0; x= GFX_START_MIRRORSCREEN && graphic <= GFX_END_MIRRORSCREEN) { graphic -= GFX_START_MIRRORSCREEN; *bitmap_nr = PIX_BACK; *x = SX + (graphic % GFX_PER_LINE) * TILEX; *y = SY + (graphic / GFX_PER_LINE) * TILEY; } else if (graphic >= GFX_START_MIRRORFONT && graphic <= GFX_END_MIRRORFONT) { graphic -= GFX_START_MIRRORFONT; *bitmap_nr = PIX_BIGFONT; *x = (graphic % FONT_CHARS_PER_LINE) * TILEX; *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY + FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY); } else if (graphic >= GFX_START_MIRRORDF && graphic <= GFX_END_MIRRORDF) { graphic -= GFX_START_MIRRORDF; *bitmap_nr = PIX_DF; *x = (graphic % DF_PER_LINE) * TILEX; *y = (graphic / DF_PER_LINE) * TILEY; } else { *bitmap_nr = PIX_BIGFONT; *x = 0; *y = 0; } } void DrawGraphic(int x, int y, int graphic) { #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphic(): This should never happen!\n"); #if 1 { int i=0; i=i/i; } #endif return; } #endif DrawGraphicExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic); MarkTileDirty(x, y); } void DrawGraphicExt(DrawBuffer *d, int x, int y, int graphic) { int bitmap_nr; int src_x, src_y; getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y); BlitBitmap(pix[bitmap_nr], d, src_x, src_y, TILEX, TILEY, x, y); } void DrawGraphicThruMask(int x, int y, int graphic) { #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphicThruMask(): This should never happen!\n"); return; } #endif DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic); MarkTileDirty(x,y); } void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic) { int tile = graphic; int bitmap_nr; int src_x, src_y; Bitmap *src_bitmap; GC drawing_gc; if (graphic == GFX_EMPTY) return; getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y); src_bitmap = pix[bitmap_nr]; drawing_gc = pix[bitmap_nr]->stored_clip_gc; if (tile_clipmask[tile] != None) { SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]); SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y); } else { #if DEBUG #ifndef TARGET_SDL printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile); #endif #endif SetClipOrigin(src_bitmap, drawing_gc, dest_x-src_x, dest_y-src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y); } } void DrawMiniGraphic(int x, int y, int graphic) { DrawMiniGraphicExt(drawto, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic); MarkTileDirty(x/2, y/2); } void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) { if (graphic >= GFX_START_MIRRORSCREEN && graphic <= GFX_END_MIRRORSCREEN) { graphic -= GFX_START_MIRRORSCREEN; *bitmap = pix[PIX_BACK]; *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX; *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY; } else if (graphic >= GFX_START_PSEUDO && graphic <= GFX_END_PSEUDO) { if (graphic == GFX_DF_WALL_STEEL || graphic == GFX_DF_WALL_WOOD) { int graphic2 = GFX_DF_WALL_SEVERAL - GFX_START_MIRRORDF; *bitmap = pix[PIX_DF]; *x = (graphic2 % DF_PER_LINE) * TILEX; *y = (graphic2 / DF_PER_LINE) * TILEY; if (graphic == GFX_DF_WALL_WOOD) *x += MINI_TILEX; } else { int graphic2 = GFX_WALL_SEVERAL - GFX_START_MIRRORSCREEN; *bitmap = pix[PIX_BACK]; *x = GFX_STARTX + (graphic2 % GFX_PER_LINE) * TILEX; *y = GFX_STARTY + (graphic2 / GFX_PER_LINE) * TILEY; if (graphic == GFX_WALL_WOOD || graphic == GFX_WALL_AMOEBA) *x += MINI_TILEX; if (graphic == GFX_WALL_ICE || graphic == GFX_WALL_AMOEBA) *y += MINI_TILEY; } } else if (graphic >= GFX_START_MIRRORFONT && graphic <= GFX_END_MIRRORFONT) { graphic -= GFX_START_MIRRORFONT; *bitmap = pix[PIX_SMALLFONT]; *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE; *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE + FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT); } else if (graphic >= GFX_START_MIRRORDF && graphic <= GFX_END_MIRRORDF) { graphic -= GFX_START_MIRRORDF; *bitmap = pix[PIX_DF]; *x = MINI_DF_STARTX + (graphic % MINI_DF_PER_LINE) * MINI_TILEX; *y = MINI_DF_STARTY + (graphic / MINI_DF_PER_LINE) * MINI_TILEY; } else { *bitmap = pix[PIX_BIGFONT]; *x = 0; *y = 0; } } void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) { if (graphic >= GFX_START_MIRRORSCREEN && graphic <= GFX_END_MIRRORSCREEN) { graphic -= GFX_START_MIRRORSCREEN; *bitmap = pix[PIX_BACK]; *x = MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX; *y = MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY; } else if (graphic >= GFX_START_PSEUDO && graphic <= GFX_END_PSEUDO) { if (graphic == GFX_DF_WALL_STEEL || graphic == GFX_DF_WALL_WOOD) { int graphic2 = GFX_DF_WALL_SEVERAL - GFX_START_MIRRORDF; *bitmap = pix[PIX_DF]; *x = MICRO_DF_STARTX + (graphic2 % MICRO_DF_PER_LINE) * MICRO_TILEX; *y = MICRO_DF_STARTY + (graphic2 / MICRO_DF_PER_LINE) * MICRO_TILEY; if (graphic == GFX_DF_WALL_WOOD) *x += MICRO_WALLX; } else { int graphic2 = GFX_WALL_SEVERAL - GFX_START_MIRRORSCREEN; *bitmap = pix[PIX_BACK]; *x = MICRO_GFX_STARTX + (graphic2 % MICRO_GFX_PER_LINE) * MICRO_TILEX; *y = MICRO_GFX_STARTY + (graphic2 / MICRO_GFX_PER_LINE) * MICRO_TILEY; if (graphic == GFX_WALL_WOOD || graphic == GFX_WALL_AMOEBA) *x += MICRO_WALLX; if (graphic == GFX_WALL_ICE || graphic == GFX_WALL_AMOEBA) *y += MICRO_WALLY; } } else if (graphic >= GFX_START_MIRRORFONT && graphic <= GFX_END_MIRRORFONT) { graphic -= GFX_START_MIRRORFONT; *bitmap = pix[PIX_DF]; *x = MICRO_FONT_STARTX + (graphic % MICRO_FONT_PER_LINE) * MICRO_TILEX; *y = MICRO_FONT_STARTY + (graphic / MICRO_FONT_PER_LINE) * MICRO_TILEY; } else if (graphic >= GFX_START_MIRRORDF && graphic <= GFX_END_MIRRORDF) { graphic -= GFX_START_MIRRORDF; *bitmap = pix[PIX_DF]; *x = MICRO_DF_STARTX + (graphic % MICRO_DF_PER_LINE) * MICRO_TILEX; *y = MICRO_DF_STARTY + (graphic / MICRO_DF_PER_LINE) * MICRO_TILEY; } else { *bitmap = pix[PIX_BIGFONT]; *x = 0; *y = 0; } } void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic) { Bitmap *bitmap; int src_x, src_y; getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y); } void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode, int mask_mode) { int width = TILEX, height = TILEY; int cx = 0, cy = 0; int src_x, src_y, dest_x, dest_y; int tile = graphic; int bitmap_nr; Bitmap *src_bitmap; GC drawing_gc; if (graphic < 0) { DrawGraphic(x, y, graphic); return; } if (dx || dy) /* Verschiebung der Grafik? */ { if (x < BX1) /* Element kommt von links ins Bild */ { x = BX1; width = dx; cx = TILEX - dx; dx = 0; } else if (x > BX2) /* Element kommt von rechts ins Bild */ { x = BX2; width = -dx; dx = TILEX + dx; } else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */ { width += dx; cx = -dx; dx = 0; } else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */ width -= dx; else if (dx) /* allg. Bewegung in x-Richtung */ MarkTileDirty(x + SIGN(dx), y); if (y < BY1) /* Element kommt von oben ins Bild */ { if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */ return; y = BY1; height = dy; cy = TILEY - dy; dy = 0; } else if (y > BY2) /* Element kommt von unten ins Bild */ { y = BY2; height = -dy; dy = TILEY + dy; } else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */ { height += dy; cy = -dy; dy = 0; } else if (dy > 0 && cut_mode == CUT_ABOVE) { if (y == BY2) /* Element unterhalb des Bildes */ return; height = dy; cy = TILEY - dy; dy = TILEY; MarkTileDirty(x, y + 1); } /* Element verläßt unten das Bild */ else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW)) height -= dy; else if (dy) /* allg. Bewegung in y-Richtung */ MarkTileDirty(x, y + SIGN(dy)); } getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y); src_bitmap = pix[bitmap_nr]; drawing_gc = pix[bitmap_nr]->stored_clip_gc; src_x += cx; src_y += cy; dest_x = FX + x * TILEX + dx; dest_y = FY + y * TILEY + dy; #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphicShifted(): This should never happen!\n"); return; } #endif if (mask_mode == USE_MASKING) { if (tile_clipmask[tile] != None) { SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]); SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y); BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, TILEX, TILEY, dest_x, dest_y); } else { #if DEBUG #ifndef TARGET_SDL printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile); #endif #endif SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y); BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dest_x, dest_y); } } else BlitBitmap(pix[bitmap_nr], drawto_field, src_x, src_y, width, height, dest_x, dest_y); MarkTileDirty(x,y); } void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic, int cut_mode) { DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING); } void DrawScreenElementExt(int x, int y, int dx, int dy, int element, int cut_mode, int mask_mode) { int ux = LEVELX(x), uy = LEVELY(y); int graphic = el2gfx(element); int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8); int phase2 = phase8 / 4; int dir = MovDir[ux][uy]; if (element == EL_PACMAN) { graphic += 4 * !phase2; if (dir == MV_UP) graphic += 1; else if (dir == MV_LEFT) graphic += 2; else if (dir == MV_DOWN) graphic += 3; } if (dx || dy) DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode); else if (mask_mode == USE_MASKING) DrawGraphicThruMask(x, y, graphic); else DrawGraphic(x, y, graphic); } void DrawLevelElementExt(int x, int y, int dx, int dy, int element, int cut_mode, int mask_mode) { if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element, cut_mode, mask_mode); } void DrawScreenElementShifted(int x, int y, int dx, int dy, int element, int cut_mode) { DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING); } void DrawLevelElementShifted(int x, int y, int dx, int dy, int element, int cut_mode) { DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING); } void DrawScreenElementThruMask(int x, int y, int element) { DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); } void DrawLevelElementThruMask(int x, int y, int element) { DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); } void DrawLevelFieldThruMask(int x, int y) { DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING); } void DrawScreenElement(int x, int y, int element) { DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING); } void DrawLevelElement(int x, int y, int element) { if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) DrawScreenElement(SCREENX(x), SCREENY(y), element); } void DrawScreenField(int x, int y) { int element = Feld[x][y]; if (!IN_LEV_FIELD(x, y)) return; if (IS_MOVING(x, y)) { int horiz_move = (MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT); DrawScreenElement(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted(x, y, MovPos[x][y], 0, element, NO_CUTTING); else DrawScreenElementShifted(x, y, 0, MovPos[x][y], element, NO_CUTTING); } else if (IS_BLOCKED(x, y)) { int oldx, oldy; int sx, sy; int horiz_move; Blocked2Moving(x, y, &oldx, &oldy); sx = SCREENX(oldx); sy = SCREENY(oldy); horiz_move = (MovDir[oldx][oldy] == MV_LEFT || MovDir[oldx][oldy] == MV_RIGHT); DrawScreenElement(x, y, EL_EMPTY); element = Feld[oldx][oldy]; if (horiz_move) DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING); else DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,NO_CUTTING); } else if (IS_DRAWABLE(element)) DrawScreenElement(x, y, element); else DrawScreenElement(x, y, EL_EMPTY); } void DrawLevelField(int x, int y) { DrawScreenField(x, y); } void DrawMiniElement(int x, int y, int element) { int graphic; if (!element) { DrawMiniGraphic(x, y, GFX_EMPTY); return; } graphic = el2gfx(element); DrawMiniGraphic(x, y, graphic); } void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y) { int x = sx + scroll_x, y = sy + scroll_y; if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy) DrawMiniElement(sx, sy, EL_EMPTY); else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy) DrawMiniElement(sx, sy, Feld[x][y]); } #if 0 void DrawMicroElement(int xpos, int ypos, int element) { int graphic; if (element == EL_LEERRAUM) return; graphic = el2gfx(element); BlitBitmap(pix[PIX_BACK], drawto, MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX, MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY, MICRO_TILEX, MICRO_TILEY, xpos, ypos); } void DrawLevel() { int x,y; ClearWindow(); for(x=BX1; x<=BX2; x++) for(y=BY1; y<=BY2; y++) DrawScreenField(x, y); redraw_mask |= REDRAW_FIELD; } #endif void DrawField(int x, int y) { int element = Feld[x][y]; DrawElement(x, y, element); } void DrawLevel() { int x,y; ClearWindow(); for (x=0; ximported_from : ""), MAX_MICROLABEL_SIZE); label_text[MAX_MICROLABEL_SIZE] = '\0'; if (strlen(label_text) > 0) { int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2; int lypos = MICROLABEL_YPOS; DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2); } redraw_mask |= REDRAW_MICROLABEL; } void DrawMicroLevel(int xpos, int ypos, boolean restart) { static unsigned long scroll_delay = 0; static unsigned long label_delay = 0; static int label_state, label_counter; if (restart) { label_state = 1; label_counter = 0; DrawMicroLevelExt(xpos, ypos); DrawMicroLevelLabelExt(label_state); /* initialize delay counters */ DelayReached(&scroll_delay, 0); DelayReached(&label_delay, 0); return; } /* redraw micro level label, if needed */ if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 && strcmp(level.author, ANONYMOUS_NAME) != 0 && strcmp(level.author, leveldir_current->name) != 0 && DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY)) { int max_label_counter = 23; if (leveldir_current->imported_from != NULL) max_label_counter += 14; label_counter = (label_counter + 1) % max_label_counter; label_state = (label_counter >= 0 && label_counter <= 7 ? MICROLABEL_LEVEL_NAME : label_counter >= 9 && label_counter <= 12 ? MICROLABEL_CREATED_BY : label_counter >= 14 && label_counter <= 21 ? MICROLABEL_LEVEL_AUTHOR : label_counter >= 23 && label_counter <= 26 ? MICROLABEL_IMPORTED_FROM : label_counter >= 28 && label_counter <= 35 ? MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY); DrawMicroLevelLabelExt(label_state); } } int REQ_in_range(int x, int y) { if (y > DY+249 && y < DY+278) { if (x > DX+1 && x < DX+48) return 1; else if (x > DX+51 && x < DX+98) return 2; } return 0; } boolean Request(char *text, unsigned int req_state) { int mx, my, ty, result = -1; unsigned int old_door_state; old_door_state = GetDoorState(); UnmapAllGadgets(); CloseDoor(DOOR_CLOSE_1); /* save old door content */ BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1); /* clear door drawing field */ ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE); /* write text for request */ for(ty=0; ty<13; ty++) { int tx, tl, tc; char txt[256]; if (!*text) break; for(tl=0,tx=0; tx<7; tl++,tx++) { tc = *(text + tx); if (!tc || tc == 32) break; } if (!tl) { text++; ty--; continue; } sprintf(txt, text); txt[tl] = 0; DrawTextExt(drawto, DX + 51 - (tl * 14)/2, DY + 8 + ty * 16, txt, FS_SMALL, FC_YELLOW); text += tl + (tc == 32 ? 1 : 0); } if (req_state & REQ_ASK) { MapGadget(tool_gadget[TOOL_CTRL_ID_YES]); MapGadget(tool_gadget[TOOL_CTRL_ID_NO]); } else if (req_state & REQ_CONFIRM) { MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]); } /* copy request gadgets to door backbuffer */ BlitBitmap(drawto, pix[PIX_DB_DOOR], DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); OpenDoor(DOOR_OPEN_1); #if 0 ClearEventQueue(); #endif if (!(req_state & REQUEST_WAIT_FOR)) return(FALSE); if (game_status != MAINMENU) InitAnimation(); button_status = MB_RELEASED; request_gadget_id = -1; while(result < 0) { if (PendingEvent()) { Event event; NextEvent(&event); switch(event.type) { case EVENT_BUTTONPRESS: case EVENT_BUTTONRELEASE: case EVENT_MOTIONNOTIFY: { if (event.type == EVENT_MOTIONNOTIFY) { if (!PointerInWindow(window)) continue; /* window and pointer are on different screens */ if (!button_status) continue; motion_status = TRUE; mx = ((MotionEvent *) &event)->x; my = ((MotionEvent *) &event)->y; } else { motion_status = FALSE; mx = ((ButtonEvent *) &event)->x; my = ((ButtonEvent *) &event)->y; if (event.type == EVENT_BUTTONPRESS) button_status = ((ButtonEvent *) &event)->button; else button_status = MB_RELEASED; } /* this sets 'request_gadget_id' */ HandleGadgets(mx, my, button_status); switch(request_gadget_id) { case TOOL_CTRL_ID_YES: result = TRUE; break; case TOOL_CTRL_ID_NO: result = FALSE; break; case TOOL_CTRL_ID_CONFIRM: result = TRUE | FALSE; break; default: break; } break; } case EVENT_KEYPRESS: switch(GetEventKey((KeyEvent *)&event, TRUE)) { case KSYM_Return: result = 1; break; case KSYM_Escape: result = 0; break; default: break; } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } DoAnimation(); /* don't eat all CPU time */ Delay(10); } if (game_status != MAINMENU) StopAnimation(); UnmapToolButtons(); if (!(req_state & REQ_STAY_OPEN)) { CloseDoor(DOOR_CLOSE_1); if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1)) { BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1); OpenDoor(DOOR_OPEN_1); } } RemapAllGadgets(); return(result); } unsigned int OpenDoor(unsigned int door_state) { unsigned int new_door_state; if (door_state & DOOR_COPY_BACK) { BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); door_state &= ~DOOR_COPY_BACK; } new_door_state = MoveDoor(door_state); return(new_door_state); } unsigned int CloseDoor(unsigned int door_state) { unsigned int new_door_state; BlitBitmap(backbuffer, pix[PIX_DB_DOOR], DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); new_door_state = MoveDoor(door_state); return(new_door_state); } unsigned int GetDoorState() { return(MoveDoor(DOOR_GET_STATE)); } unsigned int MoveDoor(unsigned int door_state) { static int door1 = DOOR_OPEN_1; static int door2 = DOOR_CLOSE_2; static unsigned long door_delay = 0; int x, start, stepsize = 2; unsigned long door_delay_value = stepsize * 5; /* there is no second door */ door_state &= ~DOOR_ACTION_2; if (door_state == DOOR_GET_STATE) return(door1 | door2); if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1) door_state &= ~DOOR_OPEN_1; else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1) door_state &= ~DOOR_CLOSE_1; if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2) door_state &= ~DOOR_OPEN_2; else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2) door_state &= ~DOOR_CLOSE_2; if (setup.quick_doors) { stepsize = 20; door_delay_value = 0; StopSound(SND_OEFFNEN); } if (door_state & DOOR_ACTION) { if (door_state & DOOR_ACTION_1) { if (door_state & DOOR_OPEN_1) { BlitBitmap(pix[PIX_DOOR], pix[PIX_DOOR], 104,136, 8,8, 146,136); BlitBitmap(pix[PIX_DOOR], window, 104,136, 8,8, DX + 46,DY + 136); redraw_mask &= ~REDRAW_DOOR_1; if (!setup.quick_doors) { #if 0 int i; for (i=0; i<30; i++) { ColorCycling(); if (game_status == MAINMENU) DoAnimation(); Delay(10); } #else Delay(100); #endif } } else BlitBitmap(pix[PIX_DOOR], pix[PIX_DOOR], 88,136, 8,8, 146,136); if (!(door_state & DOOR_NO_DELAY)) PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT); } start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0); for(x=start; x<=DXSIZE; x+=stepsize) { Bitmap *bitmap = pix[PIX_DOOR]; GC gc = bitmap->stored_clip_gc; WaitUntilDelayReached(&door_delay, door_delay_value); if (door_state & DOOR_ACTION_1) { int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x); if (x < DXSIZE || door_state & DOOR_OPEN_1) { BlitBitmap(pix[PIX_DB_DOOR], drawto, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2, DXSIZE,DYSIZE - i/2, DX, DY); ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE, i/2); } else ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE); SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1, i, 30, DX, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1 + DYSIZE - 30, i, 30, DX, DY + DYSIZE - 30); SetClipOrigin(bitmap, gc, DX - i, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1, i, 30, DX + DXSIZE - i, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1 + DYSIZE - 30, i, 30, DX + DXSIZE - i, DY + DYSIZE - 30); if (i > 14) { SetClipOrigin(bitmap, gc, DX - i, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE + 14, DOOR_GFX_PAGEY1 + 30, i - 14, DYSIZE - 60, DX + DXSIZE + 14 - i, DY + 30); SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1 + 30, i - 14, DYSIZE - 60, DX, DY + 30); } redraw_mask |= REDRAW_DOOR_1; } BackToFront(); if (game_status == MAINMENU) DoAnimation(); } } if (setup.quick_doors) StopSound(SND_OEFFNEN); if (door_state & DOOR_ACTION_1) door1 = door_state & DOOR_ACTION_1; if (door_state & DOOR_ACTION_2) door2 = door_state & DOOR_ACTION_2; return (door1 | door2); } #if 0 void DrawSpecialEditorDoor() { /* draw bigger toolbox window */ BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12); redraw_mask |= REDRAW_ALL; } void UndrawSpecialEditorDoor() { /* draw normal tape recorder window */ BlitBitmap(pix[PIX_BACK], drawto, 562, 344, 108, 56, EX - 4, EY - 12); redraw_mask |= REDRAW_ALL; } #endif Pixel ReadPixel(DrawBuffer *bitmap, int x, int y) { #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO) return GetPixel(bitmap, x, y); #else /* GetPixel() does also work for X11, but we use some optimization here */ unsigned long pixel_value; if (bitmap == pix[PIX_BACK]) { /* when reading pixel values from images, it is much faster to use client side images (XImage) than server side images (Pixmap) */ static XImage *client_image = NULL; if (client_image == NULL) /* init image cache, if not existing */ client_image = XGetImage(display, bitmap->drawable, 0,0, WIN_XSIZE,WIN_YSIZE, AllPlanes, ZPixmap); pixel_value = XGetPixel(client_image, x, y); } else { XImage *pixel_image; pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1, AllPlanes, ZPixmap); pixel_value = XGetPixel(pixel_image, 0, 0); XDestroyImage(pixel_image); } return pixel_value; #endif } void SetRGB(unsigned long pixel, unsigned short red, unsigned short green, unsigned short blue) { return; #if 0 XColor color; if (color_status==STATIC_COLORS) return; color.pixel = pixel; color.red = red; color.green = green; color.blue = blue; color.flags = DoRed | DoGreen | DoBlue; XStoreColor(display, cmap, &color); XFlush(display); #endif } /* ---------- new tool button stuff ---------------------------------------- */ /* graphic position values for tool buttons */ #define TOOL_BUTTON_YES_XPOS 2 #define TOOL_BUTTON_YES_YPOS 250 #define TOOL_BUTTON_YES_GFX_YPOS 0 #define TOOL_BUTTON_YES_XSIZE 46 #define TOOL_BUTTON_YES_YSIZE 28 #define TOOL_BUTTON_NO_XPOS 52 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30 #define TOOL_BUTTON_CONFIRM_XSIZE 96 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE static struct { int xpos, ypos; int x, y; int width, height; int gadget_id; char *infotext; } toolbutton_info[NUM_TOOL_BUTTONS] = { { TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS, TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS, TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE, TOOL_CTRL_ID_YES, "yes" }, { TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS, TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS, TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE, TOOL_CTRL_ID_NO, "no" }, { TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS, TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS, TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE, TOOL_CTRL_ID_CONFIRM, "confirm" } }; static void DoNotDisplayInfoText(void *ptr) { return; } void CreateToolButtons() { int i; for (i=0; icustom_id; } /* ------------------------------------------------------------------------- */ int get_base_element(int element) { if (IS_MIRROR(element)) return EL_MIRROR_START; else if (IS_MIRROR_FIXED(element)) return EL_MIRROR_FIXED_START; else if (IS_POLAR(element)) return EL_POLAR_START; else if (IS_POLAR_CROSS(element)) return EL_POLAR_CROSS_START; else if (IS_BEAMER(element)) return EL_BEAMER_RED_START + BEAMER_NR(element) * 16; else if (IS_FIBRE_OPTIC(element)) return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2; else if (IS_MCDUFFIN(element)) return EL_MCDUFFIN_START; else if (IS_LASER(element)) return EL_LASER_START; else if (IS_RECEIVER(element)) return EL_RECEIVER_START; else if (IS_DF_MIRROR(element)) return EL_DF_MIRROR_START; else if (IS_DF_MIRROR_AUTO(element)) return EL_DF_MIRROR_AUTO_START; else if (IS_PACMAN(element)) return EL_PACMAN_START; else if (IS_GRID_STEEL(element)) return EL_GRID_STEEL_START; else if (IS_GRID_WOOD(element)) return EL_GRID_WOOD_START; else if (IS_GRID_STEEL_FIXED(element)) return EL_GRID_STEEL_FIXED_START; else if (IS_GRID_WOOD_FIXED(element)) return EL_GRID_WOOD_FIXED_START; else if (IS_GRID_STEEL_AUTO(element)) return EL_GRID_STEEL_AUTO_START; else if (IS_GRID_WOOD_AUTO(element)) return EL_GRID_WOOD_AUTO_START; else if (IS_WALL_STEEL(element)) return EL_WALL_STEEL_START; else if (IS_WALL_WOOD(element)) return EL_WALL_WOOD_START; else if (IS_WALL_ICE(element)) return EL_WALL_ICE_START; else if (IS_WALL_AMOEBA(element)) return EL_WALL_AMOEBA_START; else if (IS_DF_WALL_STEEL(element)) return EL_DF_WALL_STEEL_START; else if (IS_DF_WALL_WOOD(element)) return EL_DF_WALL_WOOD_START; else if (IS_CHAR(element)) return EL_CHAR_START; else return element; } int get_element_phase(int element) { return element - get_base_element(element); } int get_num_elements(int element) { if (IS_MIRROR(element) || IS_POLAR(element) || IS_BEAMER(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element)) return 16; else if (IS_GRID_STEEL_FIXED(element) || IS_GRID_WOOD_FIXED(element) || IS_GRID_STEEL_AUTO(element) || IS_GRID_WOOD_AUTO(element)) return 8; else if (IS_MIRROR_FIXED(element) || IS_POLAR_CROSS(element) || IS_MCDUFFIN(element) || IS_LASER(element) || IS_RECEIVER(element) || IS_PACMAN(element) || IS_GRID_STEEL(element) || IS_GRID_WOOD(element)) return 4; else return 1; } int get_rotated_element(int element, int step) { int base_element = get_base_element(element); int num_elements = get_num_elements(element); int element_phase = element - base_element; return base_element + (element_phase + step + num_elements) % num_elements; } int el2gfx(int element) { switch(element) { case EL_EMPTY: return -1; case EL_GRID_STEEL_00: return GFX_GRID_STEEL_00; case EL_GRID_STEEL_01: return GFX_GRID_STEEL_01; case EL_GRID_STEEL_02: return GFX_GRID_STEEL_02; case EL_GRID_STEEL_03: return GFX_GRID_STEEL_03; case EL_MCDUFFIN_RIGHT: return GFX_MCDUFFIN_RIGHT; case EL_MCDUFFIN_UP: return GFX_MCDUFFIN_UP; case EL_MCDUFFIN_LEFT: return GFX_MCDUFFIN_LEFT; case EL_MCDUFFIN_DOWN: return GFX_MCDUFFIN_DOWN; case EL_EXIT_CLOSED: return GFX_EXIT_CLOSED; case EL_EXIT_OPENING_1: return GFX_EXIT_OPENING_1; case EL_EXIT_OPENING_2: return GFX_EXIT_OPENING_2; case EL_EXIT_OPEN: return GFX_EXIT_OPEN; case EL_KETTLE: return GFX_KETTLE; case EL_BOMB: return GFX_BOMB; case EL_PRISM: return GFX_PRISM; case EL_BLOCK_WOOD: return GFX_BLOCK_WOOD; case EL_BALL_GRAY: return GFX_BALL_GRAY; case EL_FUSE_ON: return GFX_FUSE_ON; case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT; case EL_PACMAN_UP: return GFX_PACMAN_UP; case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT; case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN; case EL_POLAR_CROSS_00: return GFX_POLAR_CROSS_00; case EL_POLAR_CROSS_01: return GFX_POLAR_CROSS_01; case EL_POLAR_CROSS_02: return GFX_POLAR_CROSS_02; case EL_POLAR_CROSS_03: return GFX_POLAR_CROSS_03; case EL_MIRROR_FIXED_00: return GFX_MIRROR_FIXED_00; case EL_MIRROR_FIXED_01: return GFX_MIRROR_FIXED_01; case EL_MIRROR_FIXED_02: return GFX_MIRROR_FIXED_02; case EL_MIRROR_FIXED_03: return GFX_MIRROR_FIXED_03; case EL_GATE_STONE: return GFX_GATE_STONE; case EL_KEY: return GFX_KEY; case EL_LIGHTBULB_ON: return GFX_LIGHTBULB_ON; case EL_LIGHTBULB_OFF: return GFX_LIGHTBULB_OFF; case EL_LIGHTBALL: return GFX_BALL_RED + RND(3);; case EL_BLOCK_STONE: return GFX_BLOCK_STONE; case EL_GATE_WOOD: return GFX_GATE_WOOD; case EL_FUEL_FULL: return GFX_FUEL_FULL; case EL_GRID_WOOD_00: return GFX_GRID_WOOD_00; case EL_GRID_WOOD_01: return GFX_GRID_WOOD_01; case EL_GRID_WOOD_02: return GFX_GRID_WOOD_02; case EL_GRID_WOOD_03: return GFX_GRID_WOOD_03; case EL_FUEL_EMPTY: return GFX_FUEL_EMPTY; case EL_FUSE_OFF: return GFX_FUSE_OFF; case EL_PACMAN: return GFX_PACMAN; case EL_REFRACTOR: return GFX_REFRACTOR; case EL_CELL: return GFX_CELL; case EL_MINE: return GFX_MINE; /* pseudo-graphics; will be mapped to other graphics */ case EL_WALL_STEEL: return GFX_WALL_STEEL; case EL_WALL_WOOD: return GFX_WALL_WOOD; case EL_WALL_ICE: return GFX_WALL_ICE; case EL_WALL_AMOEBA: return GFX_WALL_AMOEBA; case EL_DF_WALL_STEEL: return GFX_DF_WALL_STEEL; case EL_DF_WALL_WOOD: return GFX_DF_WALL_WOOD; default: { boolean ed = (game_status == LEVELED); int base_element = get_base_element(element); int element_phase = element - base_element; int base_graphic; if (IS_BEAMER(element)) element_phase = element - EL_BEAMER_RED_START; else if (IS_FIBRE_OPTIC(element)) element_phase = element - EL_FIBRE_OPTIC_START; if (IS_MIRROR(element)) base_graphic = GFX_MIRROR_START; else if (IS_BEAMER_OLD(element)) base_graphic = GFX_BEAMER_START; else if (IS_POLAR(element)) base_graphic = GFX_POLAR_START; else if (IS_CHAR(element)) base_graphic = GFX_CHAR_START; else if (IS_GRID_WOOD_FIXED(element)) base_graphic = GFX_GRID_WOOD_FIXED_00; else if (IS_GRID_STEEL_FIXED(element)) base_graphic = GFX_GRID_STEEL_FIXED_00; else if (IS_DF_MIRROR(element)) base_graphic = GFX_DF_MIRROR_00; else if (IS_LASER(element)) base_graphic = GFX_LASER_RIGHT; else if (IS_RECEIVER(element)) base_graphic = GFX_RECEIVER_RIGHT; else if (IS_DF_MIRROR(element)) base_graphic = GFX_DF_MIRROR_00; else if (IS_FIBRE_OPTIC(element)) base_graphic = (ed ? GFX_FIBRE_OPTIC_ED_00 : GFX_FIBRE_OPTIC_00); else if (IS_GRID_WOOD_AUTO(element)) base_graphic = (ed ? GFX_GRID_WOOD_AUTO_00 : GFX_GRID_WOOD_FIXED_00); else if (IS_GRID_STEEL_AUTO(element)) base_graphic = (ed ? GFX_GRID_STEEL_AUTO_00 : GFX_GRID_STEEL_FIXED_00); else if (IS_DF_MIRROR_AUTO(element)) base_graphic = (ed ? GFX_DF_MIRROR_AUTO_00 : GFX_DF_MIRROR_00); else if (IS_BEAMER(element)) base_graphic = GFX_BEAMER_RED_START; else return GFX_EMPTY; return base_graphic + element_phase; } } }