rocksndiamonds-3.3.0.1+dfsg1/0000755000175000017500000000000011406341220014617 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/src/0000755000175000017500000000000011406341220015406 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/src/engines.h0000644000175000017500000000424611375336125017232 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * engines.h * ***********************************************************/ #ifndef ENGINES_H #define ENGINES_H #include "libgame/libgame.h" #include "game_em/export.h" #include "game_sp/export.h" #include "game.h" /* ========================================================================= */ /* functions and definitions exported from main program to game_em */ /* ========================================================================= */ extern void SetBitmaps_EM(Bitmap **); extern void UpdateEngineValues(int, int); extern void DrawAllGameValues(int, int, int, int, int); extern int getNumActivePlayers_EM(); extern int getGameFrameDelay_EM(int); extern void PlayLevelSound_EM(int, int, int, int); extern void InitGraphicInfo_EM(void); extern void CheckSingleStepMode_EM(byte action[], int, boolean); void SetGfxAnimation_EM(struct GraphicInfo_EM *, int, int, int, int); void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *, int, int, int, int); void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *, int, int, int); /* ========================================================================= */ /* functions and definitions exported from main program to game_sp */ /* ========================================================================= */ #if 0 extern void SetBitmaps_SP(Bitmap **); #endif void CheckSingleStepMode_SP(boolean); void getGraphicSource_SP(struct GraphicInfo_SP *, int, int, int, int); int getGraphicInfo_Delay(int); boolean isNextAnimationFrame_SP(int, int); #endif /* ENGINES_H */ rocksndiamonds-3.3.0.1+dfsg1/src/netserv.c0000644000175000017500000004417510556531343017267 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * netserv.c * ***********************************************************/ #include "libgame/platform.h" #if defined(NETWORK_AVALIABLE) #include #include #include #include #if defined(TARGET_SDL) #include "main.h" #else #include #include #include #include #include #include /* apparently needed for OS/2 port */ #endif #include "libgame/libgame.h" #include "netserv.h" static int clients = 0; static int onceonly = 0; struct NetworkServerPlayerInfo { #if defined(TARGET_SDL) TCPsocket fd; #else int fd; #endif char player_name[16]; unsigned char number; struct NetworkServerPlayerInfo *next; char active; char introduced; unsigned char readbuffer[MAX_BUFFER_SIZE]; unsigned char writbuffer[MAX_BUFFER_SIZE]; int nread, nwrite; byte action; boolean action_received; }; static struct NetworkServerPlayerInfo *first_player = NULL; #define NEXT(player) ((player)->next ? (player)->next : first_player) #if defined(TARGET_SDL) /* TODO: peer address */ static TCPsocket lfd; /* listening socket */ static SDLNet_SocketSet fds; /* socket set */ #else static struct sockaddr_in saddr; static int lfd; /* listening socket */ static fd_set fds; /* socket set */ static int tcp = -1; #endif static unsigned char realbuffer[512], *buffer = realbuffer + 4; static int interrupt; static unsigned long ServerFrameCounter = 0; static void addtobuffer(struct NetworkServerPlayerInfo *player, unsigned char *b, int len) { if (player->nwrite + len >= MAX_BUFFER_SIZE) Error(ERR_EXIT_NETWORK_SERVER, "internal error: network send buffer overflow"); memcpy(player->writbuffer + player->nwrite, b, len); player->nwrite += len; } static void flushuser(struct NetworkServerPlayerInfo *player) { if (player->nwrite) { #if defined(TARGET_SDL) SDLNet_TCP_Send(player->fd, player->writbuffer, player->nwrite); #else write(player->fd, player->writbuffer, player->nwrite); #endif player->nwrite = 0; } } static void broadcast(struct NetworkServerPlayerInfo *except, int len, int activeonly) { struct NetworkServerPlayerInfo *player; realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; realbuffer[3] = (unsigned char)len; for (player = first_player; player; player = player->next) if (player != except && player->introduced && (player->active || !activeonly)) addtobuffer(player, realbuffer, 4 + len); } static void sendtoone(struct NetworkServerPlayerInfo *to, int len) { realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; realbuffer[3] = (unsigned char)len; addtobuffer(to, realbuffer, 4 + len); } static void RemovePlayer(struct NetworkServerPlayerInfo *player) { struct NetworkServerPlayerInfo *v; if (options.verbose) Error(ERR_NETWORK_SERVER, "dropping client %d (%s)", player->number, player->player_name); if (player == first_player) first_player = player->next; else { for (v = first_player; v; v = v->next) { if (v->next && v->next == player) { v->next = player->next; break; } } } #if defined(TARGET_SDL) SDLNet_TCP_DelSocket(fds, player->fd); SDLNet_TCP_Close(player->fd); #else close(player->fd); #endif if (player->introduced) { buffer[0] = player->number; buffer[1] = OP_PLAYER_DISCONNECTED; broadcast(player, 2, 0); } free(player); clients--; if (onceonly && clients == 0) { if (options.verbose) { Error(ERR_NETWORK_SERVER, "no clients left"); Error(ERR_NETWORK_SERVER, "aborting"); } exit(0); } } #if defined(TARGET_SDL) static void AddPlayer(TCPsocket fd) #else static void AddPlayer(int fd) #endif { struct NetworkServerPlayerInfo *player, *v; unsigned char nxn; boolean again = TRUE; player = checked_malloc(sizeof (struct NetworkServerPlayerInfo)); player->fd = fd; player->player_name[0] = 0; player->next = first_player; player->active = 0; player->nread = 0; player->nwrite = 0; player->introduced = 0; player->action = 0; player->action_received = FALSE; #if defined(TARGET_SDL) SDLNet_TCP_AddSocket(fds, fd); #endif first_player = player; nxn = 1; while (again) { again = FALSE; v = player->next; while (v) { if (v->number == nxn) { nxn++; again = TRUE; break; } v = v->next; } } player->number = nxn; #if !defined(TARGET_SDL) if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d connecting from %s", nxn, inet_ntoa(saddr.sin_addr)); #endif clients++; buffer[0] = 0; buffer[1] = OP_YOUR_NUMBER; buffer[2] = player->number; sendtoone(player, 3); } static void Handle_OP_PROTOCOL_VERSION(struct NetworkServerPlayerInfo *player, unsigned int len) { if (len != 5 || buffer[2] != PROTOCOL_VERSION_1 || buffer[3] != PROTOCOL_VERSION_2) { if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) has wrong protocol version %d.%d.%d", player->number, player->player_name, buffer[2], buffer[3], buffer[4]); buffer[0] = 0; buffer[1] = OP_BAD_PROTOCOL_VERSION; buffer[2] = PROTOCOL_VERSION_1; buffer[3] = PROTOCOL_VERSION_2; buffer[4] = PROTOCOL_VERSION_3; sendtoone(player, 5); flushuser(player); RemovePlayer(player); interrupt = 1; } else { if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) uses protocol version %d.%d.%d", player->number, player->player_name, buffer[2], buffer[3], buffer[4]); } } static void Handle_OP_NUMBER_WANTED(struct NetworkServerPlayerInfo *player) { struct NetworkServerPlayerInfo *v; int client_nr = player->number; int nr_wanted = buffer[2]; int nr_is_free = 1; if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) wants to switch to # %d", player->number, player->player_name, nr_wanted); for (v = first_player; v; v = v->next) { if (v->number == nr_wanted) { nr_is_free = 0; break; } } if (options.verbose) { if (nr_is_free) Error(ERR_NETWORK_SERVER, "client %d (%s) switches to # %d", player->number, player->player_name, nr_wanted); else if (player->number == nr_wanted) Error(ERR_NETWORK_SERVER, "client %d (%s) already has # %d", player->number, player->player_name, nr_wanted); else Error(ERR_NETWORK_SERVER, "client %d (%s) cannot switch (client %d already exists)", player->number, player->player_name, nr_wanted); } if (nr_is_free) player->number = nr_wanted; buffer[0] = client_nr; buffer[1] = OP_NUMBER_WANTED; buffer[2] = nr_wanted; buffer[3] = player->number; /* sendtoone(player, 4); */ broadcast(NULL, 4, 0); } static void Handle_OP_PLAYER_NAME(struct NetworkServerPlayerInfo *player, unsigned int len) { struct NetworkServerPlayerInfo *v; int i; if (len>16) len=16; memcpy(player->player_name, &buffer[2], len-2); player->player_name[len-2] = 0; for (i = 0; i < len - 2; i++) { if (player->player_name[i] < ' ' || ((unsigned char)(player->player_name[i]) > 0x7e && (unsigned char)(player->player_name[i]) <= 0xa0)) { player->player_name[i] = 0; break; } } if (!player->introduced) { buffer[0] = player->number; buffer[1] = OP_PLAYER_CONNECTED; broadcast(player, 2, 0); } if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d calls itself \"%s\"", player->number, player->player_name); buffer[1] = OP_PLAYER_NAME; broadcast(player, len, 0); if (!player->introduced) { for (v = first_player; v; v = v->next) { if (v != player && v->introduced) { buffer[0] = v->number; buffer[1] = OP_PLAYER_CONNECTED; sendtoone(player, 2); buffer[1] = OP_PLAYER_NAME; memcpy(&buffer[2], v->player_name, 14); sendtoone(player, 2+strlen(v->player_name)); } } } player->introduced = 1; } static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) { struct NetworkServerPlayerInfo *v, *w; if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) starts game [level %d from leveldir %d (%s)]", player->number, player->player_name, (buffer[2] << 8) + buffer[3], (buffer[4] << 8) + buffer[5], &buffer[10]); for (w = first_player; w; w = w->next) if (w->introduced) w->active = 1; /* reset frame counter */ ServerFrameCounter = 0; Error(ERR_NETWORK_SERVER, "resetting ServerFrameCounter to 0"); /* reset player actions */ for (v = first_player; v; v = v->next) { v->action = 0; v->action_received = FALSE; } broadcast(NULL, 10 + strlen((char *)&buffer[10])+1, 0); } static void Handle_OP_PAUSE_PLAYING(struct NetworkServerPlayerInfo *player) { if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) pauses game", player->number, player->player_name); broadcast(NULL, 2, 0); } static void Handle_OP_CONTINUE_PLAYING(struct NetworkServerPlayerInfo *player) { if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) continues game", player->number, player->player_name); broadcast(NULL, 2, 0); } static void Handle_OP_STOP_PLAYING(struct NetworkServerPlayerInfo *player) { int cause_for_stopping = buffer[2]; if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) stops game [%d]", player->number, player->player_name, cause_for_stopping); broadcast(NULL, 3, 0); } static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) { struct NetworkServerPlayerInfo *v; int last_client_nr = 0; int i; /* store player action */ for (v = first_player; v; v = v->next) { if (v->number == player->number) { v->action = buffer[2]; v->action_received = TRUE; } } /* check if server received action from each player */ for (v = first_player; v; v = v->next) { if (!v->action_received) return; if (v->number > last_client_nr) last_client_nr = v->number; } /* initialize all player actions to zero */ for (i = 0; i < last_client_nr; i++) buffer[6 + i] = 0; /* broadcast actions of all players to all players */ for (v = first_player; v; v = v->next) { buffer[6 + v->number-1] = v->action; v->action = 0; v->action_received = FALSE; } buffer[2] = (unsigned char)((ServerFrameCounter >> 24) & 0xff); buffer[3] = (unsigned char)((ServerFrameCounter >> 16) & 0xff); buffer[4] = (unsigned char)((ServerFrameCounter >> 8) & 0xff); buffer[5] = (unsigned char)((ServerFrameCounter >> 0) & 0xff); broadcast(NULL, 6 + last_client_nr, 0); #if 0 Error(ERR_NETWORK_SERVER, "sending ServerFrameCounter value %d", ServerFrameCounter); #endif ServerFrameCounter++; } #if defined(TARGET_SDL) /* the following is not used for a standalone server; the pointer points to an integer containing the port-number */ int NetworkServerThread(void *ptr) { NetworkServer(*((int *) ptr), 0); /* should never be reached */ return 0; } #endif void NetworkServer(int port, int serveronly) { int sl; struct NetworkServerPlayerInfo *player; int r; unsigned int len; #if defined(TARGET_SDL) IPaddress ip; #else int i, on; int is_daemon = 0; struct protoent *tcpproto; struct timeval tv; int mfd; #endif #if defined(PLATFORM_UNIX) && !defined(PLATFORM_NEXT) struct sigaction sact; #endif if (port == 0) port = DEFAULT_SERVER_PORT; if (!serveronly) onceonly = 1; #if !defined(TARGET_SDL) if ((tcpproto = getprotobyname("tcp")) != NULL) tcp = tcpproto->p_proto; #endif #if defined(PLATFORM_UNIX) #if defined(PLATFORM_NEXT) signal(SIGPIPE, SIG_IGN); #else sact.sa_handler = SIG_IGN; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sigaction(SIGPIPE, &sact, NULL); #endif #endif #if defined(TARGET_SDL) /* assume that SDL is already initialized */ #if 0 if (SDLNet_Init() == -1) Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_Init() failed"); atexit(SDLNet_Quit); #endif if (SDLNet_ResolveHost(&ip, NULL, port) == -1) Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed"); lfd = SDLNet_TCP_Open(&ip); if (!lfd) Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed"); fds = SDLNet_AllocSocketSet(MAX_PLAYERS+1); SDLNet_TCP_AddSocket(fds, lfd); #else if ((lfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) Error(ERR_EXIT_NETWORK_SERVER, "socket() failed"); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(port); on = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)); if (bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) Error(ERR_EXIT_NETWORK_SERVER, "bind() failed"); listen(lfd, 5); #endif #if !defined(TARGET_SDL) if (is_daemon) { /* become a daemon, breaking all ties with the controlling terminal */ options.verbose = FALSE; for (i = 0; i < 255; i++) { if (i != lfd) close(i); } if (fork()) exit(0); setsid(); if (fork()) exit(0); chdir("/"); /* open a fake stdin, stdout, stderr, just in case */ open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); } #endif if (options.verbose) { Error(ERR_NETWORK_SERVER, "started up, listening on port %d", port); Error(ERR_NETWORK_SERVER, "using protocol version %d.%d.%d", PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3); } while (1) { interrupt = 0; for (player = first_player; player; player = player->next) flushuser(player); #if defined(TARGET_SDL) if ((sl = SDLNet_CheckSockets(fds, 500000)) < 1) { Error(ERR_NETWORK_SERVER, SDLNet_GetError()); perror("SDLNet_CheckSockets"); } #else FD_ZERO(&fds); mfd = lfd; player = first_player; while (player) { FD_SET(player->fd, &fds); if (player->fd > mfd) mfd = player->fd; player = player->next; } FD_SET(lfd, &fds); tv.tv_sec = 0; tv.tv_usec = 500000; if ((sl = select(mfd + 1, &fds, NULL, NULL, &tv)) < 0) { if (errno != EINTR) Error(ERR_EXIT_NETWORK_SERVER, "select() failed"); else continue; } #endif if (sl < 0) continue; if (sl == 0) continue; /* accept incoming connections */ #if defined(TARGET_SDL) if (SDLNet_SocketReady(lfd)) { TCPsocket newsock; newsock = SDLNet_TCP_Accept(lfd); if (newsock) AddPlayer(newsock); } #else if (FD_ISSET(lfd, &fds)) { int newfd; socklen_t slen; slen = sizeof(saddr); newfd = accept(lfd, (struct sockaddr *)&saddr, &slen); if (newfd < 0) { if (errno != EINTR) Error(ERR_EXIT_NETWORK_SERVER, "accept() failed"); } else { if (tcp != -1) { on = 1; setsockopt(newfd, tcp, TCP_NODELAY, (char *)&on, sizeof(int)); } AddPlayer(newfd); } continue; } #endif player = first_player; do { #if defined(TARGET_SDL) if (SDLNet_SocketReady(player->fd)) #else if (FD_ISSET(player->fd, &fds)) #endif { #if defined(TARGET_SDL) /* read only 1 byte, because SDLNet blocks when we want more than is in the buffer */ r = SDLNet_TCP_Recv(player->fd, player->readbuffer + player->nread, 1); #else r = read(player->fd, player->readbuffer + player->nread, MAX_BUFFER_SIZE - player->nread); #endif if (r <= 0) { if (options.verbose) Error(ERR_NETWORK_SERVER, "EOF from client %d (%s)", player->number, player->player_name); RemovePlayer(player); interrupt = 1; break; } player->nread += r; while (player->nread >= 4 && player->nread >= 4 + player->readbuffer[3]) { len = player->readbuffer[3]; if (player->readbuffer[0] || player->readbuffer[1] || player->readbuffer[2]) { if (options.verbose) Error(ERR_NETWORK_SERVER, "crap from client %d (%s)", player->number, player->player_name); RemovePlayer(player); interrupt = 1; break; } memcpy(buffer, &player->readbuffer[4], len); player->nread -= 4 + len; memmove(player->readbuffer, player->readbuffer + 4 + len, player->nread); buffer[0] = player->number; if (!player->introduced && buffer[1] != OP_PLAYER_NAME) { if (options.verbose) Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME)", buffer[0], buffer[1]); RemovePlayer(player); interrupt = 1; break; } switch (buffer[1]) { case OP_PLAYER_NAME: Handle_OP_PLAYER_NAME(player, len); break; case OP_PROTOCOL_VERSION: Handle_OP_PROTOCOL_VERSION(player, len); break; case OP_NUMBER_WANTED: Handle_OP_NUMBER_WANTED(player); break; case OP_START_PLAYING: Handle_OP_START_PLAYING(player); break; case OP_PAUSE_PLAYING: Handle_OP_PAUSE_PLAYING(player); break; case OP_CONTINUE_PLAYING: Handle_OP_CONTINUE_PLAYING(player); break; case OP_STOP_PLAYING: Handle_OP_STOP_PLAYING(player); break; case OP_MOVE_PLAYER: Handle_OP_MOVE_PLAYER(player); break; case OP_BROADCAST_MESSAGE: buffer[len] = '\0'; if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) sends message: %s", player->number, player->player_name, &buffer[2]); broadcast(player, len, 0); break; default: if (options.verbose) Error(ERR_NETWORK_SERVER, "unknown opcode %d from client %d (%s)", buffer[0], player->number, player->player_name); } } } if (player && !interrupt) player = player->next; } while (player && !interrupt); } } #endif /* NETWORK_AVALIABLE */ rocksndiamonds-3.3.0.1+dfsg1/src/files.c0000644000175000017500000112551511403455470016700 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * files.c * ***********************************************************/ #include #include #include #include #include "libgame/libgame.h" #include "files.h" #include "init.h" #include "tools.h" #include "tape.h" #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */ #define CHUNK_SIZE_NONE -1 /* do not write chunk size */ #define LEVEL_CHUNK_NAME_SIZE MAX_LEVEL_NAME_LEN #define LEVEL_CHUNK_AUTH_SIZE MAX_LEVEL_AUTHOR_LEN #define LEVEL_CHUNK_VERS_SIZE 8 /* size of file version chunk */ #define LEVEL_CHUNK_DATE_SIZE 4 /* size of file date chunk */ #define LEVEL_CHUNK_HEAD_SIZE 80 /* size of level file header */ #define LEVEL_CHUNK_HEAD_UNUSED 0 /* unused level header bytes */ #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */ #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */ #define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */ #define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */ #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */ #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */ #define LEVEL_CHUNK_GRP1_SIZE 74 /* size of level GRP1 chunk */ /* (element number, number of change pages, change page number) */ #define LEVEL_CHUNK_CUSX_UNCHANGED (2 + (1 + 1) + (1 + 1)) /* (element number only) */ #define LEVEL_CHUNK_GRPX_UNCHANGED 2 #define LEVEL_CHUNK_NOTE_UNCHANGED 2 /* (nothing at all if unchanged) */ #define LEVEL_CHUNK_ELEM_UNCHANGED 0 #define TAPE_CHUNK_VERS_SIZE 8 /* size of file version chunk */ #define TAPE_CHUNK_HEAD_SIZE 20 /* size of tape file header */ #define TAPE_CHUNK_HEAD_UNUSED 3 /* unused tape header bytes */ #define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x)) #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE) #define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48) /* file identifier strings */ #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x" #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" /* values for deciding when (not) to save configuration data */ #define SAVE_CONF_NEVER 0 #define SAVE_CONF_ALWAYS 1 #define SAVE_CONF_WHEN_CHANGED -1 /* values for chunks using micro chunks */ #define CONF_MASK_1_BYTE 0x00 #define CONF_MASK_2_BYTE 0x40 #define CONF_MASK_4_BYTE 0x80 #define CONF_MASK_MULTI_BYTES 0xc0 #define CONF_MASK_BYTES 0xc0 #define CONF_MASK_TOKEN 0x3f #define CONF_VALUE_1_BYTE(x) (CONF_MASK_1_BYTE | (x)) #define CONF_VALUE_2_BYTE(x) (CONF_MASK_2_BYTE | (x)) #define CONF_VALUE_4_BYTE(x) (CONF_MASK_4_BYTE | (x)) #define CONF_VALUE_MULTI_BYTES(x) (CONF_MASK_MULTI_BYTES | (x)) /* these definitions are just for convenience of use and readability */ #define CONF_VALUE_8_BIT(x) CONF_VALUE_1_BYTE(x) #define CONF_VALUE_16_BIT(x) CONF_VALUE_2_BYTE(x) #define CONF_VALUE_32_BIT(x) CONF_VALUE_4_BYTE(x) #define CONF_VALUE_BYTES(x) CONF_VALUE_MULTI_BYTES(x) #define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \ (x) == CONF_MASK_2_BYTE ? 2 : \ (x) == CONF_MASK_4_BYTE ? 4 : 0) #define CONF_CONTENT_NUM_ELEMENTS (3 * 3) #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2) #define CONF_ELEMENT_NUM_BYTES (2) #define CONF_ENTITY_NUM_BYTES(t) ((t) == TYPE_ELEMENT || \ (t) == TYPE_ELEMENT_LIST ? \ CONF_ELEMENT_NUM_BYTES : \ (t) == TYPE_CONTENT || \ (t) == TYPE_CONTENT_LIST ? \ CONF_CONTENT_NUM_BYTES : 1) #define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES) #define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \ (b[CONF_ELEMENT_BYTE_POS(i) + 1])) #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \ (y) * 3 + (x)) #define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * \ CONF_ELEMENT_NUM_BYTES) #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\ (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1])) /* temporary variables used to store pointers to structure members */ static struct LevelInfo li; static struct ElementInfo xx_ei, yy_ei; static struct ElementChangeInfo xx_change; static struct ElementGroupInfo xx_group; static struct EnvelopeInfo xx_envelope; static unsigned int xx_event_bits[NUM_CE_BITFIELDS]; static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1]; static int xx_num_contents; static int xx_current_change_page; static char xx_default_string_empty[1] = ""; static int xx_string_length_unused; struct LevelFileConfigInfo { int element; /* element for which data is to be stored */ int save_type; /* save data always, never or when changed */ int data_type; /* data type (used internally, not stored) */ int conf_type; /* micro chunk identifier (stored in file) */ /* (mandatory) */ void *value; /* variable that holds the data to be stored */ int default_value; /* initial default value for this variable */ /* (optional) */ void *value_copy; /* variable that holds the data to be copied */ void *num_entities; /* number of entities for multi-byte data */ int default_num_entities; /* default number of entities for this data */ int max_num_entities; /* maximal number of entities for this data */ char *default_string; /* optional default string for string data */ }; static struct LevelFileConfigInfo chunk_config_INFO[] = { /* ---------- values not related to single elements ----------------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.game_engine_type, GAME_ENGINE_TYPE_RND }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.fieldx, STD_LEV_FIELDX }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.fieldy, STD_LEV_FIELDY }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &li.time, 100 }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &li.gems_needed, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_32_BIT(2), &li.random_seed, 0 }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.use_step_counter, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &li.wind_direction_initial, MV_NONE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(5), &li.em_slippery_gems, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &li.use_custom_template, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &li.can_move_into_acid_bits, ~0 /* default: everything can */ }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(7), &li.dont_collide_with_bits, ~0 /* default: always deadly */ }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.em_explodes_by_fire, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(5), &li.score[SC_TIME_BONUS], 1 }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.auto_exit_sokoban, FALSE }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_ELEM[] = { /* (these values are the same for each player) */ { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.block_last_field, FALSE /* default case for EM levels */ }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.sp_block_last_field, TRUE /* default case for SP levels */ }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &li.instant_relocation, FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(4), &li.can_pass_to_walkable, FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(5), &li.block_snap_field, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &li.continuous_snapping, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &li.shifted_relocation, FALSE }, /* (these values are different for each player) */ { EL_PLAYER_1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[0], STEPSIZE_NORMAL }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[0], FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[0], FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[0], 1 }, { EL_PLAYER_1, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[0][0],EL_EMPTY, NULL, &li.initial_inventory_size[0], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_2, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[1], STEPSIZE_NORMAL }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[1], FALSE }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[1], FALSE }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[1], 1 }, { EL_PLAYER_2, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[1][0],EL_EMPTY, NULL, &li.initial_inventory_size[1], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_3, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[2], STEPSIZE_NORMAL }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[2], FALSE }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[2], FALSE }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[2], 1 }, { EL_PLAYER_3, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[2][0],EL_EMPTY, NULL, &li.initial_inventory_size[2], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_4, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[3], STEPSIZE_NORMAL }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[3], FALSE }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[3], FALSE }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[3], 1 }, { EL_PLAYER_4, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[3][0],EL_EMPTY, NULL, &li.initial_inventory_size[3], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_EMERALD, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_EMERALD], 10 }, { EL_DIAMOND, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_DIAMOND], 10 }, { EL_BUG, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_BUG], 10 }, { EL_SPACESHIP, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_SPACESHIP], 10 }, { EL_PACMAN, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_PACMAN], 10 }, { EL_NUT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_NUT], 10 }, { EL_DYNAMITE, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_DYNAMITE], 10 }, { EL_KEY_1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_KEY], 10 }, { EL_PEARL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_PEARL], 10 }, { EL_CRYSTAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_CRYSTAL], 10 }, { EL_BD_AMOEBA, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.amoeba_content, EL_DIAMOND }, { EL_BD_AMOEBA, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.amoeba_speed, 10 }, { EL_BD_AMOEBA, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.grow_into_diggable, TRUE }, { EL_YAMYAM, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &li.yamyam_content, EL_ROCK, NULL, &li.num_yamyam_contents, 4, MAX_ELEMENT_CONTENTS }, { EL_YAMYAM, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_YAMYAM], 10 }, { EL_ROBOT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_ROBOT], 10 }, { EL_ROBOT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.slurp_score, 10 }, { EL_ROBOT_WHEEL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_wheel, 10 }, { EL_MAGIC_WALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_magic_wall, 10 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.game_of_life[0], 2 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &li.game_of_life[1], 3 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(3), &li.game_of_life[2], 3 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(4), &li.game_of_life[3], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.biomaze[0], 2 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &li.biomaze[1], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(3), &li.biomaze[2], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(4), &li.biomaze[3], 3 }, { EL_TIMEGATE_SWITCH, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_timegate, 10 }, { EL_LIGHT_SWITCH_ACTIVE, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_light, 10 }, { EL_SHIELD_NORMAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.shield_normal_time, 10 }, { EL_SHIELD_NORMAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.score[SC_SHIELD], 10 }, { EL_SHIELD_DEADLY, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.shield_deadly_time, 10 }, { EL_SHIELD_DEADLY, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.score[SC_SHIELD], 10 }, { EL_EXTRA_TIME, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.extra_time, 10 }, { EL_EXTRA_TIME, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.extra_time_score, 10 }, { EL_TIME_ORB_FULL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_orb_time, 10 }, { EL_TIME_ORB_FULL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.use_time_orb_bug, FALSE }, { EL_SPRING, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.use_spring_bug, FALSE }, { EL_EMC_ANDROID, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.android_move_time, 10 }, { EL_EMC_ANDROID, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.android_clone_time, 10 }, { EL_EMC_ANDROID, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.android_clone_element[0], EL_EMPTY, NULL, &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS }, { EL_EMC_LENSES, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.lenses_score, 10 }, { EL_EMC_LENSES, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.lenses_time, 10 }, { EL_EMC_MAGNIFIER, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.magnify_score, 10 }, { EL_EMC_MAGNIFIER, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.magnify_time, 10 }, { EL_EMC_MAGIC_BALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.ball_time, 10 }, { EL_EMC_MAGIC_BALL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.ball_random, FALSE }, { EL_EMC_MAGIC_BALL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.ball_state_initial, FALSE }, { EL_EMC_MAGIC_BALL, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &li.ball_content, EL_EMPTY, NULL, &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS }, /* ---------- unused values ----------------------------------------------- */ { EL_UNKNOWN, SAVE_CONF_NEVER, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_UNKNOWN_14], 10 }, { EL_UNKNOWN, SAVE_CONF_NEVER, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.score[SC_UNKNOWN_15], 10 }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_NOTE[] = { { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &xx_envelope.xsize, MAX_ENVELOPE_XSIZE, }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &xx_envelope.ysize, MAX_ENVELOPE_YSIZE, }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &xx_envelope.autowrap, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(4), &xx_envelope.centered, FALSE }, { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_envelope.text, -1, NULL, &xx_string_length_unused, -1, MAX_ENVELOPE_TEXT_LEN, &xx_default_string_empty[0] }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_CUSX_base[] = { { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_ei.description[0], -1, &yy_ei.description[0], &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN, &xx_default_description[0] }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT, &yy_ei.properties[EP_BITFIELD_BASE_NR] }, #if 0 /* (reserved) */ { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(2), &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT, &yy_ei.properties[EP_BITFIELD_BASE_NR + 1] }, #endif { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &xx_ei.use_gfx_element, FALSE, &yy_ei.use_gfx_element }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_ei.gfx_element_initial, EL_EMPTY_SPACE, &yy_ei.gfx_element_initial }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(2), &xx_ei.access_direction, MV_ALL_DIRECTIONS, &yy_ei.access_direction }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &xx_ei.collect_score_initial, 10, &yy_ei.collect_score_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &xx_ei.collect_count_initial, 1, &yy_ei.collect_count_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &xx_ei.ce_value_fixed_initial, 0, &yy_ei.ce_value_fixed_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(5), &xx_ei.ce_value_random_initial, 0, &yy_ei.ce_value_random_initial }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &xx_ei.use_last_ce_value, FALSE, &yy_ei.use_last_ce_value }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(6), &xx_ei.push_delay_fixed, 8, &yy_ei.push_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(7), &xx_ei.push_delay_random, 8, &yy_ei.push_delay_random }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(8), &xx_ei.drop_delay_fixed, 0, &yy_ei.drop_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(9), &xx_ei.drop_delay_random, 0, &yy_ei.drop_delay_random }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(10), &xx_ei.move_delay_fixed, 0, &yy_ei.move_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(11), &xx_ei.move_delay_random, 0, &yy_ei.move_delay_random }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(3), &xx_ei.move_pattern, MV_ALL_DIRECTIONS, &yy_ei.move_pattern }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &xx_ei.move_direction_initial, MV_START_AUTOMATIC, &yy_ei.move_direction_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(5), &xx_ei.move_stepsize, TILEX / 8, &yy_ei.move_stepsize }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(12), &xx_ei.move_enter_element, EL_EMPTY_SPACE, &yy_ei.move_enter_element }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(13), &xx_ei.move_leave_element, EL_EMPTY_SPACE, &yy_ei.move_leave_element }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(6), &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED, &yy_ei.move_leave_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM, &yy_ei.slippery_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(8), &xx_ei.explosion_type, EXPLODES_3X3, &yy_ei.explosion_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(14), &xx_ei.explosion_delay, 16, &yy_ei.explosion_delay }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(15), &xx_ei.ignition_delay, 8, &yy_ei.ignition_delay }, { -1, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2), &xx_ei.content, EL_EMPTY_SPACE, &yy_ei.content, &xx_num_contents, 1, 1 }, /* ---------- "num_change_pages" must be the last entry ------------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(9), &xx_ei.num_change_pages, 1, &yy_ei.num_change_pages }, { -1, -1, -1, -1, NULL, -1, NULL } }; static struct LevelFileConfigInfo chunk_config_CUSX_change[] = { /* ---------- "current_change_page" must be the first entry --------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &xx_current_change_page, -1 }, /* ---------- (the remaining entries can be in any order) ----------------- */ { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &xx_change.can_change, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &xx_event_bits[0], 0 }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(2), &xx_event_bits[1], 0 }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(3), &xx_change.trigger_player, CH_PLAYER_ANY }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &xx_change.trigger_side, CH_SIDE_ANY }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(3), &xx_change.trigger_page, CH_PAGE_ANY }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_change.target_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &xx_change.delay_fixed, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &xx_change.delay_random, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &xx_change.delay_frames, FRAMES_PER_SECOND }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(5), &xx_change.initial_trigger_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &xx_change.explode, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(7), &xx_change.use_target_content, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &xx_change.only_if_complete, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &xx_change.use_random_replace, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(10), &xx_change.random_percentage, 100 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(11), &xx_change.replace_when, CP_WHEN_EMPTY }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &xx_change.has_action, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(13), &xx_change.action_type, CA_NO_ACTION }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(14), &xx_change.action_mode, CA_MODE_UNDEFINED }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(6), &xx_change.action_arg, CA_ARG_UNDEFINED }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(7), &xx_change.action_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &xx_change.target_content, EL_EMPTY_SPACE, NULL, &xx_num_contents, 1, 1 }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_GRPX[] = { { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_ei.description[0], -1, NULL, &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN, &xx_default_description[0] }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &xx_ei.use_gfx_element, FALSE }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_ei.gfx_element_initial, EL_EMPTY_SPACE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &xx_group.choice_mode, ANIM_RANDOM }, { -1, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2), &xx_group.element[0], EL_EMPTY_SPACE, NULL, &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_CONF[] = /* (OBSOLETE) */ { { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.block_snap_field, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.continuous_snapping, TRUE }, { EL_PLAYER_1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.initial_player_stepsize[0], STEPSIZE_NORMAL }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_start_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_artwork_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &li.use_explosion_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[0], EL_PLAYER_1 }, { -1, -1, -1, -1, NULL, -1 } }; static struct { int filetype; char *id; } filetype_id_list[] = { { LEVEL_FILE_TYPE_RND, "RND" }, { LEVEL_FILE_TYPE_BD, "BD" }, { LEVEL_FILE_TYPE_EM, "EM" }, { LEVEL_FILE_TYPE_SP, "SP" }, { LEVEL_FILE_TYPE_DX, "DX" }, { LEVEL_FILE_TYPE_SB, "SB" }, { LEVEL_FILE_TYPE_DC, "DC" }, { -1, NULL }, }; /* ========================================================================= */ /* level file functions */ /* ========================================================================= */ static boolean check_special_flags(char *flag) { #if 0 printf("::: '%s', '%s', '%s'\n", flag, options.special_flags, leveldir_current->special_flags); #endif if (strEqual(options.special_flags, flag) || strEqual(leveldir_current->special_flags, flag)) return TRUE; return FALSE; } static struct DateInfo getCurrentDate() { time_t epoch_seconds = time(NULL); struct tm *now = localtime(&epoch_seconds); struct DateInfo date; date.year = now->tm_year + 1900; date.month = now->tm_mon + 1; date.day = now->tm_mday; date.src = DATE_SRC_CLOCK; return date; } static void resetEventFlags(struct ElementChangeInfo *change) { int i; for (i = 0; i < NUM_CHANGE_EVENTS; i++) change->has_event[i] = FALSE; } static void resetEventBits() { int i; for (i = 0; i < NUM_CE_BITFIELDS; i++) xx_event_bits[i] = 0; } static void setEventFlagsFromEventBits(struct ElementChangeInfo *change) { int i; /* important: only change event flag if corresponding event bit is set (this is because all xx_event_bits[] values are loaded separately, and all xx_event_bits[] values are set back to zero before loading another value xx_event_bits[x] (each value representing 32 flags)) */ for (i = 0; i < NUM_CHANGE_EVENTS; i++) if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i)) change->has_event[i] = TRUE; } static void setEventBitsFromEventFlags(struct ElementChangeInfo *change) { int i; /* in contrast to the above function setEventFlagsFromEventBits(), it would also be possible to set all bits in xx_event_bits[] to 0 or 1 depending on the corresponding change->has_event[i] values here, as all xx_event_bits[] values are reset in resetEventBits() before */ for (i = 0; i < NUM_CHANGE_EVENTS; i++) if (change->has_event[i]) xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i); } static char *getDefaultElementDescription(struct ElementInfo *ei) { static char description[MAX_ELEMENT_NAME_LEN + 1]; char *default_description = (ei->custom_description != NULL ? ei->custom_description : ei->editor_description); int i; /* always start with reliable default values */ for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++) description[i] = '\0'; /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */ strncpy(description, default_description, MAX_ELEMENT_NAME_LEN); return &description[0]; } static void setElementDescriptionToDefault(struct ElementInfo *ei) { char *default_description = getDefaultElementDescription(ei); int i; for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++) ei->description[i] = default_description[i]; } static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf) { int i; for (i = 0; conf[i].data_type != -1; i++) { int default_value = conf[i].default_value; int data_type = conf[i].data_type; int conf_type = conf[i].conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; if (byte_mask == CONF_MASK_MULTI_BYTES) { int default_num_entities = conf[i].default_num_entities; int max_num_entities = conf[i].max_num_entities; *(int *)(conf[i].num_entities) = default_num_entities; if (data_type == TYPE_STRING) { char *default_string = conf[i].default_string; char *string = (char *)(conf[i].value); strncpy(string, default_string, max_num_entities); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int j; for (j = 0; j < max_num_entities; j++) element_array[j] = default_value; } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(conf[i].value); int c, x, y; for (c = 0; c < max_num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content[c].e[x][y] = default_value; } } else /* constant size configuration data (1, 2 or 4 bytes) */ { if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value) = default_value; else *(int *) (conf[i].value) = default_value; } } } static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf) { int i; for (i = 0; conf[i].data_type != -1; i++) { int data_type = conf[i].data_type; int conf_type = conf[i].conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; if (byte_mask == CONF_MASK_MULTI_BYTES) { int max_num_entities = conf[i].max_num_entities; if (data_type == TYPE_STRING) { char *string = (char *)(conf[i].value); char *string_copy = (char *)(conf[i].value_copy); strncpy(string_copy, string, max_num_entities); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int *element_array_copy = (int *)(conf[i].value_copy); int j; for (j = 0; j < max_num_entities; j++) element_array_copy[j] = element_array[j]; } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(conf[i].value); struct Content *content_copy = (struct Content *)(conf[i].value_copy); int c, x, y; for (c = 0; c < max_num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_copy[c].e[x][y] = content[c].e[x][y]; } } else /* constant size configuration data (1, 2 or 4 bytes) */ { if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value); else *(int *) (conf[i].value_copy) = *(int *) (conf[i].value); } } } void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to) { int i; xx_ei = *ei_from; /* copy element data into temporary buffer */ yy_ei = *ei_to; /* copy element data into temporary buffer */ copyConfigFromConfigList(chunk_config_CUSX_base); *ei_from = xx_ei; *ei_to = yy_ei; /* ---------- reinitialize and copy change pages ---------- */ ei_to->num_change_pages = ei_from->num_change_pages; ei_to->current_change_page = ei_from->current_change_page; setElementChangePages(ei_to, ei_to->num_change_pages); for (i = 0; i < ei_to->num_change_pages; i++) ei_to->change_page[i] = ei_from->change_page[i]; /* ---------- copy group element info ---------- */ if (ei_from->group != NULL && ei_to->group != NULL) /* group or internal */ *ei_to->group = *ei_from->group; /* mark this custom element as modified */ ei_to->modified_settings = TRUE; } void setElementChangePages(struct ElementInfo *ei, int change_pages) { int change_page_size = sizeof(struct ElementChangeInfo); ei->num_change_pages = MAX(1, change_pages); ei->change_page = checked_realloc(ei->change_page, ei->num_change_pages * change_page_size); if (ei->current_change_page >= ei->num_change_pages) ei->current_change_page = ei->num_change_pages - 1; ei->change = &ei->change_page[ei->current_change_page]; } void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) { xx_change = *change; /* copy change data into temporary buffer */ #if 0 /* (not needed; set by setConfigToDefaultsFromConfigList()) */ xx_num_contents = 1; #endif setConfigToDefaultsFromConfigList(chunk_config_CUSX_change); *change = xx_change; resetEventFlags(change); change->direct_action = 0; change->other_action = 0; change->pre_change_function = NULL; change->change_function = NULL; change->post_change_function = NULL; } static void setLevelInfoToDefaults(struct LevelInfo *level) { static boolean clipboard_elements_initialized = FALSE; int i, x, y; InitElementPropertiesStatic(); li = *level; /* copy level data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_INFO); setConfigToDefaultsFromConfigList(chunk_config_ELEM); *level = li; /* copy temporary buffer back to level data */ setLevelInfoToDefaults_EM(); setLevelInfoToDefaults_SP(); level->native_em_level = &native_em_level; level->native_sp_level = &native_sp_level; level->file_version = FILE_VERSION_ACTUAL; level->game_version = GAME_VERSION_ACTUAL; level->creation_date = getCurrentDate(); level->encoding_16bit_field = TRUE; level->encoding_16bit_yamyam = TRUE; level->encoding_16bit_amoeba = TRUE; for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) level->field[x][y] = EL_SAND; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = '\0'; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) level->author[i] = '\0'; strcpy(level->name, NAMELESS_LEVEL_NAME); strcpy(level->author, ANONYMOUS_NAME); level->field[0][0] = EL_PLAYER_1; level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED; for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int element = i; struct ElementInfo *ei = &element_info[element]; /* never initialize clipboard elements after the very first time */ /* (to be able to use clipboard elements between several levels) */ if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized) continue; if (IS_ENVELOPE(element)) { int envelope_nr = element - EL_ENVELOPE_1; setConfigToDefaultsFromConfigList(chunk_config_NOTE); level->envelope[envelope_nr] = xx_envelope; } if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { xx_ei = *ei; /* copy element data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_CUSX_base); *ei = xx_ei; } setElementChangePages(ei, 1); setElementChangeInfoToDefaults(ei->change); if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { setElementDescriptionToDefault(ei); ei->modified_settings = FALSE; } if (IS_CUSTOM_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { /* internal values used in level editor */ ei->access_type = 0; ei->access_layer = 0; ei->access_protected = 0; ei->walk_to_action = 0; ei->smash_targets = 0; ei->deadliness = 0; ei->can_explode_by_fire = FALSE; ei->can_explode_smashed = FALSE; ei->can_explode_impact = FALSE; ei->current_change_page = 0; } if (IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { struct ElementGroupInfo *group; /* initialize memory for list of elements in group */ if (ei->group == NULL) ei->group = checked_malloc(sizeof(struct ElementGroupInfo)); group = ei->group; xx_group = *group; /* copy group data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_GRPX); *group = xx_group; } } clipboard_elements_initialized = TRUE; BorderElement = EL_STEELWALL; level->no_valid_file = FALSE; level->changed = FALSE; /* set all bug compatibility flags to "false" => do not emulate this bug */ level->use_action_after_change_bug = FALSE; if (leveldir_current == NULL) /* only when dumping level */ return; /* try to determine better author name than 'anonymous' */ if (!strEqual(leveldir_current->author, ANONYMOUS_NAME)) { strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; } else { switch (LEVELCLASS(leveldir_current)) { case LEVELCLASS_TUTORIAL: strcpy(level->author, PROGRAM_AUTHOR_STRING); break; case LEVELCLASS_CONTRIB: strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; break; case LEVELCLASS_PRIVATE: strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; break; default: /* keep default value */ break; } } } static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info) { level_file_info->nr = 0; level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN; level_file_info->packed = FALSE; level_file_info->basename = NULL; level_file_info->filename = NULL; } static void ActivateLevelTemplate() { int x, y; /* Currently there is no special action needed to activate the template data, because 'element_info' property settings overwrite the original level data, while all other variables do not change. */ /* Exception: 'from_level_template' elements in the original level playfield are overwritten with the corresponding elements at the same position in playfield from the level template. */ for (x = 0; x < level.fieldx; x++) for (y = 0; y < level.fieldy; y++) if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE) level.field[x][y] = level_template.field[x][y]; if (check_special_flags("load_xsb_to_ces")) { struct LevelInfo level_backup = level; /* overwrite all individual level settings from template level settings */ level = level_template; /* restore playfield size */ level.fieldx = level_backup.fieldx; level.fieldy = level_backup.fieldy; /* restore playfield content */ for (x = 0; x < level.fieldx; x++) for (y = 0; y < level.fieldy; y++) level.field[x][y] = level_backup.field[x][y]; /* restore name and author from individual level */ strcpy(level.name, level_backup.name); strcpy(level.author, level_backup.author); /* restore flag "use_custom_template" */ level.use_custom_template = level_backup.use_custom_template; } } static char *getLevelFilenameFromBasename(char *basename) { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), basename); return filename; } static int getFileTypeFromBasename(char *basename) { /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */ static char *filename = NULL; struct stat file_status; /* ---------- try to determine file type from filename ---------- */ /* check for typical filename of a Supaplex level package file */ #if 1 if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d")) return LEVEL_FILE_TYPE_SP; #else if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 || strncmp(basename, "LEVELS.D", 8) == 0)) return LEVEL_FILE_TYPE_SP; #endif /* check for typical filename of a Diamond Caves II level package file */ if (strSuffixLower(basename, ".dc") || strSuffixLower(basename, ".dc2")) return LEVEL_FILE_TYPE_DC; /* check for typical filename of a Sokoban level package file */ if (strSuffixLower(basename, ".xsb") && strchr(basename, '%') == NULL) return LEVEL_FILE_TYPE_SB; /* ---------- try to determine file type from filesize ---------- */ checked_free(filename); filename = getPath2(getCurrentLevelDir(), basename); if (stat(filename, &file_status) == 0) { /* check for typical filesize of a Supaplex level package file */ if (file_status.st_size == 170496) return LEVEL_FILE_TYPE_SP; } return LEVEL_FILE_TYPE_UNKNOWN; } static boolean checkForPackageFromBasename(char *basename) { /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!! !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES !!! */ return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN); } static char *getSingleLevelBasenameExt(int nr, char *extension) { static char basename[MAX_FILENAME_LEN]; if (nr < 0) sprintf(basename, "template.%s", extension); else sprintf(basename, "%03d.%s", nr, extension); return basename; } static char *getSingleLevelBasename(int nr) { return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION); } static char *getPackedLevelBasename(int type) { static char basename[MAX_FILENAME_LEN]; char *directory = getCurrentLevelDir(); DIR *dir; struct dirent *dir_entry; strcpy(basename, UNDEFINED_FILENAME); /* default: undefined file */ if ((dir = opendir(directory)) == NULL) { Error(ERR_WARN, "cannot read current level directory '%s'", directory); return basename; } while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { char *entry_basename = dir_entry->d_name; int entry_type = getFileTypeFromBasename(entry_basename); if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) /* found valid level package */ { if (type == LEVEL_FILE_TYPE_UNKNOWN || type == entry_type) { strcpy(basename, entry_basename); break; } } } closedir(dir); return basename; } static char *getSingleLevelFilename(int nr) { return getLevelFilenameFromBasename(getSingleLevelBasename(nr)); } #if 0 static char *getPackedLevelFilename(int type) { return getLevelFilenameFromBasename(getPackedLevelBasename(type)); } #endif char *getDefaultLevelFilename(int nr) { return getSingleLevelFilename(nr); } #if 0 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi, int type) { lfi->type = type; lfi->packed = FALSE; lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type); lfi->filename = getLevelFilenameFromBasename(lfi->basename); } #endif static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi, int type, char *format, ...) { static char basename[MAX_FILENAME_LEN]; va_list ap; va_start(ap, format); vsprintf(basename, format, ap); va_end(ap); lfi->type = type; lfi->packed = FALSE; lfi->basename = basename; lfi->filename = getLevelFilenameFromBasename(lfi->basename); } static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi, int type) { lfi->type = type; lfi->packed = TRUE; lfi->basename = getPackedLevelBasename(lfi->type); lfi->filename = getLevelFilenameFromBasename(lfi->basename); } static int getFiletypeFromID(char *filetype_id) { char *filetype_id_lower; int filetype = LEVEL_FILE_TYPE_UNKNOWN; int i; if (filetype_id == NULL) return LEVEL_FILE_TYPE_UNKNOWN; filetype_id_lower = getStringToLower(filetype_id); for (i = 0; filetype_id_list[i].id != NULL; i++) { char *id_lower = getStringToLower(filetype_id_list[i].id); if (strEqual(filetype_id_lower, id_lower)) filetype = filetype_id_list[i].filetype; free(id_lower); if (filetype != LEVEL_FILE_TYPE_UNKNOWN) break; } free(filetype_id_lower); return filetype; } static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi) { int nr = lfi->nr; /* special case: level number is negative => check for level template file */ if (nr < 0) { #if 1 /* global variable "leveldir_current" must be modified in the loop below */ LevelDirTree *leveldir_current_last = leveldir_current; /* check for template level in path from current to topmost tree node */ while (leveldir_current != NULL) { setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "template.%s", LEVELFILE_EXTENSION); if (fileExists(lfi->filename)) break; leveldir_current = leveldir_current->node_parent; } /* restore global variable "leveldir_current" modified in above loop */ leveldir_current = leveldir_current_last; #else setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "template.%s", LEVELFILE_EXTENSION); #endif /* no fallback if template file not existing */ return; } /* special case: check for file name/pattern specified in "levelinfo.conf" */ if (leveldir_current->level_filename != NULL) { int filetype = getFiletypeFromID(leveldir_current->level_filetype); setLevelFileInfo_FormatLevelFilename(lfi, filetype, leveldir_current->level_filename, nr); lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename); if (fileExists(lfi->filename)) return; } /* check for native Rocks'n'Diamonds level file */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "%03d.%s", nr, LEVELFILE_EXTENSION); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V1) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c", 'a' + (nr / 10) % 26, '0' + nr % 10); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c", 'A' + (nr / 10) % 26, '0' + nr % 10); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V2 to V5) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V6 / single mode) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V6 / teamwork mode) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr); if (fileExists(lfi->filename)) return; /* check for various packed level file formats */ setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN); if (fileExists(lfi->filename)) return; /* no known level file found -- use default values (and fail later) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "%03d.%s", nr, LEVELFILE_EXTENSION); } static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi) { if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN) lfi->type = getFileTypeFromBasename(lfi->basename); } static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr) { /* always start with reliable default values */ setFileInfoToDefaults(level_file_info); level_file_info->nr = nr; /* set requested level number */ determineLevelFileInfo_Filename(level_file_info); determineLevelFileInfo_Filetype(level_file_info); } /* ------------------------------------------------------------------------- */ /* functions for loading R'n'D level */ /* ------------------------------------------------------------------------- */ int getMappedElement(int element) { /* remap some (historic, now obsolete) elements */ switch (element) { case EL_PLAYER_OBSOLETE: element = EL_PLAYER_1; break; case EL_KEY_OBSOLETE: element = EL_KEY_1; break; case EL_EM_KEY_1_FILE_OBSOLETE: element = EL_EM_KEY_1; break; case EL_EM_KEY_2_FILE_OBSOLETE: element = EL_EM_KEY_2; break; case EL_EM_KEY_3_FILE_OBSOLETE: element = EL_EM_KEY_3; break; case EL_EM_KEY_4_FILE_OBSOLETE: element = EL_EM_KEY_4; break; case EL_ENVELOPE_OBSOLETE: element = EL_ENVELOPE_1; break; case EL_SP_EMPTY: element = EL_EMPTY; break; default: if (element >= NUM_FILE_ELEMENTS) { Error(ERR_WARN, "invalid level element %d", element); element = EL_UNKNOWN; } break; } return element; } int getMappedElementByVersion(int element, int game_version) { /* remap some elements due to certain game version */ if (game_version <= VERSION_IDENT(2,2,0,0)) { /* map game font elements */ element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT : element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT : element == EL_CHAR(']') ? EL_CHAR_UUMLAUT : element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element); } if (game_version < VERSION_IDENT(3,0,0,0)) { /* map Supaplex gravity tube elements */ element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT : element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT : element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP : element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN : element); } return element; } static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level) { level->file_version = getFileVersion(file); level->game_version = getFileVersion(file); return chunk_size; } static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level) { level->creation_date.year = getFile16BitBE(file); level->creation_date.month = getFile8Bit(file); level->creation_date.day = getFile8Bit(file); level->creation_date.src = DATE_SRC_LEVELFILE; return chunk_size; } static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level) { int initial_player_stepsize; int initial_player_gravity; int i, x, y; level->fieldx = getFile8Bit(file); level->fieldy = getFile8Bit(file); level->time = getFile16BitBE(file); level->gems_needed = getFile16BitBE(file); for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = getFile8Bit(file); level->num_yamyam_contents = STD_ELEMENT_CONTENTS; for (i = 0; i < STD_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file)); level->amoeba_speed = getFile8Bit(file); level->time_magic_wall = getFile8Bit(file); level->time_wheel = getFile8Bit(file); level->amoeba_content = getMappedElement(getFile8Bit(file)); initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST : STEPSIZE_NORMAL); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_stepsize[i] = initial_player_stepsize; initial_player_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_gravity[i] = initial_player_gravity; level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->can_move_into_acid_bits = getFile32BitBE(file); level->dont_collide_with_bits = getFile8Bit(file); level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->grow_into_diggable = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->game_engine_type = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED); return chunk_size; } static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level) { int i; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; return chunk_size; } static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level) { int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) level->author[i] = getFile8Bit(file); level->author[MAX_LEVEL_AUTHOR_LEN] = 0; return chunk_size; } static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level) { int x, y; int chunk_size_expected = level->fieldx * level->fieldy; /* Note: "chunk_size" was wrong before version 2.0 when elements are stored with 16-bit encoding (and should be twice as big then). Even worse, playfield data was stored 16-bit when only yamyam content contained 16-bit elements and vice versa. */ if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0) chunk_size_expected *= 2; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) level->field[x][y] = getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); return chunk_size; } static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level) { int i, x, y; int header_size = 4; int content_size = MAX_ELEMENT_CONTENTS * 3 * 3; int chunk_size_expected = header_size + content_size; /* Note: "chunk_size" was wrong before version 2.0 when elements are stored with 16-bit encoding (and should be twice as big then). Even worse, playfield data was stored 16-bit when only yamyam content contained 16-bit elements and vice versa. */ if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0) chunk_size_expected += content_size; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } getFile8Bit(file); level->num_yamyam_contents = getFile8Bit(file); getFile8Bit(file); getFile8Bit(file); /* correct invalid number of content fields -- should never happen */ if (level->num_yamyam_contents < 1 || level->num_yamyam_contents > MAX_ELEMENT_CONTENTS) level->num_yamyam_contents = STD_ELEMENT_CONTENTS; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); return chunk_size; } static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level) { int i, x, y; int element; int num_contents, content_xsize, content_ysize; int content_array[MAX_ELEMENT_CONTENTS][3][3]; element = getMappedElement(getFile16BitBE(file)); num_contents = getFile8Bit(file); content_xsize = getFile8Bit(file); content_ysize = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = getMappedElement(getFile16BitBE(file)); /* correct invalid number of content fields -- should never happen */ if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS) num_contents = STD_ELEMENT_CONTENTS; if (element == EL_YAMYAM) { level->num_yamyam_contents = num_contents; for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = content_array[i][x][y]; } else if (element == EL_BD_AMOEBA) { level->amoeba_content = content_array[0][0][0]; } else { Error(ERR_WARN, "cannot load content for element '%d'", element); } return chunk_size; } static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level) { int i; int element; int envelope_nr; int envelope_len; int chunk_size_expected; element = getMappedElement(getFile16BitBE(file)); if (!IS_ENVELOPE(element)) element = EL_ENVELOPE_1; envelope_nr = element - EL_ENVELOPE_1; envelope_len = getFile16BitBE(file); level->envelope[envelope_nr].xsize = getFile8Bit(file); level->envelope[envelope_nr].ysize = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED); chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len); if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER); return chunk_size_expected; } for (i = 0; i < envelope_len; i++) level->envelope[envelope_nr].text[i] = getFile8Bit(file); return chunk_size; } static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = 2 + num_changed_custom_elements * 6; int i; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); int properties = getFile32BitBE(file); if (IS_CUSTOM_ELEMENT(element)) element_info[element].properties[EP_BITFIELD_BASE_NR] = properties; else Error(ERR_WARN, "invalid custom element number %d", element); /* older game versions that wrote level files with CUS1 chunks used different default push delay values (not yet stored in level file) */ element_info[element].push_delay_fixed = 2; element_info[element].push_delay_random = 8; } return chunk_size; } static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = 2 + num_changed_custom_elements * 4; int i; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); int custom_target_element = getMappedElement(getFile16BitBE(file)); if (IS_CUSTOM_ELEMENT(element)) element_info[element].change->target_element = custom_target_element; else Error(ERR_WARN, "invalid custom element number %d", element); } return chunk_size; } static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements); int i, j, x, y; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); struct ElementInfo *ei = &element_info[element]; unsigned int event_bits; if (!IS_CUSTOM_ELEMENT(element)) { Error(ERR_WARN, "invalid custom element number %d", element); element = EL_INTERNAL_DUMMY; } for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++) ei->description[j] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file); /* some free bytes for future properties and padding */ ReadUnusedBytesFromFile(file, 7); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); ei->collect_score_initial = getFile8Bit(file); ei->collect_count_initial = getFile8Bit(file); ei->push_delay_fixed = getFile16BitBE(file); ei->push_delay_random = getFile16BitBE(file); ei->move_delay_fixed = getFile16BitBE(file); ei->move_delay_random = getFile16BitBE(file); ei->move_pattern = getFile16BitBE(file); ei->move_direction_initial = getFile8Bit(file); ei->move_stepsize = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->content.e[x][y] = getMappedElement(getFile16BitBE(file)); event_bits = getFile32BitBE(file); for (j = 0; j < NUM_CHANGE_EVENTS; j++) if (event_bits & (1 << j)) ei->change->has_event[j] = TRUE; ei->change->target_element = getMappedElement(getFile16BitBE(file)); ei->change->delay_fixed = getFile16BitBE(file); ei->change->delay_random = getFile16BitBE(file); ei->change->delay_frames = getFile16BitBE(file); ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file)); ei->change->explode = getFile8Bit(file); ei->change->use_target_content = getFile8Bit(file); ei->change->only_if_complete = getFile8Bit(file); ei->change->use_random_replace = getFile8Bit(file); ei->change->random_percentage = getFile8Bit(file); ei->change->replace_when = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->change->target_content.e[x][y] = getMappedElement(getFile16BitBE(file)); ei->slippery_type = getFile8Bit(file); /* some free bytes for future properties and padding */ ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED); /* mark that this custom element has been modified */ ei->modified_settings = TRUE; } return chunk_size; } static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) { struct ElementInfo *ei; int chunk_size_expected; int element; int i, j, x, y; /* ---------- custom element base property values (96 bytes) ------------- */ element = getMappedElement(getFile16BitBE(file)); if (!IS_CUSTOM_ELEMENT(element)) { Error(ERR_WARN, "invalid custom element number %d", element); ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size; } ei = &element_info[element]; for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file); ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */ ei->num_change_pages = getFile8Bit(file); chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages); if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 43); return chunk_size_expected; } ei->ce_value_fixed_initial = getFile16BitBE(file); ei->ce_value_random_initial = getFile16BitBE(file); ei->use_last_ce_value = getFile8Bit(file); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); ei->collect_score_initial = getFile8Bit(file); ei->collect_count_initial = getFile8Bit(file); ei->drop_delay_fixed = getFile8Bit(file); ei->push_delay_fixed = getFile8Bit(file); ei->drop_delay_random = getFile8Bit(file); ei->push_delay_random = getFile8Bit(file); ei->move_delay_fixed = getFile16BitBE(file); ei->move_delay_random = getFile16BitBE(file); /* bits 0 - 15 of "move_pattern" ... */ ei->move_pattern = getFile16BitBE(file); ei->move_direction_initial = getFile8Bit(file); ei->move_stepsize = getFile8Bit(file); ei->slippery_type = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->content.e[x][y] = getMappedElement(getFile16BitBE(file)); ei->move_enter_element = getMappedElement(getFile16BitBE(file)); ei->move_leave_element = getMappedElement(getFile16BitBE(file)); ei->move_leave_type = getFile8Bit(file); /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */ ei->move_pattern |= (getFile16BitBE(file) << 16); ei->access_direction = getFile8Bit(file); ei->explosion_delay = getFile8Bit(file); ei->ignition_delay = getFile8Bit(file); ei->explosion_type = getFile8Bit(file); /* some free bytes for future custom property values and padding */ ReadUnusedBytesFromFile(file, 1); /* ---------- change page property values (48 bytes) --------------------- */ setElementChangePages(ei, ei->num_change_pages); for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; unsigned int event_bits; /* always start with reliable default values */ setElementChangeInfoToDefaults(change); /* bits 0 - 31 of "has_event[]" ... */ event_bits = getFile32BitBE(file); for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (event_bits & (1 << j)) change->has_event[j] = TRUE; change->target_element = getMappedElement(getFile16BitBE(file)); change->delay_fixed = getFile16BitBE(file); change->delay_random = getFile16BitBE(file); change->delay_frames = getFile16BitBE(file); change->initial_trigger_element = getMappedElement(getFile16BitBE(file)); change->explode = getFile8Bit(file); change->use_target_content = getFile8Bit(file); change->only_if_complete = getFile8Bit(file); change->use_random_replace = getFile8Bit(file); change->random_percentage = getFile8Bit(file); change->replace_when = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file)); change->can_change = getFile8Bit(file); change->trigger_side = getFile8Bit(file); change->trigger_player = getFile8Bit(file); change->trigger_page = getFile8Bit(file); change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ? CH_PAGE_ANY : (1 << change->trigger_page)); change->has_action = getFile8Bit(file); change->action_type = getFile8Bit(file); change->action_mode = getFile8Bit(file); change->action_arg = getFile16BitBE(file); /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ event_bits = getFile8Bit(file); for (j = 32; j < NUM_CHANGE_EVENTS; j++) if (event_bits & (1 << (j - 32))) change->has_event[j] = TRUE; } /* mark this custom element as modified */ ei->modified_settings = TRUE; return chunk_size; } static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level) { struct ElementInfo *ei; struct ElementGroupInfo *group; int element; int i; element = getMappedElement(getFile16BitBE(file)); if (!IS_GROUP_ELEMENT(element)) { Error(ERR_WARN, "invalid group element number %d", element); ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size; } ei = &element_info[element]; for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; group = element_info[element].group; group->num_elements = getFile8Bit(file); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); group->choice_mode = getFile8Bit(file); /* some free bytes for future values and padding */ ReadUnusedBytesFromFile(file, 3); for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++) group->element[i] = getMappedElement(getFile16BitBE(file)); /* mark this group element as modified */ element_info[element].modified_settings = TRUE; return chunk_size; } static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf, int element, int real_element) { int micro_chunk_size = 0; int conf_type = getFile8Bit(file); int byte_mask = conf_type & CONF_MASK_BYTES; boolean element_found = FALSE; int i; micro_chunk_size += 1; if (byte_mask == CONF_MASK_MULTI_BYTES) { int num_bytes = getFile16BitBE(file); byte *buffer = checked_malloc(num_bytes); ReadBytesFromFile(file, buffer, num_bytes); for (i = 0; conf[i].data_type != -1; i++) { if (conf[i].element == element && conf[i].conf_type == conf_type) { int data_type = conf[i].data_type; int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type); int max_num_entities = conf[i].max_num_entities; if (num_entities > max_num_entities) { Error(ERR_WARN, "truncating number of entities for element %d from %d to %d", element, num_entities, max_num_entities); num_entities = max_num_entities; } if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST || data_type == TYPE_CONTENT_LIST)) { /* for element and content lists, zero entities are not allowed */ Error(ERR_WARN, "found empty list of entities for element %d", element); /* do not set "num_entities" here to prevent reading behind buffer */ *(int *)(conf[i].num_entities) = 1; /* at least one is required */ } else { *(int *)(conf[i].num_entities) = num_entities; } element_found = TRUE; if (data_type == TYPE_STRING) { char *string = (char *)(conf[i].value); int j; for (j = 0; j < max_num_entities; j++) string[j] = (j < num_entities ? buffer[j] : '\0'); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int j; for (j = 0; j < num_entities; j++) element_array[j] = getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j)); } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content= (struct Content *)(conf[i].value); int c, x, y; for (c = 0; c < num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content[c].e[x][y] = getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y)); } else element_found = FALSE; break; } } checked_free(buffer); micro_chunk_size += 2 + num_bytes; } else /* constant size configuration data (1, 2 or 4 bytes) */ { int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) : byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) : byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0); for (i = 0; conf[i].data_type != -1; i++) { if (conf[i].element == element && conf[i].conf_type == conf_type) { int data_type = conf[i].data_type; if (data_type == TYPE_ELEMENT) value = getMappedElement(value); if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value) = value; else *(int *) (conf[i].value) = value; element_found = TRUE; break; } } micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask); } if (!element_found) { char *error_conf_chunk_bytes = (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" : byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" : byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES"); int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN; int error_element = real_element; Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']", error_conf_chunk_bytes, error_conf_chunk_token, error_element, EL_NAME(error_element)); } return micro_chunk_size; } static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!feof(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!feof(file)) { int element = getMappedElement(getFile16BitBE(file)); real_chunk_size += 2; real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF, element, element); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!feof(file)) { int element = getMappedElement(getFile16BitBE(file)); real_chunk_size += 2; real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM, element, element); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int envelope_nr = element - EL_ENVELOPE_1; int real_chunk_size = 2; while (!feof(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE, -1, element); if (real_chunk_size >= chunk_size) break; } level->envelope[envelope_nr] = xx_envelope; return real_chunk_size; } static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int real_chunk_size = 2; struct ElementInfo *ei = &element_info[element]; int i; xx_ei = *ei; /* copy element data into temporary buffer */ xx_ei.num_change_pages = -1; while (!feof(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base, -1, element); if (xx_ei.num_change_pages != -1) break; if (real_chunk_size >= chunk_size) break; } *ei = xx_ei; if (ei->num_change_pages == -1) { Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'", EL_NAME(element)); ei->num_change_pages = 1; setElementChangePages(ei, 1); setElementChangeInfoToDefaults(ei->change); return real_chunk_size; } /* initialize number of change pages stored for this custom element */ setElementChangePages(ei, ei->num_change_pages); for (i = 0; i < ei->num_change_pages; i++) setElementChangeInfoToDefaults(&ei->change_page[i]); /* start with reading properties for the first change page */ xx_current_change_page = 0; while (!feof(file)) { struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page]; xx_change = *change; /* copy change data into temporary buffer */ resetEventBits(); /* reset bits; change page might have changed */ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change, -1, element); *change = xx_change; setEventFlagsFromEventBits(change); if (real_chunk_size >= chunk_size) break; } return real_chunk_size; } static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int real_chunk_size = 2; struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; xx_ei = *ei; /* copy element data into temporary buffer */ xx_group = *group; /* copy group data into temporary buffer */ while (!feof(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX, -1, element); if (real_chunk_size >= chunk_size) break; } *ei = xx_ei; *group = xx_group; return real_chunk_size; } static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; char cookie[MAX_LINE_LEN]; char chunk_name[CHUNK_ID_LEN + 1]; int chunk_size; FILE *file; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; #if 1 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); #else if (level != &level_template) Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); #endif return; } getFileChunkBE(file, chunk_name, NULL); if (strEqual(chunk_name, "RND1")) { getFile32BitBE(file); /* not used */ getFileChunkBE(file, chunk_name, NULL); if (!strEqual(chunk_name, "CAVE")) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown format of level file '%s'", filename); fclose(file); return; } } else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); fgets(&cookie[4], MAX_LINE_LEN - 4, file); if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL)) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown format of level file '%s'", filename); fclose(file); return; } if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1) { level->no_valid_file = TRUE; Error(ERR_WARN, "unsupported version of level file '%s'", filename); fclose(file); return; } /* pre-2.0 level files have no game version, so use file version here */ level->game_version = level->file_version; } if (level->file_version < FILE_VERSION_1_2) { /* level files from versions before 1.2.0 without chunk structure */ LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE, level); LoadLevel_BODY(file, level->fieldx * level->fieldy, level); } else { static struct { char *name; int size; int (*loader)(FILE *, int, struct LevelInfo *); } chunk_info[] = { { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS }, { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE }, { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD }, { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME }, { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH }, { "INFO", -1, LoadLevel_INFO }, { "BODY", -1, LoadLevel_BODY }, { "CONT", -1, LoadLevel_CONT }, { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 }, { "CNT3", -1, LoadLevel_CNT3 }, { "CUS1", -1, LoadLevel_CUS1 }, { "CUS2", -1, LoadLevel_CUS2 }, { "CUS3", -1, LoadLevel_CUS3 }, { "CUS4", -1, LoadLevel_CUS4 }, { "GRP1", -1, LoadLevel_GRP1 }, { "CONF", -1, LoadLevel_CONF }, { "ELEM", -1, LoadLevel_ELEM }, { "NOTE", -1, LoadLevel_NOTE }, { "CUSX", -1, LoadLevel_CUSX }, { "GRPX", -1, LoadLevel_GRPX }, { NULL, 0, NULL } }; while (getFileChunkBE(file, chunk_name, &chunk_size)) { int i = 0; while (chunk_info[i].name != NULL && !strEqual(chunk_name, chunk_info[i].name)) i++; if (chunk_info[i].name == NULL) { Error(ERR_WARN, "unknown chunk '%s' in level file '%s'", chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else if (chunk_info[i].size != -1 && chunk_info[i].size != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else { /* call function to load this level chunk */ int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, level); /* the size of some chunks cannot be checked before reading other chunks first (like "HEAD" and "BODY") that contain some header information, so check them here */ if (chunk_size_expected != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); } } } } fclose(file); } /* ------------------------------------------------------------------------- */ /* functions for loading EM level */ /* ------------------------------------------------------------------------- */ #if 0 static int map_em_element_yam(int element) { switch (element) { case 0x00: return EL_EMPTY; case 0x01: return EL_EMERALD; case 0x02: return EL_DIAMOND; case 0x03: return EL_ROCK; case 0x04: return EL_ROBOT; case 0x05: return EL_SPACESHIP_UP; case 0x06: return EL_BOMB; case 0x07: return EL_BUG_UP; case 0x08: return EL_AMOEBA_DROP; case 0x09: return EL_NUT; case 0x0a: return EL_YAMYAM; case 0x0b: return EL_QUICKSAND_FULL; case 0x0c: return EL_SAND; case 0x0d: return EL_WALL_SLIPPERY; case 0x0e: return EL_STEELWALL; case 0x0f: return EL_WALL; case 0x10: return EL_EM_KEY_1; case 0x11: return EL_EM_KEY_2; case 0x12: return EL_EM_KEY_4; case 0x13: return EL_EM_KEY_3; case 0x14: return EL_MAGIC_WALL; case 0x15: return EL_ROBOT_WHEEL; case 0x16: return EL_DYNAMITE; case 0x17: return EL_EM_KEY_1; /* EMC */ case 0x18: return EL_BUG_UP; /* EMC */ case 0x1a: return EL_DIAMOND; /* EMC */ case 0x1b: return EL_EMERALD; /* EMC */ case 0x25: return EL_NUT; /* EMC */ case 0x80: return EL_EMPTY; /* EMC */ case 0x85: return EL_EM_KEY_1; /* EMC */ case 0x86: return EL_EM_KEY_2; /* EMC */ case 0x87: return EL_EM_KEY_4; /* EMC */ case 0x88: return EL_EM_KEY_3; /* EMC */ case 0x94: return EL_QUICKSAND_EMPTY; /* EMC */ case 0x9a: return EL_AMOEBA_WET; /* EMC */ case 0xaf: return EL_DYNAMITE; /* EMC */ case 0xbd: return EL_SAND; /* EMC */ default: Error(ERR_WARN, "invalid level element %d", element); return EL_UNKNOWN; } } static int map_em_element_field(int element) { if (element >= 0xc8 && element <= 0xe1) return EL_CHAR_A + (element - 0xc8); else if (element >= 0xe2 && element <= 0xeb) return EL_CHAR_0 + (element - 0xe2); switch (element) { case 0x00: return EL_ROCK; case 0x01: return EL_ROCK; /* EMC */ case 0x02: return EL_DIAMOND; case 0x03: return EL_DIAMOND; case 0x04: return EL_ROBOT; case 0x05: return EL_ROBOT; /* EMC */ case 0x06: return EL_EMPTY_SPACE; /* EMC */ case 0x07: return EL_EMPTY_SPACE; /* EMC */ case 0x08: return EL_SPACESHIP_UP; case 0x09: return EL_SPACESHIP_RIGHT; case 0x0a: return EL_SPACESHIP_DOWN; case 0x0b: return EL_SPACESHIP_LEFT; case 0x0c: return EL_SPACESHIP_UP; case 0x0d: return EL_SPACESHIP_RIGHT; case 0x0e: return EL_SPACESHIP_DOWN; case 0x0f: return EL_SPACESHIP_LEFT; case 0x10: return EL_BOMB; case 0x11: return EL_BOMB; /* EMC */ case 0x12: return EL_EMERALD; case 0x13: return EL_EMERALD; case 0x14: return EL_BUG_UP; case 0x15: return EL_BUG_RIGHT; case 0x16: return EL_BUG_DOWN; case 0x17: return EL_BUG_LEFT; case 0x18: return EL_BUG_UP; case 0x19: return EL_BUG_RIGHT; case 0x1a: return EL_BUG_DOWN; case 0x1b: return EL_BUG_LEFT; case 0x1c: return EL_AMOEBA_DROP; case 0x1d: return EL_AMOEBA_DROP; /* EMC */ case 0x1e: return EL_AMOEBA_DROP; /* EMC */ case 0x1f: return EL_AMOEBA_DROP; /* EMC */ case 0x20: return EL_ROCK; case 0x21: return EL_BOMB; /* EMC */ case 0x22: return EL_DIAMOND; /* EMC */ case 0x23: return EL_EMERALD; /* EMC */ case 0x24: return EL_MAGIC_WALL; case 0x25: return EL_NUT; case 0x26: return EL_NUT; /* EMC */ case 0x27: return EL_NUT; /* EMC */ /* looks like magic wheel, but is _always_ activated */ case 0x28: return EL_ROBOT_WHEEL; /* EMC */ case 0x29: return EL_YAMYAM; /* up */ case 0x2a: return EL_YAMYAM; /* down */ case 0x2b: return EL_YAMYAM; /* left */ /* EMC */ case 0x2c: return EL_YAMYAM; /* right */ /* EMC */ case 0x2d: return EL_QUICKSAND_FULL; case 0x2e: return EL_EMPTY_SPACE; /* EMC */ case 0x2f: return EL_EMPTY_SPACE; /* EMC */ case 0x30: return EL_EMPTY_SPACE; /* EMC */ case 0x31: return EL_SAND; /* EMC */ case 0x32: return EL_SAND; /* EMC */ case 0x33: return EL_SAND; /* EMC */ case 0x34: return EL_QUICKSAND_FULL; /* EMC */ case 0x35: return EL_QUICKSAND_FULL; /* EMC */ case 0x36: return EL_QUICKSAND_FULL; /* EMC */ case 0x37: return EL_SAND; /* EMC */ case 0x38: return EL_ROCK; /* EMC */ case 0x39: return EL_EXPANDABLE_WALL_HORIZONTAL; /* EMC */ case 0x3a: return EL_EXPANDABLE_WALL_VERTICAL; /* EMC */ case 0x3b: return EL_DYNAMITE_ACTIVE; /* 1 */ case 0x3c: return EL_DYNAMITE_ACTIVE; /* 2 */ case 0x3d: return EL_DYNAMITE_ACTIVE; /* 3 */ case 0x3e: return EL_DYNAMITE_ACTIVE; /* 4 */ case 0x3f: return EL_ACID_POOL_BOTTOM; case 0x40: return EL_EXIT_OPEN; /* 1 */ case 0x41: return EL_EXIT_OPEN; /* 2 */ case 0x42: return EL_EXIT_OPEN; /* 3 */ case 0x43: return EL_BALLOON; /* EMC */ case 0x44: return EL_UNKNOWN; /* EMC ("plant") */ case 0x45: return EL_SPRING; /* EMC */ case 0x46: return EL_SPRING; /* falling */ /* EMC */ case 0x47: return EL_SPRING; /* left */ /* EMC */ case 0x48: return EL_SPRING; /* right */ /* EMC */ case 0x49: return EL_UNKNOWN; /* EMC ("ball 1") */ case 0x4a: return EL_UNKNOWN; /* EMC ("ball 2") */ case 0x4b: return EL_UNKNOWN; /* EMC ("android") */ case 0x4c: return EL_EMPTY_SPACE; /* EMC */ case 0x4d: return EL_UNKNOWN; /* EMC ("android") */ case 0x4e: return EL_INVISIBLE_WALL; /* EMC (? "android") */ case 0x4f: return EL_UNKNOWN; /* EMC ("android") */ case 0x50: return EL_UNKNOWN; /* EMC ("android") */ case 0x51: return EL_UNKNOWN; /* EMC ("android") */ case 0x52: return EL_UNKNOWN; /* EMC ("android") */ case 0x53: return EL_UNKNOWN; /* EMC ("android") */ case 0x54: return EL_UNKNOWN; /* EMC ("android") */ case 0x55: return EL_EMPTY_SPACE; /* EMC */ case 0x56: return EL_EMPTY_SPACE; /* EMC */ case 0x57: return EL_EMPTY_SPACE; /* EMC */ case 0x58: return EL_EMPTY_SPACE; /* EMC */ case 0x59: return EL_EMPTY_SPACE; /* EMC */ case 0x5a: return EL_EMPTY_SPACE; /* EMC */ case 0x5b: return EL_EMPTY_SPACE; /* EMC */ case 0x5c: return EL_EMPTY_SPACE; /* EMC */ case 0x5d: return EL_EMPTY_SPACE; /* EMC */ case 0x5e: return EL_EMPTY_SPACE; /* EMC */ case 0x5f: return EL_EMPTY_SPACE; /* EMC */ case 0x60: return EL_EMPTY_SPACE; /* EMC */ case 0x61: return EL_EMPTY_SPACE; /* EMC */ case 0x62: return EL_EMPTY_SPACE; /* EMC */ case 0x63: return EL_SPRING; /* left */ /* EMC */ case 0x64: return EL_SPRING; /* right */ /* EMC */ case 0x65: return EL_ACID; /* 1 */ /* EMC */ case 0x66: return EL_ACID; /* 2 */ /* EMC */ case 0x67: return EL_ACID; /* 3 */ /* EMC */ case 0x68: return EL_ACID; /* 4 */ /* EMC */ case 0x69: return EL_ACID; /* 5 */ /* EMC */ case 0x6a: return EL_ACID; /* 6 */ /* EMC */ case 0x6b: return EL_ACID; /* 7 */ /* EMC */ case 0x6c: return EL_ACID; /* 8 */ /* EMC */ case 0x6d: return EL_EMPTY_SPACE; /* EMC */ case 0x6e: return EL_EMPTY_SPACE; /* EMC */ case 0x6f: return EL_EMPTY_SPACE; /* EMC */ case 0x70: return EL_EMPTY_SPACE; /* EMC */ case 0x71: return EL_EMPTY_SPACE; /* EMC */ case 0x72: return EL_NUT; /* left */ /* EMC */ case 0x73: return EL_SAND; /* EMC (? "nut") */ case 0x74: return EL_STEELWALL; case 0x75: return EL_EMPTY_SPACE; /* EMC */ case 0x76: return EL_EMPTY_SPACE; /* EMC */ case 0x77: return EL_BOMB; /* left */ /* EMC */ case 0x78: return EL_BOMB; /* right */ /* EMC */ case 0x79: return EL_ROCK; /* left */ /* EMC */ case 0x7a: return EL_ROCK; /* right */ /* EMC */ case 0x7b: return EL_ACID; /* (? EMC "blank") */ case 0x7c: return EL_EMPTY_SPACE; /* EMC */ case 0x7d: return EL_EMPTY_SPACE; /* EMC */ case 0x7e: return EL_EMPTY_SPACE; /* EMC */ case 0x7f: return EL_EMPTY_SPACE; /* EMC */ case 0x80: return EL_EMPTY; case 0x81: return EL_WALL_SLIPPERY; case 0x82: return EL_SAND; case 0x83: return EL_STEELWALL; case 0x84: return EL_WALL; case 0x85: return EL_EM_KEY_1; case 0x86: return EL_EM_KEY_2; case 0x87: return EL_EM_KEY_4; case 0x88: return EL_EM_KEY_3; case 0x89: return EL_EM_GATE_1; case 0x8a: return EL_EM_GATE_2; case 0x8b: return EL_EM_GATE_4; case 0x8c: return EL_EM_GATE_3; case 0x8d: return EL_INVISIBLE_WALL; /* EMC (? "dripper") */ case 0x8e: return EL_EM_GATE_1_GRAY; case 0x8f: return EL_EM_GATE_2_GRAY; case 0x90: return EL_EM_GATE_4_GRAY; case 0x91: return EL_EM_GATE_3_GRAY; case 0x92: return EL_MAGIC_WALL; case 0x93: return EL_ROBOT_WHEEL; case 0x94: return EL_QUICKSAND_EMPTY; /* (? EMC "sand") */ case 0x95: return EL_ACID_POOL_TOPLEFT; case 0x96: return EL_ACID_POOL_TOPRIGHT; case 0x97: return EL_ACID_POOL_BOTTOMLEFT; case 0x98: return EL_ACID_POOL_BOTTOMRIGHT; case 0x99: return EL_ACID; /* (? EMC "fake blank") */ case 0x9a: return EL_AMOEBA_DEAD; /* 1 */ case 0x9b: return EL_AMOEBA_DEAD; /* 2 */ case 0x9c: return EL_AMOEBA_DEAD; /* 3 */ case 0x9d: return EL_AMOEBA_DEAD; /* 4 */ case 0x9e: return EL_EXIT_CLOSED; case 0x9f: return EL_CHAR_LESS; /* arrow left */ /* looks like normal sand, but behaves like wall */ case 0xa0: return EL_UNKNOWN; /* EMC ("fake grass") */ case 0xa1: return EL_UNKNOWN; /* EMC ("lenses") */ case 0xa2: return EL_UNKNOWN; /* EMC ("magnify") */ case 0xa3: return EL_UNKNOWN; /* EMC ("fake blank") */ case 0xa4: return EL_UNKNOWN; /* EMC ("fake grass") */ case 0xa5: return EL_UNKNOWN; /* EMC ("switch") */ case 0xa6: return EL_UNKNOWN; /* EMC ("switch") */ case 0xa7: return EL_EMPTY_SPACE; /* EMC */ case 0xa8: return EL_EMC_WALL_1; /* EMC ("decor 8") */ case 0xa9: return EL_EMC_WALL_2; /* EMC ("decor 9") */ case 0xaa: return EL_EMC_WALL_3; /* EMC ("decor 10") */ case 0xab: return EL_EMC_WALL_7; /* EMC ("decor 5") */ case 0xac: return EL_CHAR_COMMA; /* EMC */ case 0xad: return EL_CHAR_QUOTEDBL; /* EMC */ case 0xae: return EL_CHAR_MINUS; /* EMC */ case 0xaf: return EL_DYNAMITE; case 0xb0: return EL_EMC_STEELWALL_1; /* EMC ("steel 3") */ case 0xb1: return EL_EMC_WALL_8; /* EMC ("decor 6") */ case 0xb2: return EL_UNKNOWN; /* EMC ("decor 7") */ case 0xb3: return EL_STEELWALL; /* 2 */ /* EMC */ case 0xb4: return EL_WALL_SLIPPERY; /* 2 */ /* EMC */ case 0xb5: return EL_EMC_WALL_6; /* EMC ("decor 2") */ case 0xb6: return EL_EMC_WALL_5; /* EMC ("decor 4") */ case 0xb7: return EL_EMC_WALL_4; /* EMC ("decor 3") */ case 0xb8: return EL_BALLOON_SWITCH_ANY; /* EMC */ case 0xb9: return EL_BALLOON_SWITCH_RIGHT; /* EMC */ case 0xba: return EL_BALLOON_SWITCH_DOWN; /* EMC */ case 0xbb: return EL_BALLOON_SWITCH_LEFT; /* EMC */ case 0xbc: return EL_BALLOON_SWITCH_UP; /* EMC */ case 0xbd: return EL_SAND; /* EMC ("dirt") */ case 0xbe: return EL_UNKNOWN; /* EMC ("plant") */ case 0xbf: return EL_UNKNOWN; /* EMC ("key 5") */ case 0xc0: return EL_UNKNOWN; /* EMC ("key 6") */ case 0xc1: return EL_UNKNOWN; /* EMC ("key 7") */ case 0xc2: return EL_UNKNOWN; /* EMC ("key 8") */ case 0xc3: return EL_UNKNOWN; /* EMC ("door 5") */ case 0xc4: return EL_UNKNOWN; /* EMC ("door 6") */ case 0xc5: return EL_UNKNOWN; /* EMC ("door 7") */ case 0xc6: return EL_UNKNOWN; /* EMC ("door 8") */ case 0xc7: return EL_UNKNOWN; /* EMC ("bumper") */ /* characters: see above */ case 0xec: return EL_CHAR_PERIOD; case 0xed: return EL_CHAR_EXCLAM; case 0xee: return EL_CHAR_COLON; case 0xef: return EL_CHAR_QUESTION; case 0xf0: return EL_CHAR_GREATER; /* arrow right */ case 0xf1: return EL_CHAR_COPYRIGHT; /* EMC: "decor 1" */ case 0xf2: return EL_UNKNOWN; /* EMC ("fake door 5") */ case 0xf3: return EL_UNKNOWN; /* EMC ("fake door 6") */ case 0xf4: return EL_UNKNOWN; /* EMC ("fake door 7") */ case 0xf5: return EL_UNKNOWN; /* EMC ("fake door 8") */ case 0xf6: return EL_EMPTY_SPACE; /* EMC */ case 0xf7: return EL_EMPTY_SPACE; /* EMC */ case 0xf8: return EL_EMPTY_SPACE; /* EMC */ case 0xf9: return EL_EMPTY_SPACE; /* EMC */ case 0xfa: return EL_EMPTY_SPACE; /* EMC */ case 0xfb: return EL_EMPTY_SPACE; /* EMC */ case 0xfc: return EL_EMPTY_SPACE; /* EMC */ case 0xfd: return EL_EMPTY_SPACE; /* EMC */ case 0xfe: return EL_PLAYER_1; /* EMC: "blank" */ case 0xff: return EL_PLAYER_2; /* EMC: "blank" */ default: /* should never happen (all 8-bit value cases should be handled) */ Error(ERR_WARN, "invalid level element %d", element); return EL_UNKNOWN; } } #define EM_LEVEL_SIZE 2106 #define EM_LEVEL_XSIZE 64 #define EM_LEVEL_YSIZE 32 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; FILE *file; unsigned char leveldata[EM_LEVEL_SIZE]; unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE]; int nr = level_file_info->nr; int i, x, y; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } for (i = 0; i < EM_LEVEL_SIZE; i++) leveldata[i] = fgetc(file); fclose(file); /* check if level data is crypted by testing against known starting bytes of the few existing crypted level files (from Emerald Mine 1 + 2) */ if ((leveldata[0] == 0xf1 || leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee) { unsigned char code0 = 0x65; unsigned char code1 = 0x11; if (leveldata[0] == 0xf5) /* error in crypted Emerald Mine 2 levels */ leveldata[0] = 0xf1; /* decode crypted level data */ for (i = 0; i < EM_LEVEL_SIZE; i++) { leveldata[i] ^= code0; leveldata[i] -= code1; code0 = (code0 + 7) & 0xff; } } level->fieldx = EM_LEVEL_XSIZE; level->fieldy = EM_LEVEL_YSIZE; level->time = header[46] * 10; level->gems_needed = header[47]; /* The original Emerald Mine levels have their level number stored at the second byte of the level file... Do not trust this information at other level files, e.g. EMC, but correct it anyway (normally the first row is completely steel wall, so the correction does not hurt anyway). */ if (leveldata[1] == nr) leveldata[1] = leveldata[2]; /* correct level number field */ sprintf(level->name, "Level %d", nr); /* set level name */ level->score[SC_EMERALD] = header[36]; level->score[SC_DIAMOND] = header[37]; level->score[SC_ROBOT] = header[38]; level->score[SC_SPACESHIP] = header[39]; level->score[SC_BUG] = header[40]; level->score[SC_YAMYAM] = header[41]; level->score[SC_NUT] = header[42]; level->score[SC_DYNAMITE] = header[43]; level->score[SC_TIME_BONUS] = header[44]; level->num_yamyam_contents = 4; for (i = 0; i < level->num_yamyam_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = map_em_element_yam(header[i * 9 + y * 3 + x]); level->amoeba_speed = (header[52] * 256 + header[53]) % 256; level->time_magic_wall = (header[54] * 256 + header[55]) * 16 / 100; level->time_wheel = (header[56] * 256 + header[57]) * 16 / 100; level->amoeba_content = EL_DIAMOND; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]); if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed) new_element = EL_AMOEBA_WET; level->field[x][y] = new_element; } x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE; y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE; level->field[x][y] = EL_PLAYER_1; x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE; y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE; level->field[x][y] = EL_PLAYER_2; } #endif void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) { static int ball_xy[8][2] = { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; struct PLAYER **ply = level_em->ply; int i, j, x, y; lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH); lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT); lev->time_seconds = level->time; lev->required_initial = level->gems_needed; lev->emerald_score = level->score[SC_EMERALD]; lev->diamond_score = level->score[SC_DIAMOND]; lev->alien_score = level->score[SC_ROBOT]; lev->tank_score = level->score[SC_SPACESHIP]; lev->bug_score = level->score[SC_BUG]; lev->eater_score = level->score[SC_YAMYAM]; lev->nut_score = level->score[SC_NUT]; lev->dynamite_score = level->score[SC_DYNAMITE]; lev->key_score = level->score[SC_KEY]; lev->exit_score = level->score[SC_TIME_BONUS]; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) lev->eater_array[i][y * 3 + x] = map_element_RND_to_EM(level->yamyam_content[i].e[x][y]); lev->amoeba_time = level->amoeba_speed; lev->wonderwall_time_initial = level->time_magic_wall; lev->wheel_time = level->time_wheel; lev->android_move_time = level->android_move_time; lev->android_clone_time = level->android_clone_time; lev->ball_random = level->ball_random; lev->ball_state_initial = level->ball_state_initial; lev->ball_time = level->ball_time; lev->num_ball_arrays = level->num_ball_contents; lev->lenses_score = level->lenses_score; lev->magnify_score = level->magnify_score; lev->slurp_score = level->slurp_score; lev->lenses_time = level->lenses_time; lev->magnify_time = level->magnify_time; lev->wind_direction_initial = map_direction_RND_to_EM(level->wind_direction_initial); lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ? lev->wind_time : 0); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) lev->ball_array[i][j] = map_element_RND_to_EM(level-> ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); map_android_clone_elements_RND_to_EM(level); /* first fill the complete playfield with the default border element */ for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++) for (x = 0; x < EM_MAX_CAVE_WIDTH; x++) level_em->cave[x][y] = ZBORDER; if (BorderElement == EL_STEELWALL) { for (y = 0; y < lev->height + 2; y++) for (x = 0; x < lev->width + 2; x++) level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL); } /* then copy the real level contents from level file into the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { int new_element = map_element_RND_to_EM(level->field[x][y]); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int xx = x + 1 + offset; int yy = y + 1 + offset; if (level->field[x][y] == EL_AMOEBA_DEAD) new_element = map_element_RND_to_EM(EL_AMOEBA_WET); level_em->cave[xx][yy] = new_element; } for (i = 0; i < MAX_PLAYERS; i++) { ply[i]->x_initial = 0; ply[i]->y_initial = 0; } /* initialize player positions and delete players from the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { if (ELEM_IS_PLAYER(level->field[x][y])) { int player_nr = GET_PLAYER_NR(level->field[x][y]); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int xx = x + 1 + offset; int yy = y + 1 + offset; ply[player_nr]->x_initial = xx; ply[player_nr]->y_initial = yy; level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY); } } if (BorderElement == EL_STEELWALL) { lev->width += 2; lev->height += 2; } } void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) { static int ball_xy[8][2] = { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; struct PLAYER **ply = level_em->ply; int i, j, x, y; level->fieldx = MIN(lev->width, MAX_LEV_FIELDX); level->fieldy = MIN(lev->height, MAX_LEV_FIELDY); level->time = lev->time_seconds; level->gems_needed = lev->required_initial; sprintf(level->name, "Level %d", level->file_info.nr); level->score[SC_EMERALD] = lev->emerald_score; level->score[SC_DIAMOND] = lev->diamond_score; level->score[SC_ROBOT] = lev->alien_score; level->score[SC_SPACESHIP] = lev->tank_score; level->score[SC_BUG] = lev->bug_score; level->score[SC_YAMYAM] = lev->eater_score; level->score[SC_NUT] = lev->nut_score; level->score[SC_DYNAMITE] = lev->dynamite_score; level->score[SC_KEY] = lev->key_score; level->score[SC_TIME_BONUS] = lev->exit_score; level->num_yamyam_contents = MAX_ELEMENT_CONTENTS; for (i = 0; i < level->num_yamyam_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]); level->amoeba_speed = lev->amoeba_time; level->time_magic_wall = lev->wonderwall_time_initial; level->time_wheel = lev->wheel_time; level->android_move_time = lev->android_move_time; level->android_clone_time = lev->android_clone_time; level->ball_random = lev->ball_random; level->ball_state_initial = lev->ball_state_initial; level->ball_time = lev->ball_time; level->num_ball_contents = lev->num_ball_arrays; level->lenses_score = lev->lenses_score; level->magnify_score = lev->magnify_score; level->slurp_score = lev->slurp_score; level->lenses_time = lev->lenses_time; level->magnify_time = lev->magnify_time; level->wind_direction_initial = map_direction_EM_to_RND(lev->wind_direction_initial); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] = map_element_EM_to_RND(lev->ball_array[i][j]); map_android_clone_elements_EM_to_RND(level); /* convert the playfield (some elements need special treatment) */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]); if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0) new_element = EL_AMOEBA_DEAD; level->field[x][y] = new_element; } for (i = 0; i < MAX_PLAYERS; i++) { /* in case of all players set to the same field, use the first player */ int nr = MAX_PLAYERS - i - 1; int jx = ply[nr]->x_initial - 1; int jy = ply[nr]->y_initial - 1; if (jx != -1 && jy != -1) level->field[jx][jy] = EL_PLAYER_1 + nr; } } /* ------------------------------------------------------------------------- */ /* functions for loading SP level */ /* ------------------------------------------------------------------------- */ #if 0 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111 #define SP_LEVEL_SIZE 1536 #define SP_LEVEL_XSIZE 60 #define SP_LEVEL_YSIZE 24 #define SP_LEVEL_NAME_LEN 23 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level, int nr) { int initial_player_gravity; int num_special_ports; int i, x, y; /* for details of the Supaplex level format, see Herman Perk's Supaplex documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */ /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */ for (y = 0; y < SP_LEVEL_YSIZE; y++) { for (x = 0; x < SP_LEVEL_XSIZE; x++) { int element_old = fgetc(file); int element_new; if (element_old <= 0x27) element_new = getMappedElement(EL_SP_START + element_old); else if (element_old == 0x28) element_new = EL_INVISIBLE_WALL; else { Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y); Error(ERR_WARN, "invalid level element %d", element_old); element_new = EL_UNKNOWN; } level->field[x][y] = element_new; } } ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */ /* initial gravity: 1 == "on", anything else (0) == "off" */ initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_gravity[i] = initial_player_gravity; ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */ /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) level->name[i] = fgetc(file); level->name[SP_LEVEL_NAME_LEN] = '\0'; /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */ ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */ /* number of infotrons needed; 0 means that Supaplex will count the total amount of infotrons in the level and use the low byte of that number (a multiple of 256 infotrons will result in "0 infotrons needed"!) */ level->gems_needed = fgetc(file); /* number of special ("gravity") port entries below (maximum 10 allowed) */ num_special_ports = fgetc(file); /* database of properties of up to 10 special ports (6 bytes per port) */ for (i = 0; i < 10; i++) { int port_location, port_x, port_y, port_element; int gravity; /* high and low byte of the location of a special port; if (x, y) are the coordinates of a port in the field and (0, 0) is the top-left corner, the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice of what may be expected: Supaplex works with a game field in memory which is 2 bytes per tile) */ port_location = getFile16BitBE(file); /* change gravity: 1 == "turn on", anything else (0) == "turn off" */ gravity = fgetc(file); /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */ ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */ /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */ ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */ ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */ if (i >= num_special_ports) continue; port_x = (port_location / 2) % SP_LEVEL_XSIZE; port_y = (port_location / 2) / SP_LEVEL_XSIZE; if (port_x < 0 || port_x >= SP_LEVEL_XSIZE || port_y < 0 || port_y >= SP_LEVEL_YSIZE) { Error(ERR_WARN, "special port position (%d, %d) out of bounds", port_x, port_y); continue; } port_element = level->field[port_x][port_y]; if (port_element < EL_SP_GRAVITY_PORT_RIGHT || port_element > EL_SP_GRAVITY_PORT_UP) { Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y); continue; } /* change previous (wrong) gravity inverting special port to either gravity enabling special port or gravity disabling special port */ level->field[port_x][port_y] += (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT : EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT; } ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */ /* change special gravity ports without database entries to normal ports */ for (y = 0; y < SP_LEVEL_YSIZE; y++) for (x = 0; x < SP_LEVEL_XSIZE; x++) if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT && level->field[x][y] <= EL_SP_GRAVITY_PORT_UP) level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT; /* auto-determine number of infotrons if it was stored as "0" -- see above */ if (level->gems_needed == 0) { for (y = 0; y < SP_LEVEL_YSIZE; y++) for (x = 0; x < SP_LEVEL_XSIZE; x++) if (level->field[x][y] == EL_SP_INFOTRON) level->gems_needed++; level->gems_needed &= 0xff; /* only use low byte -- see above */ } level->fieldx = SP_LEVEL_XSIZE; level->fieldy = SP_LEVEL_YSIZE; level->time = 0; /* no time limit */ level->amoeba_speed = 0; level->time_magic_wall = 0; level->time_wheel = 0; level->amoeba_content = EL_EMPTY; #if 1 /* original Supaplex does not use score values -- use default values */ #else for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = 0; #endif /* there are no yamyams in supaplex levels */ for (i = 0; i < level->num_yamyam_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = EL_EMPTY; } static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; FILE *file; int nr = level_file_info->nr - leveldir_current->first_level; int i, l, x, y; char name_first, name_last; struct LevelInfo multipart_level; int multipart_xpos, multipart_ypos; boolean is_multipart_level; boolean is_first_part; boolean reading_multipart_level = FALSE; boolean use_empty_level = FALSE; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } /* position file stream to the requested level inside the level package */ if (level_file_info->packed && fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return; } /* there exist Supaplex level package files with multi-part levels which can be detected as follows: instead of leading and trailing dashes ('-') to pad the level name, they have leading and trailing numbers which are the x and y coordinations of the current part of the multi-part level; if there are '?' characters instead of numbers on the left or right side of the level name, the multi-part level consists of only horizontal or vertical parts */ for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++) { LoadLevelFromFileStream_SP(file, level, l); /* check if this level is a part of a bigger multi-part level */ name_first = level->name[0]; name_last = level->name[SP_LEVEL_NAME_LEN - 1]; is_multipart_level = ((name_first == '?' || (name_first >= '0' && name_first <= '9')) && (name_last == '?' || (name_last >= '0' && name_last <= '9'))); is_first_part = ((name_first == '?' || name_first == '1') && (name_last == '?' || name_last == '1')); /* correct leading multipart level meta information in level name */ for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++) level->name[i] = '-'; /* correct trailing multipart level meta information in level name */ for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && level->name[i] == name_last; i--) level->name[i] = '-'; /* ---------- check for normal single level ---------- */ if (!reading_multipart_level && !is_multipart_level) { /* the current level is simply a normal single-part level, and we are not reading a multi-part level yet, so return the level as it is */ break; } /* ---------- check for empty level (unused multi-part) ---------- */ if (!reading_multipart_level && is_multipart_level && !is_first_part) { /* this is a part of a multi-part level, but not the first part (and we are not already reading parts of a multi-part level); in this case, use an empty level instead of the single part */ use_empty_level = TRUE; break; } /* ---------- check for finished multi-part level ---------- */ if (reading_multipart_level && (!is_multipart_level || !strEqual(level->name, multipart_level.name))) { /* we are already reading parts of a multi-part level, but this level is either not a multi-part level, or a part of a different multi-part level; in both cases, the multi-part level seems to be complete */ break; } /* ---------- here we have one part of a multi-part level ---------- */ reading_multipart_level = TRUE; if (is_first_part) /* start with first part of new multi-part level */ { /* copy level info structure from first part */ multipart_level = *level; /* clear playfield of new multi-part level */ for (y = 0; y < MAX_LEV_FIELDY; y++) for (x = 0; x < MAX_LEV_FIELDX; x++) multipart_level.field[x][y] = EL_EMPTY; } if (name_first == '?') name_first = '1'; if (name_last == '?') name_last = '1'; multipart_xpos = (int)(name_first - '0'); multipart_ypos = (int)(name_last - '0'); #if 0 printf("----------> part (%d/%d) of multi-part level '%s'\n", multipart_xpos, multipart_ypos, multipart_level.name); #endif if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX || multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY) { Error(ERR_WARN, "multi-part level is too big -- ignoring part of it"); break; } multipart_level.fieldx = MAX(multipart_level.fieldx, multipart_xpos * SP_LEVEL_XSIZE); multipart_level.fieldy = MAX(multipart_level.fieldy, multipart_ypos * SP_LEVEL_YSIZE); /* copy level part at the right position of multi-part level */ for (y = 0; y < SP_LEVEL_YSIZE; y++) { for (x = 0; x < SP_LEVEL_XSIZE; x++) { int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE; int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE; multipart_level.field[start_x + x][start_y + y] = level->field[x][y]; } } } fclose(file); if (use_empty_level) { setLevelInfoToDefaults(level); level->fieldx = SP_LEVEL_XSIZE; level->fieldy = SP_LEVEL_YSIZE; for (y = 0; y < SP_LEVEL_YSIZE; y++) for (x = 0; x < SP_LEVEL_XSIZE; x++) level->field[x][y] = EL_EMPTY; strcpy(level->name, "-------- EMPTY --------"); Error(ERR_WARN, "single part of multi-part level -- using empty level"); } if (reading_multipart_level) *level = multipart_level; } #endif void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; int i, x, y; level_sp->width = level->fieldx; level_sp->height = level->fieldy; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]); header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0); for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = level->name[i]; /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */ header->InfotronsNeeded = level->gems_needed; header->SpecialPortCount = 0; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) { boolean gravity_port_found = FALSE; boolean gravity_port_valid = FALSE; int gravity_port_flag; int gravity_port_base_element; int element = level->field[x][y]; if (element >= EL_SP_GRAVITY_ON_PORT_RIGHT && element <= EL_SP_GRAVITY_ON_PORT_UP) { gravity_port_found = TRUE; gravity_port_valid = TRUE; gravity_port_flag = 1; gravity_port_base_element = EL_SP_GRAVITY_ON_PORT_RIGHT; } else if (element >= EL_SP_GRAVITY_OFF_PORT_RIGHT && element <= EL_SP_GRAVITY_OFF_PORT_UP) { gravity_port_found = TRUE; gravity_port_valid = TRUE; gravity_port_flag = 0; gravity_port_base_element = EL_SP_GRAVITY_OFF_PORT_RIGHT; } else if (element >= EL_SP_GRAVITY_PORT_RIGHT && element <= EL_SP_GRAVITY_PORT_UP) { /* change R'n'D style gravity inverting special port to normal port (there are no gravity inverting ports in native Supaplex engine) */ gravity_port_found = TRUE; gravity_port_valid = FALSE; gravity_port_base_element = EL_SP_GRAVITY_PORT_RIGHT; } if (gravity_port_found) { if (gravity_port_valid && header->SpecialPortCount < SP_MAX_SPECIAL_PORTS) { SpecialPortType *port = &header->SpecialPort[header->SpecialPortCount]; port->PortLocation = (y * level->fieldx + x) * 2; port->Gravity = gravity_port_flag; element += EL_SP_GRAVITY_PORT_RIGHT - gravity_port_base_element; header->SpecialPortCount++; } else { /* change special gravity port to normal port */ element += EL_SP_PORT_RIGHT - gravity_port_base_element; } level_sp->playfield[x][y] = element - EL_SP_START; } } } void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; int i, x, y; level->fieldx = level_sp->width; level->fieldy = level_sp->height; for (x = 0; x < level->fieldx; x++) { for (y = 0; y < level->fieldy; y++) { int element_old = level_sp->playfield[x][y]; int element_new = getMappedElement(map_element_SP_to_RND(element_old)); if (element_new == EL_UNKNOWN) Error(ERR_WARN, "invalid element %d at position %d, %d", element_old, x, y); level->field[x][y] = element_new; } } for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_gravity[i] = (header->InitialGravity == 1 ? TRUE : FALSE); for (i = 0; i < SP_LEVEL_NAME_LEN; i++) level->name[i] = header->LevelTitle[i]; level->name[SP_LEVEL_NAME_LEN] = '\0'; level->gems_needed = header->InfotronsNeeded; for (i = 0; i < header->SpecialPortCount; i++) { SpecialPortType *port = &header->SpecialPort[i]; int port_location = port->PortLocation; int gravity = port->Gravity; int port_x, port_y, port_element; port_x = (port_location / 2) % level->fieldx; port_y = (port_location / 2) / level->fieldx; if (port_x < 0 || port_x >= level->fieldx || port_y < 0 || port_y >= level->fieldy) { Error(ERR_WARN, "special port position (%d, %d) out of bounds", port_x, port_y); continue; } port_element = level->field[port_x][port_y]; if (port_element < EL_SP_GRAVITY_PORT_RIGHT || port_element > EL_SP_GRAVITY_PORT_UP) { Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y); continue; } /* change previous (wrong) gravity inverting special port to either gravity enabling special port or gravity disabling special port */ level->field[port_x][port_y] += (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT : EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT; } /* change special gravity ports without database entries to normal ports */ for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT && level->field[x][y] <= EL_SP_GRAVITY_PORT_UP) level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT; level->time = 0; /* no time limit */ level->amoeba_speed = 0; level->time_magic_wall = 0; level->time_wheel = 0; level->amoeba_content = EL_EMPTY; #if 1 /* original Supaplex does not use score values -- use default values */ #else for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = 0; #endif /* there are no yamyams in supaplex levels */ for (i = 0; i < level->num_yamyam_contents; i++) for (x = 0; x < 3; x++) for (y = 0; y < 3; y++) level->yamyam_content[i].e[x][y] = EL_EMPTY; } static void CopyNativeTape_RND_to_SP(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; struct DemoInfo_SP *demo = &level_sp->demo; int i, j; /* always start with reliable default values */ demo->is_available = FALSE; demo->length = 0; if (TAPE_IS_EMPTY(tape)) return; demo->level_nr = tape.level_nr; /* (currently not used) */ level_sp->header.DemoRandomSeed = tape.random_seed; demo->length = 0; for (i = 0; i < tape.length; i++) { int demo_action = map_key_RND_to_SP(tape.pos[i].action[0]); int demo_repeat = tape.pos[i].delay; for (j = 0; j < demo_repeat / 16; j++) demo->data[demo->length++] = 0xf0 | demo_action; if (demo_repeat % 16) demo->data[demo->length++] = ((demo_repeat % 16 - 1) << 4) | demo_action; } demo->data[demo->length++] = 0xff; demo->is_available = TRUE; } static void setTapeInfoToDefaults(); static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; struct DemoInfo_SP *demo = &level_sp->demo; char *filename = level->file_info.filename; int i; /* always start with reliable default values */ setTapeInfoToDefaults(); if (!demo->is_available) return; tape.level_nr = demo->level_nr; /* (currently not used) */ tape.length = demo->length - 1; /* without "end of demo" byte */ tape.random_seed = level_sp->header.DemoRandomSeed; TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename)); for (i = 0; i < demo->length - 1; i++) { int demo_action = demo->data[i] & 0x0f; int demo_repeat = (demo->data[i] & 0xf0) >> 4; tape.pos[i].action[0] = map_key_SP_to_RND(demo_action); tape.pos[i].delay = demo_repeat + 1; } tape.length_seconds = GetTapeLength(); } /* ------------------------------------------------------------------------- */ /* functions for loading DC level */ /* ------------------------------------------------------------------------- */ #define DC_LEVEL_HEADER_SIZE 344 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init) { static int last_data_encoded; static int offset1; static int offset2; int diff; int diff_hi, diff_lo; int data_hi, data_lo; unsigned short data_decoded; if (init) { last_data_encoded = 0; offset1 = -1; offset2 = 0; return 0; } diff = data_encoded - last_data_encoded; diff_hi = diff & ~0xff; diff_lo = diff & 0xff; offset2 += diff_lo; data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00); data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff; data_hi = data_hi & 0xff00; data_decoded = data_hi | data_lo; last_data_encoded = data_encoded; offset1 = (offset1 + 1) % 31; offset2 = offset2 & 0xff; return data_decoded; } int getMappedElement_DC(int element) { switch (element) { case 0x0000: element = EL_ROCK; break; /* 0x0117 - 0x036e: (?) */ /* EL_DIAMOND */ /* 0x042d - 0x0684: (?) */ /* EL_EMERALD */ case 0x06f1: element = EL_NUT; break; case 0x074c: element = EL_BOMB; break; case 0x07a4: element = EL_PEARL; break; case 0x0823: element = EL_CRYSTAL; break; case 0x0e77: /* quicksand (boulder) */ element = EL_QUICKSAND_FAST_FULL; break; case 0x0e99: /* slow quicksand (boulder) */ element = EL_QUICKSAND_FULL; break; case 0x0ed2: element = EL_EM_EXIT_OPEN; break; case 0x0ee3: element = EL_EM_EXIT_CLOSED; break; case 0x0eeb: element = EL_EM_STEEL_EXIT_OPEN; break; case 0x0efc: element = EL_EM_STEEL_EXIT_CLOSED; break; case 0x0f4f: /* dynamite (lit 1) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f57: /* dynamite (lit 2) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f5f: /* dynamite (lit 3) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f67: /* dynamite (lit 4) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f81: case 0x0f82: case 0x0f83: case 0x0f84: element = EL_AMOEBA_WET; break; case 0x0f85: element = EL_AMOEBA_DROP; break; case 0x0fb9: element = EL_DC_MAGIC_WALL; break; case 0x0fd0: element = EL_SPACESHIP_UP; break; case 0x0fd9: element = EL_SPACESHIP_DOWN; break; case 0x0ff1: element = EL_SPACESHIP_LEFT; break; case 0x0ff9: element = EL_SPACESHIP_RIGHT; break; case 0x1057: element = EL_BUG_UP; break; case 0x1060: element = EL_BUG_DOWN; break; case 0x1078: element = EL_BUG_LEFT; break; case 0x1080: element = EL_BUG_RIGHT; break; case 0x10de: element = EL_MOLE_UP; break; case 0x10e7: element = EL_MOLE_DOWN; break; case 0x10ff: element = EL_MOLE_LEFT; break; case 0x1107: element = EL_MOLE_RIGHT; break; case 0x11c0: element = EL_ROBOT; break; case 0x13f5: element = EL_YAMYAM; break; case 0x1425: element = EL_SWITCHGATE_OPEN; break; case 0x1426: element = EL_SWITCHGATE_CLOSED; break; case 0x1437: element = EL_DC_SWITCHGATE_SWITCH_UP; break; case 0x143a: element = EL_TIMEGATE_CLOSED; break; case 0x144c: /* conveyor belt switch (green) */ element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE; break; case 0x144f: /* conveyor belt switch (red) */ element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE; break; case 0x1452: /* conveyor belt switch (blue) */ element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE; break; case 0x145b: element = EL_CONVEYOR_BELT_3_MIDDLE; break; case 0x1463: element = EL_CONVEYOR_BELT_3_LEFT; break; case 0x146b: element = EL_CONVEYOR_BELT_3_RIGHT; break; case 0x1473: element = EL_CONVEYOR_BELT_1_MIDDLE; break; case 0x147b: element = EL_CONVEYOR_BELT_1_LEFT; break; case 0x1483: element = EL_CONVEYOR_BELT_1_RIGHT; break; case 0x148b: element = EL_CONVEYOR_BELT_4_MIDDLE; break; case 0x1493: element = EL_CONVEYOR_BELT_4_LEFT; break; case 0x149b: element = EL_CONVEYOR_BELT_4_RIGHT; break; case 0x14ac: element = EL_EXPANDABLE_WALL_HORIZONTAL; break; case 0x14bd: element = EL_EXPANDABLE_WALL_VERTICAL; break; case 0x14c6: element = EL_EXPANDABLE_WALL_ANY; break; case 0x14ce: /* growing steel wall (left/right) */ element = EL_EXPANDABLE_STEELWALL_HORIZONTAL; break; case 0x14df: /* growing steel wall (up/down) */ element = EL_EXPANDABLE_STEELWALL_VERTICAL; break; case 0x14e8: /* growing steel wall (up/down/left/right) */ element = EL_EXPANDABLE_STEELWALL_ANY; break; case 0x14e9: element = EL_SHIELD_DEADLY; break; case 0x1501: element = EL_EXTRA_TIME; break; case 0x154f: element = EL_ACID; break; case 0x1577: element = EL_EMPTY_SPACE; break; case 0x1578: /* quicksand (empty) */ element = EL_QUICKSAND_FAST_EMPTY; break; case 0x1579: /* slow quicksand (empty) */ element = EL_QUICKSAND_EMPTY; break; /* 0x157c - 0x158b: */ /* EL_SAND */ /* 0x1590 - 0x159f: */ /* EL_DC_LANDMINE */ case 0x15a0: element = EL_EM_DYNAMITE; break; case 0x15a1: /* key (red) */ element = EL_EM_KEY_1; break; case 0x15a2: /* key (yellow) */ element = EL_EM_KEY_2; break; case 0x15a3: /* key (blue) */ element = EL_EM_KEY_4; break; case 0x15a4: /* key (green) */ element = EL_EM_KEY_3; break; case 0x15a5: /* key (white) */ element = EL_DC_KEY_WHITE; break; case 0x15a6: element = EL_WALL_SLIPPERY; break; case 0x15a7: element = EL_WALL; break; case 0x15a8: /* wall (not round) */ element = EL_WALL; break; case 0x15a9: /* (blue) */ element = EL_CHAR_A; break; case 0x15aa: /* (blue) */ element = EL_CHAR_B; break; case 0x15ab: /* (blue) */ element = EL_CHAR_C; break; case 0x15ac: /* (blue) */ element = EL_CHAR_D; break; case 0x15ad: /* (blue) */ element = EL_CHAR_E; break; case 0x15ae: /* (blue) */ element = EL_CHAR_F; break; case 0x15af: /* (blue) */ element = EL_CHAR_G; break; case 0x15b0: /* (blue) */ element = EL_CHAR_H; break; case 0x15b1: /* (blue) */ element = EL_CHAR_I; break; case 0x15b2: /* (blue) */ element = EL_CHAR_J; break; case 0x15b3: /* (blue) */ element = EL_CHAR_K; break; case 0x15b4: /* (blue) */ element = EL_CHAR_L; break; case 0x15b5: /* (blue) */ element = EL_CHAR_M; break; case 0x15b6: /* (blue) */ element = EL_CHAR_N; break; case 0x15b7: /* (blue) */ element = EL_CHAR_O; break; case 0x15b8: /* (blue) */ element = EL_CHAR_P; break; case 0x15b9: /* (blue) */ element = EL_CHAR_Q; break; case 0x15ba: /* (blue) */ element = EL_CHAR_R; break; case 0x15bb: /* (blue) */ element = EL_CHAR_S; break; case 0x15bc: /* (blue) */ element = EL_CHAR_T; break; case 0x15bd: /* (blue) */ element = EL_CHAR_U; break; case 0x15be: /* (blue) */ element = EL_CHAR_V; break; case 0x15bf: /* (blue) */ element = EL_CHAR_W; break; case 0x15c0: /* (blue) */ element = EL_CHAR_X; break; case 0x15c1: /* (blue) */ element = EL_CHAR_Y; break; case 0x15c2: /* (blue) */ element = EL_CHAR_Z; break; case 0x15c3: /* (blue) */ element = EL_CHAR_AUMLAUT; break; case 0x15c4: /* (blue) */ element = EL_CHAR_OUMLAUT; break; case 0x15c5: /* (blue) */ element = EL_CHAR_UUMLAUT; break; case 0x15c6: /* (blue) */ element = EL_CHAR_0; break; case 0x15c7: /* (blue) */ element = EL_CHAR_1; break; case 0x15c8: /* (blue) */ element = EL_CHAR_2; break; case 0x15c9: /* (blue) */ element = EL_CHAR_3; break; case 0x15ca: /* (blue) */ element = EL_CHAR_4; break; case 0x15cb: /* (blue) */ element = EL_CHAR_5; break; case 0x15cc: /* (blue) */ element = EL_CHAR_6; break; case 0x15cd: /* (blue) */ element = EL_CHAR_7; break; case 0x15ce: /* (blue) */ element = EL_CHAR_8; break; case 0x15cf: /* (blue) */ element = EL_CHAR_9; break; case 0x15d0: /* (blue) */ element = EL_CHAR_PERIOD; break; case 0x15d1: /* (blue) */ element = EL_CHAR_EXCLAM; break; case 0x15d2: /* (blue) */ element = EL_CHAR_COLON; break; case 0x15d3: /* (blue) */ element = EL_CHAR_LESS; break; case 0x15d4: /* (blue) */ element = EL_CHAR_GREATER; break; case 0x15d5: /* (blue) */ element = EL_CHAR_QUESTION; break; case 0x15d6: /* (blue) */ element = EL_CHAR_COPYRIGHT; break; case 0x15d7: /* (blue) */ element = EL_CHAR_UP; break; case 0x15d8: /* (blue) */ element = EL_CHAR_DOWN; break; case 0x15d9: /* (blue) */ element = EL_CHAR_BUTTON; break; case 0x15da: /* (blue) */ element = EL_CHAR_PLUS; break; case 0x15db: /* (blue) */ element = EL_CHAR_MINUS; break; case 0x15dc: /* (blue) */ element = EL_CHAR_APOSTROPHE; break; case 0x15dd: /* (blue) */ element = EL_CHAR_PARENLEFT; break; case 0x15de: /* (blue) */ element = EL_CHAR_PARENRIGHT; break; case 0x15df: /* (green) */ element = EL_CHAR_A; break; case 0x15e0: /* (green) */ element = EL_CHAR_B; break; case 0x15e1: /* (green) */ element = EL_CHAR_C; break; case 0x15e2: /* (green) */ element = EL_CHAR_D; break; case 0x15e3: /* (green) */ element = EL_CHAR_E; break; case 0x15e4: /* (green) */ element = EL_CHAR_F; break; case 0x15e5: /* (green) */ element = EL_CHAR_G; break; case 0x15e6: /* (green) */ element = EL_CHAR_H; break; case 0x15e7: /* (green) */ element = EL_CHAR_I; break; case 0x15e8: /* (green) */ element = EL_CHAR_J; break; case 0x15e9: /* (green) */ element = EL_CHAR_K; break; case 0x15ea: /* (green) */ element = EL_CHAR_L; break; case 0x15eb: /* (green) */ element = EL_CHAR_M; break; case 0x15ec: /* (green) */ element = EL_CHAR_N; break; case 0x15ed: /* (green) */ element = EL_CHAR_O; break; case 0x15ee: /* (green) */ element = EL_CHAR_P; break; case 0x15ef: /* (green) */ element = EL_CHAR_Q; break; case 0x15f0: /* (green) */ element = EL_CHAR_R; break; case 0x15f1: /* (green) */ element = EL_CHAR_S; break; case 0x15f2: /* (green) */ element = EL_CHAR_T; break; case 0x15f3: /* (green) */ element = EL_CHAR_U; break; case 0x15f4: /* (green) */ element = EL_CHAR_V; break; case 0x15f5: /* (green) */ element = EL_CHAR_W; break; case 0x15f6: /* (green) */ element = EL_CHAR_X; break; case 0x15f7: /* (green) */ element = EL_CHAR_Y; break; case 0x15f8: /* (green) */ element = EL_CHAR_Z; break; case 0x15f9: /* (green) */ element = EL_CHAR_AUMLAUT; break; case 0x15fa: /* (green) */ element = EL_CHAR_OUMLAUT; break; case 0x15fb: /* (green) */ element = EL_CHAR_UUMLAUT; break; case 0x15fc: /* (green) */ element = EL_CHAR_0; break; case 0x15fd: /* (green) */ element = EL_CHAR_1; break; case 0x15fe: /* (green) */ element = EL_CHAR_2; break; case 0x15ff: /* (green) */ element = EL_CHAR_3; break; case 0x1600: /* (green) */ element = EL_CHAR_4; break; case 0x1601: /* (green) */ element = EL_CHAR_5; break; case 0x1602: /* (green) */ element = EL_CHAR_6; break; case 0x1603: /* (green) */ element = EL_CHAR_7; break; case 0x1604: /* (green) */ element = EL_CHAR_8; break; case 0x1605: /* (green) */ element = EL_CHAR_9; break; case 0x1606: /* (green) */ element = EL_CHAR_PERIOD; break; case 0x1607: /* (green) */ element = EL_CHAR_EXCLAM; break; case 0x1608: /* (green) */ element = EL_CHAR_COLON; break; case 0x1609: /* (green) */ element = EL_CHAR_LESS; break; case 0x160a: /* (green) */ element = EL_CHAR_GREATER; break; case 0x160b: /* (green) */ element = EL_CHAR_QUESTION; break; case 0x160c: /* (green) */ element = EL_CHAR_COPYRIGHT; break; case 0x160d: /* (green) */ element = EL_CHAR_UP; break; case 0x160e: /* (green) */ element = EL_CHAR_DOWN; break; case 0x160f: /* (green) */ element = EL_CHAR_BUTTON; break; case 0x1610: /* (green) */ element = EL_CHAR_PLUS; break; case 0x1611: /* (green) */ element = EL_CHAR_MINUS; break; case 0x1612: /* (green) */ element = EL_CHAR_APOSTROPHE; break; case 0x1613: /* (green) */ element = EL_CHAR_PARENLEFT; break; case 0x1614: /* (green) */ element = EL_CHAR_PARENRIGHT; break; case 0x1615: /* (blue steel) */ element = EL_STEEL_CHAR_A; break; case 0x1616: /* (blue steel) */ element = EL_STEEL_CHAR_B; break; case 0x1617: /* (blue steel) */ element = EL_STEEL_CHAR_C; break; case 0x1618: /* (blue steel) */ element = EL_STEEL_CHAR_D; break; case 0x1619: /* (blue steel) */ element = EL_STEEL_CHAR_E; break; case 0x161a: /* (blue steel) */ element = EL_STEEL_CHAR_F; break; case 0x161b: /* (blue steel) */ element = EL_STEEL_CHAR_G; break; case 0x161c: /* (blue steel) */ element = EL_STEEL_CHAR_H; break; case 0x161d: /* (blue steel) */ element = EL_STEEL_CHAR_I; break; case 0x161e: /* (blue steel) */ element = EL_STEEL_CHAR_J; break; case 0x161f: /* (blue steel) */ element = EL_STEEL_CHAR_K; break; case 0x1620: /* (blue steel) */ element = EL_STEEL_CHAR_L; break; case 0x1621: /* (blue steel) */ element = EL_STEEL_CHAR_M; break; case 0x1622: /* (blue steel) */ element = EL_STEEL_CHAR_N; break; case 0x1623: /* (blue steel) */ element = EL_STEEL_CHAR_O; break; case 0x1624: /* (blue steel) */ element = EL_STEEL_CHAR_P; break; case 0x1625: /* (blue steel) */ element = EL_STEEL_CHAR_Q; break; case 0x1626: /* (blue steel) */ element = EL_STEEL_CHAR_R; break; case 0x1627: /* (blue steel) */ element = EL_STEEL_CHAR_S; break; case 0x1628: /* (blue steel) */ element = EL_STEEL_CHAR_T; break; case 0x1629: /* (blue steel) */ element = EL_STEEL_CHAR_U; break; case 0x162a: /* (blue steel) */ element = EL_STEEL_CHAR_V; break; case 0x162b: /* (blue steel) */ element = EL_STEEL_CHAR_W; break; case 0x162c: /* (blue steel) */ element = EL_STEEL_CHAR_X; break; case 0x162d: /* (blue steel) */ element = EL_STEEL_CHAR_Y; break; case 0x162e: /* (blue steel) */ element = EL_STEEL_CHAR_Z; break; case 0x162f: /* (blue steel) */ element = EL_STEEL_CHAR_AUMLAUT; break; case 0x1630: /* (blue steel) */ element = EL_STEEL_CHAR_OUMLAUT; break; case 0x1631: /* (blue steel) */ element = EL_STEEL_CHAR_UUMLAUT; break; case 0x1632: /* (blue steel) */ element = EL_STEEL_CHAR_0; break; case 0x1633: /* (blue steel) */ element = EL_STEEL_CHAR_1; break; case 0x1634: /* (blue steel) */ element = EL_STEEL_CHAR_2; break; case 0x1635: /* (blue steel) */ element = EL_STEEL_CHAR_3; break; case 0x1636: /* (blue steel) */ element = EL_STEEL_CHAR_4; break; case 0x1637: /* (blue steel) */ element = EL_STEEL_CHAR_5; break; case 0x1638: /* (blue steel) */ element = EL_STEEL_CHAR_6; break; case 0x1639: /* (blue steel) */ element = EL_STEEL_CHAR_7; break; case 0x163a: /* (blue steel) */ element = EL_STEEL_CHAR_8; break; case 0x163b: /* (blue steel) */ element = EL_STEEL_CHAR_9; break; case 0x163c: /* (blue steel) */ element = EL_STEEL_CHAR_PERIOD; break; case 0x163d: /* (blue steel) */ element = EL_STEEL_CHAR_EXCLAM; break; case 0x163e: /* (blue steel) */ element = EL_STEEL_CHAR_COLON; break; case 0x163f: /* (blue steel) */ element = EL_STEEL_CHAR_LESS; break; case 0x1640: /* (blue steel) */ element = EL_STEEL_CHAR_GREATER; break; case 0x1641: /* (blue steel) */ element = EL_STEEL_CHAR_QUESTION; break; case 0x1642: /* (blue steel) */ element = EL_STEEL_CHAR_COPYRIGHT; break; case 0x1643: /* (blue steel) */ element = EL_STEEL_CHAR_UP; break; case 0x1644: /* (blue steel) */ element = EL_STEEL_CHAR_DOWN; break; case 0x1645: /* (blue steel) */ element = EL_STEEL_CHAR_BUTTON; break; case 0x1646: /* (blue steel) */ element = EL_STEEL_CHAR_PLUS; break; case 0x1647: /* (blue steel) */ element = EL_STEEL_CHAR_MINUS; break; case 0x1648: /* (blue steel) */ element = EL_STEEL_CHAR_APOSTROPHE; break; case 0x1649: /* (blue steel) */ element = EL_STEEL_CHAR_PARENLEFT; break; case 0x164a: /* (blue steel) */ element = EL_STEEL_CHAR_PARENRIGHT; break; case 0x164b: /* (green steel) */ element = EL_STEEL_CHAR_A; break; case 0x164c: /* (green steel) */ element = EL_STEEL_CHAR_B; break; case 0x164d: /* (green steel) */ element = EL_STEEL_CHAR_C; break; case 0x164e: /* (green steel) */ element = EL_STEEL_CHAR_D; break; case 0x164f: /* (green steel) */ element = EL_STEEL_CHAR_E; break; case 0x1650: /* (green steel) */ element = EL_STEEL_CHAR_F; break; case 0x1651: /* (green steel) */ element = EL_STEEL_CHAR_G; break; case 0x1652: /* (green steel) */ element = EL_STEEL_CHAR_H; break; case 0x1653: /* (green steel) */ element = EL_STEEL_CHAR_I; break; case 0x1654: /* (green steel) */ element = EL_STEEL_CHAR_J; break; case 0x1655: /* (green steel) */ element = EL_STEEL_CHAR_K; break; case 0x1656: /* (green steel) */ element = EL_STEEL_CHAR_L; break; case 0x1657: /* (green steel) */ element = EL_STEEL_CHAR_M; break; case 0x1658: /* (green steel) */ element = EL_STEEL_CHAR_N; break; case 0x1659: /* (green steel) */ element = EL_STEEL_CHAR_O; break; case 0x165a: /* (green steel) */ element = EL_STEEL_CHAR_P; break; case 0x165b: /* (green steel) */ element = EL_STEEL_CHAR_Q; break; case 0x165c: /* (green steel) */ element = EL_STEEL_CHAR_R; break; case 0x165d: /* (green steel) */ element = EL_STEEL_CHAR_S; break; case 0x165e: /* (green steel) */ element = EL_STEEL_CHAR_T; break; case 0x165f: /* (green steel) */ element = EL_STEEL_CHAR_U; break; case 0x1660: /* (green steel) */ element = EL_STEEL_CHAR_V; break; case 0x1661: /* (green steel) */ element = EL_STEEL_CHAR_W; break; case 0x1662: /* (green steel) */ element = EL_STEEL_CHAR_X; break; case 0x1663: /* (green steel) */ element = EL_STEEL_CHAR_Y; break; case 0x1664: /* (green steel) */ element = EL_STEEL_CHAR_Z; break; case 0x1665: /* (green steel) */ element = EL_STEEL_CHAR_AUMLAUT; break; case 0x1666: /* (green steel) */ element = EL_STEEL_CHAR_OUMLAUT; break; case 0x1667: /* (green steel) */ element = EL_STEEL_CHAR_UUMLAUT; break; case 0x1668: /* (green steel) */ element = EL_STEEL_CHAR_0; break; case 0x1669: /* (green steel) */ element = EL_STEEL_CHAR_1; break; case 0x166a: /* (green steel) */ element = EL_STEEL_CHAR_2; break; case 0x166b: /* (green steel) */ element = EL_STEEL_CHAR_3; break; case 0x166c: /* (green steel) */ element = EL_STEEL_CHAR_4; break; case 0x166d: /* (green steel) */ element = EL_STEEL_CHAR_5; break; case 0x166e: /* (green steel) */ element = EL_STEEL_CHAR_6; break; case 0x166f: /* (green steel) */ element = EL_STEEL_CHAR_7; break; case 0x1670: /* (green steel) */ element = EL_STEEL_CHAR_8; break; case 0x1671: /* (green steel) */ element = EL_STEEL_CHAR_9; break; case 0x1672: /* (green steel) */ element = EL_STEEL_CHAR_PERIOD; break; case 0x1673: /* (green steel) */ element = EL_STEEL_CHAR_EXCLAM; break; case 0x1674: /* (green steel) */ element = EL_STEEL_CHAR_COLON; break; case 0x1675: /* (green steel) */ element = EL_STEEL_CHAR_LESS; break; case 0x1676: /* (green steel) */ element = EL_STEEL_CHAR_GREATER; break; case 0x1677: /* (green steel) */ element = EL_STEEL_CHAR_QUESTION; break; case 0x1678: /* (green steel) */ element = EL_STEEL_CHAR_COPYRIGHT; break; case 0x1679: /* (green steel) */ element = EL_STEEL_CHAR_UP; break; case 0x167a: /* (green steel) */ element = EL_STEEL_CHAR_DOWN; break; case 0x167b: /* (green steel) */ element = EL_STEEL_CHAR_BUTTON; break; case 0x167c: /* (green steel) */ element = EL_STEEL_CHAR_PLUS; break; case 0x167d: /* (green steel) */ element = EL_STEEL_CHAR_MINUS; break; case 0x167e: /* (green steel) */ element = EL_STEEL_CHAR_APOSTROPHE; break; case 0x167f: /* (green steel) */ element = EL_STEEL_CHAR_PARENLEFT; break; case 0x1680: /* (green steel) */ element = EL_STEEL_CHAR_PARENRIGHT; break; case 0x1681: /* gate (red) */ element = EL_EM_GATE_1; break; case 0x1682: /* secret gate (red) */ element = EL_GATE_1_GRAY; break; case 0x1683: /* gate (yellow) */ element = EL_EM_GATE_2; break; case 0x1684: /* secret gate (yellow) */ element = EL_GATE_2_GRAY; break; case 0x1685: /* gate (blue) */ element = EL_EM_GATE_4; break; case 0x1686: /* secret gate (blue) */ element = EL_GATE_4_GRAY; break; case 0x1687: /* gate (green) */ element = EL_EM_GATE_3; break; case 0x1688: /* secret gate (green) */ element = EL_GATE_3_GRAY; break; case 0x1689: /* gate (white) */ element = EL_DC_GATE_WHITE; break; case 0x168a: /* secret gate (white) */ element = EL_DC_GATE_WHITE_GRAY; break; case 0x168b: /* secret gate (no key) */ element = EL_DC_GATE_FAKE_GRAY; break; case 0x168c: element = EL_ROBOT_WHEEL; break; case 0x168d: element = EL_DC_TIMEGATE_SWITCH; break; case 0x168e: element = EL_ACID_POOL_BOTTOM; break; case 0x168f: element = EL_ACID_POOL_TOPLEFT; break; case 0x1690: element = EL_ACID_POOL_TOPRIGHT; break; case 0x1691: element = EL_ACID_POOL_BOTTOMLEFT; break; case 0x1692: element = EL_ACID_POOL_BOTTOMRIGHT; break; case 0x1693: element = EL_STEELWALL; break; case 0x1694: element = EL_STEELWALL_SLIPPERY; break; case 0x1695: /* steel wall (not round) */ element = EL_STEELWALL; break; case 0x1696: /* steel wall (left) */ element = EL_DC_STEELWALL_1_LEFT; break; case 0x1697: /* steel wall (bottom) */ element = EL_DC_STEELWALL_1_BOTTOM; break; case 0x1698: /* steel wall (right) */ element = EL_DC_STEELWALL_1_RIGHT; break; case 0x1699: /* steel wall (top) */ element = EL_DC_STEELWALL_1_TOP; break; case 0x169a: /* steel wall (left/bottom) */ element = EL_DC_STEELWALL_1_BOTTOMLEFT; break; case 0x169b: /* steel wall (right/bottom) */ element = EL_DC_STEELWALL_1_BOTTOMRIGHT; break; case 0x169c: /* steel wall (right/top) */ element = EL_DC_STEELWALL_1_TOPRIGHT; break; case 0x169d: /* steel wall (left/top) */ element = EL_DC_STEELWALL_1_TOPLEFT; break; case 0x169e: /* steel wall (right/bottom small) */ element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2; break; case 0x169f: /* steel wall (left/bottom small) */ element = EL_DC_STEELWALL_1_BOTTOMLEFT_2; break; case 0x16a0: /* steel wall (right/top small) */ element = EL_DC_STEELWALL_1_TOPRIGHT_2; break; case 0x16a1: /* steel wall (left/top small) */ element = EL_DC_STEELWALL_1_TOPLEFT_2; break; case 0x16a2: /* steel wall (left/right) */ element = EL_DC_STEELWALL_1_VERTICAL; break; case 0x16a3: /* steel wall (top/bottom) */ element = EL_DC_STEELWALL_1_HORIZONTAL; break; case 0x16a4: /* steel wall 2 (left end) */ element = EL_DC_STEELWALL_2_LEFT; break; case 0x16a5: /* steel wall 2 (right end) */ element = EL_DC_STEELWALL_2_RIGHT; break; case 0x16a6: /* steel wall 2 (top end) */ element = EL_DC_STEELWALL_2_TOP; break; case 0x16a7: /* steel wall 2 (bottom end) */ element = EL_DC_STEELWALL_2_BOTTOM; break; case 0x16a8: /* steel wall 2 (left/right) */ element = EL_DC_STEELWALL_2_HORIZONTAL; break; case 0x16a9: /* steel wall 2 (up/down) */ element = EL_DC_STEELWALL_2_VERTICAL; break; case 0x16aa: /* steel wall 2 (mid) */ element = EL_DC_STEELWALL_2_MIDDLE; break; case 0x16ab: element = EL_SIGN_EXCLAMATION; break; case 0x16ac: element = EL_SIGN_RADIOACTIVITY; break; case 0x16ad: element = EL_SIGN_STOP; break; case 0x16ae: element = EL_SIGN_WHEELCHAIR; break; case 0x16af: element = EL_SIGN_PARKING; break; case 0x16b0: element = EL_SIGN_NO_ENTRY; break; case 0x16b1: element = EL_SIGN_HEART; break; case 0x16b2: element = EL_SIGN_GIVE_WAY; break; case 0x16b3: element = EL_SIGN_ENTRY_FORBIDDEN; break; case 0x16b4: element = EL_SIGN_EMERGENCY_EXIT; break; case 0x16b5: element = EL_SIGN_YIN_YANG; break; case 0x16b6: element = EL_WALL_EMERALD; break; case 0x16b7: element = EL_WALL_DIAMOND; break; case 0x16b8: element = EL_WALL_PEARL; break; case 0x16b9: element = EL_WALL_CRYSTAL; break; case 0x16ba: element = EL_INVISIBLE_WALL; break; case 0x16bb: element = EL_INVISIBLE_STEELWALL; break; /* 0x16bc - 0x16cb: */ /* EL_INVISIBLE_SAND */ case 0x16cc: element = EL_LIGHT_SWITCH; break; case 0x16cd: element = EL_ENVELOPE_1; break; default: if (element >= 0x0117 && element <= 0x036e) /* (?) */ element = EL_DIAMOND; else if (element >= 0x042d && element <= 0x0684) /* (?) */ element = EL_EMERALD; else if (element >= 0x157c && element <= 0x158b) element = EL_SAND; else if (element >= 0x1590 && element <= 0x159f) element = EL_DC_LANDMINE; else if (element >= 0x16bc && element <= 0x16cb) element = EL_INVISIBLE_SAND; else { Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element); element = EL_UNKNOWN; } break; } return getMappedElement(element); } #if 1 static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level, int nr) { byte header[DC_LEVEL_HEADER_SIZE]; int envelope_size; int envelope_header_pos = 62; int envelope_content_pos = 94; int level_name_pos = 251; int level_author_pos = 292; int envelope_header_len; int envelope_content_len; int level_name_len; int level_author_len; int fieldx, fieldy; int num_yamyam_contents; int i, x, y; getDecodedWord_DC(0, TRUE); /* initialize DC2 decoding engine */ for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++) { unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE); header[i * 2 + 0] = header_word >> 8; header[i * 2 + 1] = header_word & 0xff; } /* read some values from level header to check level decoding integrity */ fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); num_yamyam_contents = header[60] | (header[61] << 8); /* do some simple sanity checks to ensure that level was correctly decoded */ if (fieldx < 1 || fieldx > 256 || fieldy < 1 || fieldy > 256 || num_yamyam_contents < 1 || num_yamyam_contents > 8) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot decode level from stream -- using empty level"); return; } /* maximum envelope header size is 31 bytes */ envelope_header_len = header[envelope_header_pos]; /* maximum envelope content size is 110 (156?) bytes */ envelope_content_len = header[envelope_content_pos]; /* maximum level title size is 40 bytes */ level_name_len = MIN(header[level_name_pos], MAX_LEVEL_NAME_LEN); /* maximum level author size is 30 (51?) bytes */ level_author_len = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN); envelope_size = 0; for (i = 0; i < envelope_header_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_header_pos + 1 + i]; if (envelope_header_len > 0 && envelope_content_len > 0) { if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; } for (i = 0; i < envelope_content_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_content_pos + 1 + i]; level->envelope[0].text[envelope_size] = '\0'; level->envelope[0].xsize = MAX_ENVELOPE_XSIZE; level->envelope[0].ysize = 10; level->envelope[0].autowrap = TRUE; level->envelope[0].centered = TRUE; for (i = 0; i < level_name_len; i++) level->name[i] = header[level_name_pos + 1 + i]; level->name[level_name_len] = '\0'; for (i = 0; i < level_author_len; i++) level->author[i] = header[level_author_pos + 1 + i]; level->author[level_author_len] = '\0'; num_yamyam_contents = header[60] | (header[61] << 8); level->num_yamyam_contents = MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS); for (i = 0; i < num_yamyam_contents; i++) { for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); #if 1 int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); #else int element_dc = word; #endif if (i < MAX_ELEMENT_CONTENTS) level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc); } } fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX); level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY); for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); #if 1 int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); #else int element_dc = word; #endif if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY) level->field[x][y] = getMappedElement_DC(element_dc); } x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_1; x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_2; level->gems_needed = header[18] | (header[19] << 8); level->score[SC_EMERALD] = header[20] | (header[21] << 8); level->score[SC_DIAMOND] = header[22] | (header[23] << 8); level->score[SC_PEARL] = header[24] | (header[25] << 8); level->score[SC_CRYSTAL] = header[26] | (header[27] << 8); level->score[SC_NUT] = header[28] | (header[29] << 8); level->score[SC_ROBOT] = header[30] | (header[31] << 8); level->score[SC_SPACESHIP] = header[32] | (header[33] << 8); level->score[SC_BUG] = header[34] | (header[35] << 8); level->score[SC_YAMYAM] = header[36] | (header[37] << 8); level->score[SC_DYNAMITE] = header[38] | (header[39] << 8); level->score[SC_KEY] = header[40] | (header[41] << 8); level->score[SC_TIME_BONUS] = header[42] | (header[43] << 8); level->time = header[44] | (header[45] << 8); level->amoeba_speed = header[46] | (header[47] << 8); level->time_light = header[48] | (header[49] << 8); level->time_timegate = header[50] | (header[51] << 8); level->time_wheel = header[52] | (header[53] << 8); level->time_magic_wall = header[54] | (header[55] << 8); level->extra_time = header[56] | (header[57] << 8); level->shield_normal_time = header[58] | (header[59] << 8); /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems can slip down from flat walls, like normal walls and steel walls */ level->em_slippery_gems = TRUE; #if 0 /* Diamond Caves II levels are always surrounded by indestructible wall, but not necessarily in a rectangular way -- fill with invisible steel wall */ /* !!! not always true !!! keep level and set BorderElement instead !!! */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { #if 1 if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == EL_EMPTY) level->field[x][y] = EL_INVISIBLE_STEELWALL; #else if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == EL_EMPTY) FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL, level->field, level->fieldx, level->fieldy); #endif } #endif } static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; FILE *file; int num_magic_bytes = 8; char magic_bytes[num_magic_bytes + 1]; int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } // fseek(file, 0x0000, SEEK_SET); if (level_file_info->packed) { /* read "magic bytes" from start of file */ fgets(magic_bytes, num_magic_bytes + 1, file); /* check "magic bytes" for correct file format */ if (!strPrefix(magic_bytes, "DC2")) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown DC level file '%s' -- using empty level", filename); return; } if (strPrefix(magic_bytes, "DC2Win95") || strPrefix(magic_bytes, "DC2Win98")) { int position_first_level = 0x00fa; int extra_bytes = 4; int skip_bytes; /* advance file stream to first level inside the level package */ skip_bytes = position_first_level - num_magic_bytes - extra_bytes; /* each block of level data is followed by block of non-level data */ num_levels_to_skip *= 2; /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */ while (num_levels_to_skip >= 0) { /* advance file stream to next level inside the level package */ if (fseek(file, skip_bytes, SEEK_CUR) != 0) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return; } /* skip apparently unused extra bytes following each level */ ReadUnusedBytesFromFile(file, extra_bytes); /* read size of next level in level package */ skip_bytes = getFile32BitLE(file); num_levels_to_skip--; } } else { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level", filename); return; } } LoadLevelFromFileStream_DC(file, level, level_file_info->nr); fclose(file); } #else static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; FILE *file; #if 0 int nr = level_file_info->nr - leveldir_current->first_level; #endif byte header[DC_LEVEL_HEADER_SIZE]; int envelope_size; int envelope_header_pos = 62; int envelope_content_pos = 94; int level_name_pos = 251; int level_author_pos = 292; int envelope_header_len; int envelope_content_len; int level_name_len; int level_author_len; int fieldx, fieldy; int num_yamyam_contents; int i, x, y; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } #if 0 /* position file stream to the requested level inside the level package */ if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return; } #endif getDecodedWord_DC(0, TRUE); /* initialize DC2 decoding engine */ for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++) { unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE); header[i * 2 + 0] = header_word >> 8; header[i * 2 + 1] = header_word & 0xff; } /* read some values from level header to check level decoding integrity */ fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); num_yamyam_contents = header[60] | (header[61] << 8); /* do some simple sanity checks to ensure that level was correctly decoded */ if (fieldx < 1 || fieldx > 256 || fieldy < 1 || fieldy > 256 || num_yamyam_contents < 1 || num_yamyam_contents > 8) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level from file '%s' -- using empty level", filename); return; } /* maximum envelope header size is 31 bytes */ envelope_header_len = header[envelope_header_pos]; /* maximum envelope content size is 110 (156?) bytes */ envelope_content_len = header[envelope_content_pos]; /* maximum level title size is 40 bytes */ level_name_len = MIN(header[level_name_pos], MAX_LEVEL_NAME_LEN); /* maximum level author size is 30 (51?) bytes */ level_author_len = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN); envelope_size = 0; for (i = 0; i < envelope_header_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_header_pos + 1 + i]; if (envelope_header_len > 0 && envelope_content_len > 0) { if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; } for (i = 0; i < envelope_content_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_content_pos + 1 + i]; level->envelope[0].text[envelope_size] = '\0'; level->envelope[0].xsize = MAX_ENVELOPE_XSIZE; level->envelope[0].ysize = 10; level->envelope[0].autowrap = TRUE; level->envelope[0].centered = TRUE; for (i = 0; i < level_name_len; i++) level->name[i] = header[level_name_pos + 1 + i]; level->name[level_name_len] = '\0'; for (i = 0; i < level_author_len; i++) level->author[i] = header[level_author_pos + 1 + i]; level->author[level_author_len] = '\0'; num_yamyam_contents = header[60] | (header[61] << 8); level->num_yamyam_contents = MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS); for (i = 0; i < num_yamyam_contents; i++) { for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); #if 1 int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); #else int element_dc = word; #endif if (i < MAX_ELEMENT_CONTENTS) level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc); } } fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX); level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY); for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); #if 1 int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); #else int element_dc = word; #endif if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY) level->field[x][y] = getMappedElement_DC(element_dc); } x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_1; x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_2; level->gems_needed = header[18] | (header[19] << 8); level->score[SC_EMERALD] = header[20] | (header[21] << 8); level->score[SC_DIAMOND] = header[22] | (header[23] << 8); level->score[SC_PEARL] = header[24] | (header[25] << 8); level->score[SC_CRYSTAL] = header[26] | (header[27] << 8); level->score[SC_NUT] = header[28] | (header[29] << 8); level->score[SC_ROBOT] = header[30] | (header[31] << 8); level->score[SC_SPACESHIP] = header[32] | (header[33] << 8); level->score[SC_BUG] = header[34] | (header[35] << 8); level->score[SC_YAMYAM] = header[36] | (header[37] << 8); level->score[SC_DYNAMITE] = header[38] | (header[39] << 8); level->score[SC_KEY] = header[40] | (header[41] << 8); level->score[SC_TIME_BONUS] = header[42] | (header[43] << 8); level->time = header[44] | (header[45] << 8); level->amoeba_speed = header[46] | (header[47] << 8); level->time_light = header[48] | (header[49] << 8); level->time_timegate = header[50] | (header[51] << 8); level->time_wheel = header[52] | (header[53] << 8); level->time_magic_wall = header[54] | (header[55] << 8); level->extra_time = header[56] | (header[57] << 8); level->shield_normal_time = header[58] | (header[59] << 8); fclose(file); /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems can slip down from flat walls, like normal walls and steel walls */ level->em_slippery_gems = TRUE; #if 0 /* Diamond Caves II levels are always surrounded by indestructible wall, but not necessarily in a rectangular way -- fill with invisible steel wall */ /* !!! not always true !!! keep level and set BorderElement instead !!! */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { #if 1 if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == EL_EMPTY) level->field[x][y] = EL_INVISIBLE_STEELWALL; #else if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == EL_EMPTY) FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL, level->field, level->fieldx, level->fieldy); #endif } #endif } #endif /* ------------------------------------------------------------------------- */ /* functions for loading SB level */ /* ------------------------------------------------------------------------- */ int getMappedElement_SB(int element_ascii, boolean use_ces) { static struct { int ascii; int sb; int ce; } sb_element_mapping[] = { { ' ', EL_EMPTY, EL_CUSTOM_1 }, /* floor (space) */ { '#', EL_STEELWALL, EL_CUSTOM_2 }, /* wall */ { '@', EL_PLAYER_1, EL_CUSTOM_3 }, /* player */ { '$', EL_SOKOBAN_OBJECT, EL_CUSTOM_4 }, /* box */ { '.', EL_SOKOBAN_FIELD_EMPTY, EL_CUSTOM_5 }, /* goal square */ { '*', EL_SOKOBAN_FIELD_FULL, EL_CUSTOM_6 }, /* box on goal square */ { '+', EL_SOKOBAN_FIELD_PLAYER, EL_CUSTOM_7 }, /* player on goal square */ #if 0 { '_', EL_INVISIBLE_STEELWALL, EL_CUSTOM_8 }, /* floor beyond border */ #else { '_', EL_INVISIBLE_STEELWALL, EL_FROM_LEVEL_TEMPLATE }, /* floor beyond border */ #endif { 0, -1, -1 }, }; int i; for (i = 0; sb_element_mapping[i].ascii != 0; i++) if (element_ascii == sb_element_mapping[i].ascii) return (use_ces ? sb_element_mapping[i].ce : sb_element_mapping[i].sb); return EL_UNDEFINED; } static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { char *filename = level_file_info->filename; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char last_comment[MAX_LINE_LEN]; char level_name[MAX_LINE_LEN]; char *line_ptr; FILE *file; int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level; boolean read_continued_line = FALSE; boolean reading_playfield = FALSE; boolean got_valid_playfield_line = FALSE; boolean invalid_playfield_char = FALSE; boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces"); int file_level_nr = 0; int line_nr = 0; int x = 0, y = 0; /* initialized to make compilers happy */ #if 0 printf("::: looking for level number %d [%d]\n", level_file_info->nr, num_levels_to_skip); #endif last_comment[0] = '\0'; level_name[0] = '\0'; if (!(file = fopen(filename, MODE_READ))) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } while (!feof(file)) { /* level successfully read, but next level may follow here */ if (!got_valid_playfield_line && reading_playfield) { #if 0 printf("::: read complete playfield\n"); #endif /* read playfield from single level file -- skip remaining file */ if (!level_file_info->packed) break; if (file_level_nr >= num_levels_to_skip) break; file_level_nr++; last_comment[0] = '\0'; level_name[0] = '\0'; reading_playfield = FALSE; } got_valid_playfield_line = FALSE; /* read next line of input file */ if (!fgets(line, MAX_LINE_LEN, file)) break; /* check if line was completely read and is terminated by line break */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line_nr++; /* cut trailing line break (this can be newline and/or carriage return) */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* copy raw input line for later use (mainly debugging output) */ strcpy(line_raw, line); if (read_continued_line) { /* append new line to existing line, if there is enough space */ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) strcat(previous_line, line_ptr); strcpy(line, previous_line); /* copy storage buffer to line */ read_continued_line = FALSE; } /* if the last character is '\', continue at next line */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ strcpy(previous_line, line); /* copy line to storage buffer */ read_continued_line = TRUE; continue; } /* skip empty lines */ if (line[0] == '\0') continue; /* extract comment text from comment line */ if (line[0] == ';') { for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != ';') break; strcpy(last_comment, line_ptr); #if 0 printf("::: found comment '%s' in line %d\n", last_comment, line_nr); #endif continue; } /* extract level title text from line containing level title */ if (line[0] == '\'') { strcpy(level_name, &line[1]); if (strlen(level_name) > 0 && level_name[strlen(level_name) - 1] == '\'') level_name[strlen(level_name) - 1] = '\0'; #if 0 printf("::: found level name '%s' in line %d\n", level_name, line_nr); #endif continue; } /* skip lines containing only spaces (or empty lines) */ for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ') break; if (*line_ptr == '\0') continue; /* at this point, we have found a line containing part of a playfield */ #if 0 printf("::: found playfield row in line %d\n", line_nr); #endif got_valid_playfield_line = TRUE; if (!reading_playfield) { reading_playfield = TRUE; invalid_playfield_char = FALSE; for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) level->field[x][y] = getMappedElement_SB(' ', load_xsb_to_ces); level->fieldx = 0; level->fieldy = 0; /* start with topmost tile row */ y = 0; } /* skip playfield line if larger row than allowed */ if (y >= MAX_LEV_FIELDY) continue; /* start with leftmost tile column */ x = 0; /* read playfield elements from line */ for (line_ptr = line; *line_ptr; line_ptr++) { int mapped_sb_element = getMappedElement_SB(*line_ptr, load_xsb_to_ces); /* stop parsing playfield line if larger column than allowed */ if (x >= MAX_LEV_FIELDX) break; if (mapped_sb_element == EL_UNDEFINED) { invalid_playfield_char = TRUE; break; } level->field[x][y] = mapped_sb_element; /* continue with next tile column */ x++; level->fieldx = MAX(x, level->fieldx); } if (invalid_playfield_char) { /* if first playfield line, treat invalid lines as comment lines */ if (y == 0) reading_playfield = FALSE; continue; } /* continue with next tile row */ y++; } fclose(file); level->fieldy = y; level->fieldx = MIN(MAX(MIN_LEV_FIELDX, level->fieldx), MAX_LEV_FIELDX); level->fieldy = MIN(MAX(MIN_LEV_FIELDY, level->fieldy), MAX_LEV_FIELDY); if (!reading_playfield) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } if (*level_name != '\0') { strncpy(level->name, level_name, MAX_LEVEL_NAME_LEN); level->name[MAX_LEVEL_NAME_LEN] = '\0'; #if 0 printf(":1: level name: '%s'\n", level->name); #endif } else if (*last_comment != '\0') { strncpy(level->name, last_comment, MAX_LEVEL_NAME_LEN); level->name[MAX_LEVEL_NAME_LEN] = '\0'; #if 0 printf(":2: level name: '%s'\n", level->name); #endif } else { sprintf(level->name, "--> Level %d <--", level_file_info->nr); } /* set all empty fields beyond the border walls to invisible steel wall */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == getMappedElement_SB(' ', load_xsb_to_ces)) FloodFillLevel(x, y, getMappedElement_SB('_', load_xsb_to_ces), level->field, level->fieldx, level->fieldy); } /* set special level settings for Sokoban levels */ level->time = 0; level->use_step_counter = TRUE; if (load_xsb_to_ces) { #if 1 /* !!! special global settings can now be set in level template !!! */ #else level->initial_player_stepsize[0] = STEPSIZE_SLOW; #endif /* fill smaller playfields with padding "beyond border wall" elements */ if (level->fieldx < SCR_FIELDX || level->fieldy < SCR_FIELDY) { short field[level->fieldx][level->fieldy]; int new_fieldx = MAX(level->fieldx, SCR_FIELDX); int new_fieldy = MAX(level->fieldy, SCR_FIELDY); int pos_fieldx = (new_fieldx - level->fieldx) / 2; int pos_fieldy = (new_fieldy - level->fieldy) / 2; /* copy old playfield (which is smaller than the visible area) */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) field[x][y] = level->field[x][y]; /* fill new, larger playfield with "beyond border wall" elements */ for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++) level->field[x][y] = getMappedElement_SB('_', load_xsb_to_ces); /* copy the old playfield to the middle of the new playfield */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) level->field[pos_fieldx + x][pos_fieldy + y] = field[x][y]; level->fieldx = new_fieldx; level->fieldy = new_fieldy; } level->use_custom_template = TRUE; } } /* ------------------------------------------------------------------------- */ /* functions for handling native levels */ /* ------------------------------------------------------------------------- */ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { if (!LoadNativeLevel_EM(level_file_info->filename)) level->no_valid_file = TRUE; } static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { int pos = 0; /* determine position of requested level inside level package */ if (level_file_info->packed) pos = level_file_info->nr - leveldir_current->first_level; if (!LoadNativeLevel_SP(level_file_info->filename, pos)) level->no_valid_file = TRUE; } void CopyNativeLevel_RND_to_Native(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_RND_to_EM(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_RND_to_SP(level); } void CopyNativeLevel_Native_to_RND(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_EM_to_RND(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_SP_to_RND(level); } void SaveNativeLevel(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_SP) { char *basename = getSingleLevelBasenameExt(level->file_info.nr, "sp"); char *filename = getLevelFilenameFromBasename(basename); CopyNativeLevel_RND_to_SP(level); CopyNativeTape_RND_to_SP(level); SaveNativeLevel_SP(filename); } } /* ------------------------------------------------------------------------- */ /* functions for loading generic level */ /* ------------------------------------------------------------------------- */ void LoadLevelFromFileInfo(struct LevelInfo *level, struct LevelFileInfo *level_file_info) { /* always start with reliable default values */ setLevelInfoToDefaults(level); switch (level_file_info->type) { case LEVEL_FILE_TYPE_RND: LoadLevelFromFileInfo_RND(level, level_file_info); break; case LEVEL_FILE_TYPE_EM: LoadLevelFromFileInfo_EM(level, level_file_info); level->game_engine_type = GAME_ENGINE_TYPE_EM; break; case LEVEL_FILE_TYPE_SP: LoadLevelFromFileInfo_SP(level, level_file_info); level->game_engine_type = GAME_ENGINE_TYPE_SP; break; case LEVEL_FILE_TYPE_DC: LoadLevelFromFileInfo_DC(level, level_file_info); break; case LEVEL_FILE_TYPE_SB: LoadLevelFromFileInfo_SB(level, level_file_info); break; default: LoadLevelFromFileInfo_RND(level, level_file_info); break; } /* if level file is invalid, restore level structure to default values */ if (level->no_valid_file) setLevelInfoToDefaults(level); if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN) level->game_engine_type = GAME_ENGINE_TYPE_RND; if (level_file_info->type != LEVEL_FILE_TYPE_RND) CopyNativeLevel_Native_to_RND(level); } void LoadLevelFromFilename(struct LevelInfo *level, char *filename) { static struct LevelFileInfo level_file_info; /* always start with reliable default values */ setFileInfoToDefaults(&level_file_info); level_file_info.nr = 0; /* unknown level number */ level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */ level_file_info.filename = filename; LoadLevelFromFileInfo(level, &level_file_info); } static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) { int i, j; if (leveldir_current == NULL) /* only when dumping level */ return; /* all engine modifications also valid for levels which use latest engine */ if (level->game_version < VERSION_IDENT(3,2,0,5)) { /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ level->score[SC_TIME_BONUS] /= 10; } #if 0 leveldir_current->latest_engine = TRUE; /* !!! TEST ONLY !!! */ #endif if (leveldir_current->latest_engine) { /* ---------- use latest game engine ----------------------------------- */ /* For all levels which are forced to use the latest game engine version (normally all but user contributed, private and undefined levels), set the game engine version to the actual version; this allows for actual corrections in the game engine to take effect for existing, converted levels (from "classic" or other existing games) to make the emulation of the corresponding game more accurate, while (hopefully) not breaking existing levels created from other players. */ level->game_version = GAME_VERSION_ACTUAL; /* Set special EM style gems behaviour: EM style gems slip down from normal, steel and growing wall. As this is a more fundamental change, it seems better to set the default behaviour to "off" (as it is more natural) and make it configurable in the level editor (as a property of gem style elements). Already existing converted levels (neither private nor contributed levels) are changed to the new behaviour. */ if (level->file_version < FILE_VERSION_2_0) level->em_slippery_gems = TRUE; return; } /* ---------- use game engine the level was created with ----------------- */ /* For all levels which are not forced to use the latest game engine version (normally user contributed, private and undefined levels), use the version of the game engine the levels were created for. Since 2.0.1, the game engine version is now directly stored in the level file (chunk "VERS"), so there is no need anymore to set the game version from the file version (except for old, pre-2.0 levels, where the game version is still taken from the file format version used to store the level -- see above). */ /* player was faster than enemies in 1.0.0 and before */ if (level->file_version == FILE_VERSION_1_0) for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_stepsize[i] = STEPSIZE_FAST; /* default behaviour for EM style gems was "slippery" only in 2.0.1 */ if (level->game_version == VERSION_IDENT(2,0,1,0)) level->em_slippery_gems = TRUE; /* springs could be pushed over pits before (pre-release version) 2.2.0 */ if (level->game_version < VERSION_IDENT(2,2,0,0)) level->use_spring_bug = TRUE; if (level->game_version < VERSION_IDENT(3,2,0,5)) { /* time orb caused limited time in endless time levels before 3.2.0-5 */ level->use_time_orb_bug = TRUE; /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */ level->block_snap_field = FALSE; /* extra time score was same value as time left score before 3.2.0-5 */ level->extra_time_score = level->score[SC_TIME_BONUS]; #if 0 /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ level->score[SC_TIME_BONUS] /= 10; #endif } if (level->game_version < VERSION_IDENT(3,2,0,7)) { /* default behaviour for snapping was "not continuous" before 3.2.0-7 */ level->continuous_snapping = FALSE; } /* only few elements were able to actively move into acid before 3.1.0 */ /* trigger settings did not exist before 3.1.0; set to default "any" */ if (level->game_version < VERSION_IDENT(3,1,0,0)) { /* correct "can move into acid" settings (all zero in old levels) */ level->can_move_into_acid_bits = 0; /* nothing can move into acid */ level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */ setMoveIntoAcidProperty(level, EL_ROBOT, TRUE); setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE); setMoveIntoAcidProperty(level, EL_PENGUIN, TRUE); setMoveIntoAcidProperty(level, EL_BALLOON, TRUE); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE); /* correct trigger settings (stored as zero == "none" in old levels) */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; change->trigger_player = CH_PLAYER_ANY; change->trigger_page = CH_PAGE_ANY; } } } /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */ { int element = EL_CUSTOM_256; struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[0]; /* This is needed to fix a problem that was caused by a bugfix in function game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did not replace walkable elements, but instead just placed the player on it, without placing the Sokoban field under the player). Unfortunately, this breaks "Snake Bite" style levels when the snake is halfway through a door that just closes (the snake head is still alive and can be moved in this case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the player (without Sokoban element) which then gets killed as designed). */ if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 || strncmp(ei->description, "pause b4 death", 14) == 0) && change->target_element == EL_SOKOBAN_FIELD_PLAYER) change->target_element = EL_PLAYER_1; } #if 1 /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */ if (level->game_version < VERSION_IDENT(3,2,5,0)) { /* This is needed to fix a problem that was caused by a bugfix in function game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that corrects the behaviour when a custom element changes to another custom element with a higher element number that has change actions defined. Normally, only one change per frame is allowed for custom elements. Therefore, it is checked if a custom element already changed in the current frame; if it did, subsequent changes are suppressed. Unfortunately, this is only checked for element changes, but not for change actions, which are still executed. As the function above loops through all custom elements from lower to higher, an element change resulting in a lower CE number won't be checked again, while a target element with a higher number will also be checked, and potential change actions will get executed for this CE, too (which is wrong), while further changes are ignored (which is correct). As this bugfix breaks Zelda II (and introduces graphical bugs to Zelda I, and also breaks a few other levels like Alan Bond's "FMV"), allow the previous, incorrect behaviour for existing levels and tapes that make use of this bug */ level->use_action_after_change_bug = TRUE; } #else /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */ /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */ { int element = EL_CUSTOM_16; struct ElementInfo *ei = &element_info[element]; /* This is needed to fix a problem that was caused by a bugfix in function game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that corrects the behaviour when a custom element changes to another custom element with a higher element number that has change actions defined. Normally, only one change per frame is allowed for custom elements. Therefore, it is checked if a custom element already changed in the current frame; if it did, subsequent changes are suppressed. Unfortunately, this is only checked for element changes, but not for change actions, which are still executed. As the function above loops through all custom elements from lower to higher, an element change resulting in a lower CE number won't be checked again, while a target element with a higher number will also be checked, and potential change actions will get executed for this CE, too (which is wrong), while further changes are ignored (which is correct). As this bugfix breaks Zelda II (but no other levels), allow the previous, incorrect behaviour for this outstanding level set to not break the game or existing tapes */ if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 || strncmp(ei->description, "scanline - row 1", 16) == 0) level->use_action_after_change_bug = TRUE; } #endif /* not centering level after relocating player was default only in 3.2.3 */ if (level->game_version == VERSION_IDENT(3,2,3,0)) /* (no pre-releases) */ level->shifted_relocation = TRUE; /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */ if (level->game_version < VERSION_IDENT(3,2,6,0)) level->em_explodes_by_fire = TRUE; } static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) { int i, j, x, y; /* map custom element change events that have changed in newer versions (these following values were accidentally changed in version 3.0.1) (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */ if (level->game_version <= VERSION_IDENT(3,0,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; /* order of checking and copying events to be mapped is important */ /* (do not change the start and end value -- they are constant) */ for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--) { if (HAS_CHANGE_EVENT(element, j - 2)) { SET_CHANGE_EVENT(element, j - 2, FALSE); SET_CHANGE_EVENT(element, j, TRUE); } } /* order of checking and copying events to be mapped is important */ /* (do not change the start and end value -- they are constant) */ for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--) { if (HAS_CHANGE_EVENT(element, j - 1)) { SET_CHANGE_EVENT(element, j - 1, FALSE); SET_CHANGE_EVENT(element, j, TRUE); } } } } /* initialize "can_change" field for old levels with only one change page */ if (level->game_version <= VERSION_IDENT(3,0,2,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (CAN_CHANGE(element)) element_info[element].change->can_change = TRUE; } } /* correct custom element values (for old levels without these options) */ if (level->game_version < VERSION_IDENT(3,1,1,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->access_direction == MV_NO_DIRECTION) ei->access_direction = MV_ALL_DIRECTIONS; } } /* correct custom element values (fix invalid values for all versions) */ if (1) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; if (change->trigger_player == CH_PLAYER_NONE) change->trigger_player = CH_PLAYER_ANY; if (change->trigger_side == CH_SIDE_NONE) change->trigger_side = CH_SIDE_ANY; } } } /* initialize "can_explode" field for old levels which did not store this */ /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */ if (level->game_version <= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (EXPLODES_1X1_OLD(element)) element_info[element].explosion_type = EXPLODES_1X1; SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) || EXPLODES_SMASHED(element) || EXPLODES_IMPACT(element))); } } /* correct previously hard-coded move delay values for maze runner style */ if (level->game_version < VERSION_IDENT(3,1,1,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE) { /* previously hard-coded and therefore ignored */ element_info[element].move_delay_fixed = 9; element_info[element].move_delay_random = 0; } } } /* map elements that have changed in newer versions */ level->amoeba_content = getMappedElementByVersion(level->amoeba_content, level->game_version); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (x = 0; x < 3; x++) for (y = 0; y < 3; y++) level->yamyam_content[i].e[x][y] = getMappedElementByVersion(level->yamyam_content[i].e[x][y], level->game_version); /* initialize element properties for level editor etc. */ InitElementPropertiesEngine(level->game_version); InitElementPropertiesAfterLoading(level->game_version); InitElementPropertiesGfxElement(); } static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) { int x, y; /* map elements that have changed in newer versions */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) level->field[x][y] = getMappedElementByVersion(level->field[x][y], level->game_version); /* copy elements to runtime playfield array */ for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) Feld[x][y] = level->field[x][y]; /* initialize level size variables for faster access */ lev_fieldx = level->fieldx; lev_fieldy = level->fieldy; /* determine border element for this level */ if (level->file_info.type == LEVEL_FILE_TYPE_DC) BorderElement = EL_EMPTY; /* (in editor, SetBorderElement() is used) */ else SetBorderElement(); } static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename) { struct LevelFileInfo *level_file_info = &level->file_info; if (level_file_info->type == LEVEL_FILE_TYPE_RND) CopyNativeLevel_RND_to_Native(level); } void LoadLevelTemplate(int nr) { char *filename; setLevelFileInfo(&level_template.file_info, nr); filename = level_template.file_info.filename; LoadLevelFromFileInfo(&level_template, &level_template.file_info); LoadLevel_InitVersion(&level_template, filename); LoadLevel_InitElements(&level_template, filename); ActivateLevelTemplate(); } void LoadLevel(int nr) { char *filename; setLevelFileInfo(&level.file_info, nr); filename = level.file_info.filename; LoadLevelFromFileInfo(&level, &level.file_info); if (level.use_custom_template) LoadLevelTemplate(-1); LoadLevel_InitVersion(&level, filename); LoadLevel_InitElements(&level, filename); LoadLevel_InitPlayfield(&level, filename); LoadLevel_InitNativeEngines(&level, filename); } static int SaveLevel_VERS(FILE *file, struct LevelInfo *level) { int chunk_size = 0; chunk_size += putFileVersion(file, level->file_version); chunk_size += putFileVersion(file, level->game_version); return chunk_size; } static int SaveLevel_DATE(FILE *file, struct LevelInfo *level) { int chunk_size = 0; chunk_size += putFile16BitBE(file, level->creation_date.year); chunk_size += putFile8Bit(file, level->creation_date.month); chunk_size += putFile8Bit(file, level->creation_date.day); return chunk_size; } #if 0 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) { int i, x, y; putFile8Bit(file, level->fieldx); putFile8Bit(file, level->fieldy); putFile16BitBE(file, level->time); putFile16BitBE(file, level->gems_needed); for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) putFile8Bit(file, level->name[i]); for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) putFile8Bit(file, level->score[i]); for (i = 0; i < STD_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY : level->yamyam_content[i].e[x][y])); putFile8Bit(file, level->amoeba_speed); putFile8Bit(file, level->time_magic_wall); putFile8Bit(file, level->time_wheel); putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content)); putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0)); putFile8Bit(file, (level->initial_gravity ? 1 : 0)); putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0)); putFile8Bit(file, (level->em_slippery_gems ? 1 : 0)); putFile8Bit(file, (level->use_custom_template ? 1 : 0)); putFile8Bit(file, (level->block_last_field ? 1 : 0)); putFile8Bit(file, (level->sp_block_last_field ? 1 : 0)); putFile32BitBE(file, level->can_move_into_acid_bits); putFile8Bit(file, level->dont_collide_with_bits); putFile8Bit(file, (level->use_spring_bug ? 1 : 0)); putFile8Bit(file, (level->use_step_counter ? 1 : 0)); putFile8Bit(file, (level->instant_relocation ? 1 : 0)); putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0)); putFile8Bit(file, (level->grow_into_diggable ? 1 : 0)); putFile8Bit(file, level->game_engine_type); WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED); } #endif static int SaveLevel_NAME(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) chunk_size += putFile8Bit(file, level->name[i]); return chunk_size; } static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) chunk_size += putFile8Bit(file, level->author[i]); return chunk_size; } #if 0 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int x, y; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) if (level->encoding_16bit_field) chunk_size += putFile16BitBE(file, level->field[x][y]); else chunk_size += putFile8Bit(file, level->field[x][y]); return chunk_size; } #endif static int SaveLevel_BODY(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int x, y; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) chunk_size += putFile16BitBE(file, level->field[x][y]); return chunk_size; } #if 0 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level) { int i, x, y; putFile8Bit(file, EL_YAMYAM); putFile8Bit(file, level->num_yamyam_contents); putFile8Bit(file, 0); putFile8Bit(file, 0); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (level->encoding_16bit_field) putFile16BitBE(file, level->yamyam_content[i].e[x][y]); else putFile8Bit(file, level->yamyam_content[i].e[x][y]); } #endif #if 0 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) { int i, x, y; int num_contents, content_xsize, content_ysize; int content_array[MAX_ELEMENT_CONTENTS][3][3]; if (element == EL_YAMYAM) { num_contents = level->num_yamyam_contents; content_xsize = 3; content_ysize = 3; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = level->yamyam_content[i].e[x][y]; } else if (element == EL_BD_AMOEBA) { num_contents = 1; content_xsize = 1; content_ysize = 1; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = EL_EMPTY; content_array[0][0][0] = level->amoeba_content; } else { /* chunk header already written -- write empty chunk data */ WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE); Error(ERR_WARN, "cannot save content for element '%d'", element); return; } putFile16BitBE(file, element); putFile8Bit(file, num_contents); putFile8Bit(file, content_xsize); putFile8Bit(file, content_ysize); WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, content_array[i][x][y]); } #endif #if 0 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element) { int envelope_nr = element - EL_ENVELOPE_1; int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); chunk_size += putFile16BitBE(file, envelope_len); chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]); chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]); WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED); chunk_size += LEVEL_CHUNK_CNT3_UNUSED; for (i = 0; i < envelope_len; i++) chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]); return chunk_size; } #endif #if 0 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom element properties"); } #endif #if 0 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (element_info[element].change->target_element != EL_EMPTY_SPACE) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); putFile16BitBE(file, element_info[element].change->target_element); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom target elements"); } #endif #if 0 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, j, x, y, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->modified_settings) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++) putFile8Bit(file, ei->description[j]); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); /* some free bytes for future properties and padding */ WriteUnusedBytesToFile(file, 7); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, ei->collect_score_initial); putFile8Bit(file, ei->collect_count_initial); putFile16BitBE(file, ei->push_delay_fixed); putFile16BitBE(file, ei->push_delay_random); putFile16BitBE(file, ei->move_delay_fixed); putFile16BitBE(file, ei->move_delay_random); putFile16BitBE(file, ei->move_pattern); putFile8Bit(file, ei->move_direction_initial); putFile8Bit(file, ei->move_stepsize); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->content.e[x][y]); putFile32BitBE(file, ei->change->events); putFile16BitBE(file, ei->change->target_element); putFile16BitBE(file, ei->change->delay_fixed); putFile16BitBE(file, ei->change->delay_random); putFile16BitBE(file, ei->change->delay_frames); putFile16BitBE(file, ei->change->initial_trigger_element); putFile8Bit(file, ei->change->explode); putFile8Bit(file, ei->change->use_target_content); putFile8Bit(file, ei->change->only_if_complete); putFile8Bit(file, ei->change->use_random_replace); putFile8Bit(file, ei->change->random_percentage); putFile8Bit(file, ei->change->replace_when); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->change->content.e[x][y]); putFile8Bit(file, ei->slippery_type); /* some free bytes for future properties and padding */ WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom element properties"); } #endif #if 0 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; int i, j, x, y; /* ---------- custom element base property values (96 bytes) ------------- */ putFile16BitBE(file, element); for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */ putFile8Bit(file, ei->num_change_pages); putFile16BitBE(file, ei->ce_value_fixed_initial); putFile16BitBE(file, ei->ce_value_random_initial); putFile8Bit(file, ei->use_last_ce_value); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, ei->collect_score_initial); putFile8Bit(file, ei->collect_count_initial); putFile8Bit(file, ei->drop_delay_fixed); putFile8Bit(file, ei->push_delay_fixed); putFile8Bit(file, ei->drop_delay_random); putFile8Bit(file, ei->push_delay_random); putFile16BitBE(file, ei->move_delay_fixed); putFile16BitBE(file, ei->move_delay_random); /* bits 0 - 15 of "move_pattern" ... */ putFile16BitBE(file, ei->move_pattern & 0xffff); putFile8Bit(file, ei->move_direction_initial); putFile8Bit(file, ei->move_stepsize); putFile8Bit(file, ei->slippery_type); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->content.e[x][y]); putFile16BitBE(file, ei->move_enter_element); putFile16BitBE(file, ei->move_leave_element); putFile8Bit(file, ei->move_leave_type); /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */ putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff); putFile8Bit(file, ei->access_direction); putFile8Bit(file, ei->explosion_delay); putFile8Bit(file, ei->ignition_delay); putFile8Bit(file, ei->explosion_type); /* some free bytes for future custom property values and padding */ WriteUnusedBytesToFile(file, 1); /* ---------- change page property values (48 bytes) --------------------- */ for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; unsigned int event_bits; /* bits 0 - 31 of "has_event[]" ... */ event_bits = 0; for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (change->has_event[j]) event_bits |= (1 << j); putFile32BitBE(file, event_bits); putFile16BitBE(file, change->target_element); putFile16BitBE(file, change->delay_fixed); putFile16BitBE(file, change->delay_random); putFile16BitBE(file, change->delay_frames); putFile16BitBE(file, change->initial_trigger_element); putFile8Bit(file, change->explode); putFile8Bit(file, change->use_target_content); putFile8Bit(file, change->only_if_complete); putFile8Bit(file, change->use_random_replace); putFile8Bit(file, change->random_percentage); putFile8Bit(file, change->replace_when); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, change->target_content.e[x][y]); putFile8Bit(file, change->can_change); putFile8Bit(file, change->trigger_side); putFile8Bit(file, change->trigger_player); putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE : log_2(change->trigger_page))); putFile8Bit(file, change->has_action); putFile8Bit(file, change->action_type); putFile8Bit(file, change->action_mode); putFile16BitBE(file, change->action_arg); /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ event_bits = 0; for (j = 32; j < NUM_CHANGE_EVENTS; j++) if (change->has_event[j]) event_bits |= (1 << (j - 32)); putFile8Bit(file, event_bits); } } #endif #if 0 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; int i; putFile16BitBE(file, element); for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); putFile8Bit(file, group->num_elements); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, group->choice_mode); /* some free bytes for future values and padding */ WriteUnusedBytesToFile(file, 3); for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++) putFile16BitBE(file, group->element[i]); } #endif static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry, boolean write_element) { int save_type = entry->save_type; int data_type = entry->data_type; int conf_type = entry->conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; int element = entry->element; int default_value = entry->default_value; int num_bytes = 0; boolean modified = FALSE; if (byte_mask != CONF_MASK_MULTI_BYTES) { void *value_ptr = entry->value; int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr : *(int *)value_ptr); /* check if any settings have been modified before saving them */ if (value != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit (file, value) : byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) : byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) : 0); } else if (data_type == TYPE_STRING) { char *default_string = entry->default_string; char *string = (char *)(entry->value); int string_length = strlen(string); int i; /* check if any settings have been modified before saving them */ if (!strEqual(string, default_string)) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, string_length); for (i = 0; i < string_length; i++) num_bytes += putFile8Bit(file, string[i]); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(entry->value); int num_elements = *(int *)(entry->num_entities); int i; /* check if any settings have been modified before saving them */ for (i = 0; i < num_elements; i++) if (element_array[i] != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES); for (i = 0; i < num_elements; i++) num_bytes += putFile16BitBE(file, element_array[i]); } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(entry->value); int num_contents = *(int *)(entry->num_entities); int i, x, y; /* check if any settings have been modified before saving them */ for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (content[i].e[x][y] != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES); for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) num_bytes += putFile16BitBE(file, content[i].e[x][y]); } return num_bytes; } static int SaveLevel_INFO(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; li = *level; /* copy level data into temporary buffer */ for (i = 0; chunk_config_INFO[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE); return chunk_size; } static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; li = *level; /* copy level data into temporary buffer */ for (i = 0; chunk_config_ELEM[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE); return chunk_size; } static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element) { int envelope_nr = element - EL_ENVELOPE_1; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); /* copy envelope data into temporary buffer */ xx_envelope = level->envelope[envelope_nr]; for (i = 0; chunk_config_NOTE[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE); return chunk_size; } static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; int chunk_size = 0; int i, j; chunk_size += putFile16BitBE(file, element); xx_ei = *ei; /* copy element data into temporary buffer */ /* set default description string for this specific element */ strcpy(xx_default_description, getDefaultElementDescription(ei)); #if 0 /* set (fixed) number of content areas (may be wrong by broken level file) */ /* (this is now directly corrected for broken level files after loading) */ xx_num_contents = 1; #endif for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE); for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; xx_current_change_page = i; xx_change = *change; /* copy change data into temporary buffer */ resetEventBits(); setEventBitsFromEventFlags(change); for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j], FALSE); } return chunk_size; } static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); xx_ei = *ei; /* copy element data into temporary buffer */ xx_group = *group; /* copy group data into temporary buffer */ /* set default description string for this specific element */ strcpy(xx_default_description, getDefaultElementDescription(ei)); for (i = 0; chunk_config_GRPX[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE); return chunk_size; } static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) { int chunk_size; int i; FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save level file '%s'", filename); return; } level->file_version = FILE_VERSION_ACTUAL; level->game_version = GAME_VERSION_ACTUAL; level->creation_date = getCurrentDate(); putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE); chunk_size = SaveLevel_VERS(NULL, level); putFileChunkBE(file, "VERS", chunk_size); SaveLevel_VERS(file, level); chunk_size = SaveLevel_DATE(NULL, level); putFileChunkBE(file, "DATE", chunk_size); SaveLevel_DATE(file, level); chunk_size = SaveLevel_NAME(NULL, level); putFileChunkBE(file, "NAME", chunk_size); SaveLevel_NAME(file, level); chunk_size = SaveLevel_AUTH(NULL, level); putFileChunkBE(file, "AUTH", chunk_size); SaveLevel_AUTH(file, level); chunk_size = SaveLevel_INFO(NULL, level); putFileChunkBE(file, "INFO", chunk_size); SaveLevel_INFO(file, level); chunk_size = SaveLevel_BODY(NULL, level); putFileChunkBE(file, "BODY", chunk_size); SaveLevel_BODY(file, level); chunk_size = SaveLevel_ELEM(NULL, level); if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "ELEM", chunk_size); SaveLevel_ELEM(file, level); } for (i = 0; i < NUM_ENVELOPES; i++) { int element = EL_ENVELOPE_1 + i; chunk_size = SaveLevel_NOTE(NULL, level, element); if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "NOTE", chunk_size); SaveLevel_NOTE(file, level, element); } } /* if not using template level, check for non-default custom/group elements */ if (!level->use_custom_template) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; chunk_size = SaveLevel_CUSX(NULL, level, element); if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "CUSX", chunk_size); SaveLevel_CUSX(file, level, element); } } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; chunk_size = SaveLevel_GRPX(NULL, level, element); if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "GRPX", chunk_size); SaveLevel_GRPX(file, level, element); } } } fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); } void SaveLevel(int nr) { char *filename = getDefaultLevelFilename(nr); SaveLevelFromFilename(&level, filename); } void SaveLevelTemplate() { char *filename = getDefaultLevelFilename(-1); SaveLevelFromFilename(&level, filename); } boolean SaveLevelChecked(int nr) { char *filename = getDefaultLevelFilename(nr); boolean new_level = !fileExists(filename); boolean level_saved = FALSE; if (new_level || Request("Save this level and kill the old ?", REQ_ASK)) { SaveLevel(nr); if (new_level) Request("Level saved !", REQ_CONFIRM); level_saved = TRUE; } return level_saved; } void DumpLevel(struct LevelInfo *level) { if (level->no_valid_file) { Error(ERR_WARN, "cannot dump -- no valid level file found"); return; } printf_line("-", 79); printf("Level xxx (file version %08d, game version %08d)\n", level->file_version, level->game_version); printf_line("-", 79); printf("Level author: '%s'\n", level->author); printf("Level title: '%s'\n", level->name); printf("\n"); printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy); printf("\n"); printf("Level time: %d seconds\n", level->time); printf("Gems needed: %d\n", level->gems_needed); printf("\n"); printf("Time for magic wall: %d seconds\n", level->time_magic_wall); printf("Time for wheel: %d seconds\n", level->time_wheel); printf("Time for light: %d seconds\n", level->time_light); printf("Time for timegate: %d seconds\n", level->time_timegate); printf("\n"); printf("Amoeba speed: %d\n", level->amoeba_speed); printf("\n"); printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no")); printf("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no")); printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no")); printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no")); printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no")); printf_line("-", 79); } /* ========================================================================= */ /* tape file functions */ /* ========================================================================= */ static void setTapeInfoToDefaults() { int i; /* always start with reliable default values (empty tape) */ TapeErase(); /* default values (also for pre-1.2 tapes) with only the first player */ tape.player_participates[0] = TRUE; for (i = 1; i < MAX_PLAYERS; i++) tape.player_participates[i] = FALSE; /* at least one (default: the first) player participates in every tape */ tape.num_participating_players = 1; tape.level_nr = level_nr; tape.counter = 0; tape.changed = FALSE; tape.recording = FALSE; tape.playing = FALSE; tape.pausing = FALSE; tape.no_valid_file = FALSE; } static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape) { tape->file_version = getFileVersion(file); tape->game_version = getFileVersion(file); return chunk_size; } static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape) { int i; tape->random_seed = getFile32BitBE(file); tape->date = getFile32BitBE(file); tape->length = getFile32BitBE(file); /* read header fields that are new since version 1.2 */ if (tape->file_version >= FILE_VERSION_1_2) { byte store_participating_players = getFile8Bit(file); int engine_version; /* since version 1.2, tapes store which players participate in the tape */ tape->num_participating_players = 0; for (i = 0; i < MAX_PLAYERS; i++) { tape->player_participates[i] = FALSE; if (store_participating_players & (1 << i)) { tape->player_participates[i] = TRUE; tape->num_participating_players++; } } ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED); engine_version = getFileVersion(file); if (engine_version > 0) tape->engine_version = engine_version; else tape->engine_version = tape->game_version; } return chunk_size; } static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape) { int level_identifier_size; int i; level_identifier_size = getFile16BitBE(file); tape->level_identifier = checked_realloc(tape->level_identifier, level_identifier_size); for (i = 0; i < level_identifier_size; i++) tape->level_identifier[i] = getFile8Bit(file); tape->level_nr = getFile16BitBE(file); chunk_size = 2 + level_identifier_size + 2; return chunk_size; } static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape) { int i, j; int chunk_size_expected = (tape->num_participating_players + 1) * tape->length; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) break; for (j = 0; j < MAX_PLAYERS; j++) { tape->pos[i].action[j] = MV_NONE; if (tape->player_participates[j]) tape->pos[i].action[j] = getFile8Bit(file); } tape->pos[i].delay = getFile8Bit(file); if (tape->file_version == FILE_VERSION_1_0) { /* eliminate possible diagonal moves in old tapes */ /* this is only for backward compatibility */ byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN }; byte action = tape->pos[i].action[0]; int k, num_moves = 0; for (k = 0; k<4; k++) { if (action & joy_dir[k]) { tape->pos[i + num_moves].action[0] = joy_dir[k]; if (num_moves > 0) tape->pos[i + num_moves].delay = 0; num_moves++; } } if (num_moves > 1) { num_moves--; i += num_moves; tape->length += num_moves; } } else if (tape->file_version < FILE_VERSION_2_0) { /* convert pre-2.0 tapes to new tape format */ if (tape->pos[i].delay > 1) { /* action part */ tape->pos[i + 1] = tape->pos[i]; tape->pos[i + 1].delay = 1; /* delay part */ for (j = 0; j < MAX_PLAYERS; j++) tape->pos[i].action[j] = MV_NONE; tape->pos[i].delay--; i++; tape->length++; } } if (feof(file)) break; } if (i != tape->length) chunk_size = (tape->num_participating_players + 1) * i; return chunk_size; } void LoadTape_SokobanSolution(char *filename) { FILE *file; int move_delay = TILESIZE / level.initial_player_stepsize[0]; if (!(file = fopen(filename, MODE_READ))) { tape.no_valid_file = TRUE; return; } while (!feof(file)) { unsigned char c = fgetc(file); if (feof(file)) break; switch (c) { case 'u': case 'U': tape.pos[tape.length].action[0] = MV_UP; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'd': case 'D': tape.pos[tape.length].action[0] = MV_DOWN; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'l': case 'L': tape.pos[tape.length].action[0] = MV_LEFT; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'r': case 'R': tape.pos[tape.length].action[0] = MV_RIGHT; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case '\n': case '\r': case '\t': case ' ': /* ignore white-space characters */ break; default: tape.no_valid_file = TRUE; Error(ERR_WARN, "unsupported Sokoban solution file '%s' ['%d']", filename, c); break; } } fclose(file); if (tape.no_valid_file) return; tape.length_seconds = GetTapeLength(); } void LoadTapeFromFilename(char *filename) { char cookie[MAX_LINE_LEN]; char chunk_name[CHUNK_ID_LEN + 1]; FILE *file; int chunk_size; /* always start with reliable default values */ setTapeInfoToDefaults(); if (strSuffix(filename, ".sln")) { LoadTape_SokobanSolution(filename); return; } if (!(file = fopen(filename, MODE_READ))) { tape.no_valid_file = TRUE; return; } getFileChunkBE(file, chunk_name, NULL); if (strEqual(chunk_name, "RND1")) { getFile32BitBE(file); /* not used */ getFileChunkBE(file, chunk_name, NULL); if (!strEqual(chunk_name, "TAPE")) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unknown format of tape file '%s'", filename); fclose(file); return; } } else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); fgets(&cookie[4], MAX_LINE_LEN - 4, file); if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, TAPE_COOKIE_TMPL)) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unknown format of tape file '%s'", filename); fclose(file); return; } if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unsupported version of tape file '%s'", filename); fclose(file); return; } /* pre-2.0 tape files have no game version, so use file version here */ tape.game_version = tape.file_version; } if (tape.file_version < FILE_VERSION_1_2) { /* tape files from versions before 1.2.0 without chunk structure */ LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape); LoadTape_BODY(file, 2 * tape.length, &tape); } else { static struct { char *name; int size; int (*loader)(FILE *, int, struct TapeInfo *); } chunk_info[] = { { "VERS", TAPE_CHUNK_VERS_SIZE, LoadTape_VERS }, { "HEAD", TAPE_CHUNK_HEAD_SIZE, LoadTape_HEAD }, { "INFO", -1, LoadTape_INFO }, { "BODY", -1, LoadTape_BODY }, { NULL, 0, NULL } }; while (getFileChunkBE(file, chunk_name, &chunk_size)) { int i = 0; while (chunk_info[i].name != NULL && !strEqual(chunk_name, chunk_info[i].name)) i++; if (chunk_info[i].name == NULL) { Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'", chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else if (chunk_info[i].size != -1 && chunk_info[i].size != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'", chunk_size, chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else { /* call function to load this tape chunk */ int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, &tape); /* the size of some chunks cannot be checked before reading other chunks first (like "HEAD" and "BODY") that contain some header information, so check them here */ if (chunk_size_expected != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'", chunk_size, chunk_name, filename); } } } } fclose(file); tape.length_seconds = GetTapeLength(); #if 0 printf("::: tape file version: %d\n", tape.file_version); printf("::: tape game version: %d\n", tape.game_version); printf("::: tape engine version: %d\n", tape.engine_version); #endif } void LoadTape(int nr) { char *filename = getTapeFilename(nr); LoadTapeFromFilename(filename); } void LoadSolutionTape(int nr) { char *filename = getSolutionTapeFilename(nr); LoadTapeFromFilename(filename); #if 1 if (TAPE_IS_EMPTY(tape) && level.game_engine_type == GAME_ENGINE_TYPE_SP && level.native_sp_level->demo.is_available) CopyNativeTape_SP_to_RND(&level); #endif } static void SaveTape_VERS(FILE *file, struct TapeInfo *tape) { putFileVersion(file, tape->file_version); putFileVersion(file, tape->game_version); } static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape) { int i; byte store_participating_players = 0; /* set bits for participating players for compact storage */ for (i = 0; i < MAX_PLAYERS; i++) if (tape->player_participates[i]) store_participating_players |= (1 << i); putFile32BitBE(file, tape->random_seed); putFile32BitBE(file, tape->date); putFile32BitBE(file, tape->length); putFile8Bit(file, store_participating_players); /* unused bytes not at the end here for 4-byte alignment of engine_version */ WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED); putFileVersion(file, tape->engine_version); } static void SaveTape_INFO(FILE *file, struct TapeInfo *tape) { int level_identifier_size = strlen(tape->level_identifier) + 1; int i; putFile16BitBE(file, level_identifier_size); for (i = 0; i < level_identifier_size; i++) putFile8Bit(file, tape->level_identifier[i]); putFile16BitBE(file, tape->level_nr); } static void SaveTape_BODY(FILE *file, struct TapeInfo *tape) { int i, j; for (i = 0; i < tape->length; i++) { for (j = 0; j < MAX_PLAYERS; j++) if (tape->player_participates[j]) putFile8Bit(file, tape->pos[i].action[j]); putFile8Bit(file, tape->pos[i].delay); } } void SaveTape(int nr) { char *filename = getTapeFilename(nr); FILE *file; #if 0 boolean new_tape = TRUE; #endif int num_participating_players = 0; int info_chunk_size; int body_chunk_size; int i; InitTapeDirectory(leveldir_current->subdir); #if 0 /* if a tape still exists, ask to overwrite it */ if (fileExists(filename)) { new_tape = FALSE; if (!Request("Replace old tape ?", REQ_ASK)) return; } #endif if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save level recording file '%s'", filename); return; } tape.file_version = FILE_VERSION_ACTUAL; tape.game_version = GAME_VERSION_ACTUAL; /* count number of participating players */ for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) num_participating_players++; info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2; body_chunk_size = (num_participating_players + 1) * tape.length; putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE); putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE); SaveTape_VERS(file, &tape); putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE); SaveTape_HEAD(file, &tape); putFileChunkBE(file, "INFO", info_chunk_size); SaveTape_INFO(file, &tape); putFileChunkBE(file, "BODY", body_chunk_size); SaveTape_BODY(file, &tape); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); tape.changed = FALSE; #if 0 if (new_tape) Request("Tape saved !", REQ_CONFIRM); #endif } boolean SaveTapeChecked(int nr) { char *filename = getTapeFilename(nr); boolean new_tape = !fileExists(filename); boolean tape_saved = FALSE; if (new_tape || Request("Replace old tape ?", REQ_ASK)) { SaveTape(nr); if (new_tape) Request("Tape saved !", REQ_CONFIRM); tape_saved = TRUE; } return tape_saved; } void DumpTape(struct TapeInfo *tape) { int tape_frame_counter; int i, j; if (tape->no_valid_file) { Error(ERR_WARN, "cannot dump -- no valid tape file found"); return; } printf_line("-", 79); printf("Tape of Level %03d (file version %08d, game version %08d)\n", tape->level_nr, tape->file_version, tape->game_version); printf(" (effective engine version %08d)\n", tape->engine_version); printf("Level series identifier: '%s'\n", tape->level_identifier); printf_line("-", 79); tape_frame_counter = 0; for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) break; printf("%04d: ", i); for (j = 0; j < MAX_PLAYERS; j++) { if (tape->player_participates[j]) { int action = tape->pos[i].action[j]; printf("%d:%02x ", j, action); printf("[%c%c%c%c|%c%c] - ", (action & JOY_LEFT ? '<' : ' '), (action & JOY_RIGHT ? '>' : ' '), (action & JOY_UP ? '^' : ' '), (action & JOY_DOWN ? 'v' : ' '), (action & JOY_BUTTON_1 ? '1' : ' '), (action & JOY_BUTTON_2 ? '2' : ' ')); } } printf("(%03d) ", tape->pos[i].delay); printf("[%05d]\n", tape_frame_counter); tape_frame_counter += tape->pos[i].delay; } printf_line("-", 79); } /* ========================================================================= */ /* score file functions */ /* ========================================================================= */ void LoadScore(int nr) { int i; char *filename = getScoreFilename(nr); char cookie[MAX_LINE_LEN]; char line[MAX_LINE_LEN]; char *line_ptr; FILE *file; /* always start with reliable default values */ for (i = 0; i < MAX_SCORE_ENTRIES; i++) { strcpy(highscore[i].Name, EMPTY_PLAYER_NAME); highscore[i].Score = 0; } if (!(file = fopen(filename, MODE_READ))) return; /* check file identifier */ fgets(cookie, MAX_LINE_LEN, file); if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, SCORE_COOKIE)) { Error(ERR_WARN, "unknown format of score file '%s'", filename); fclose(file); return; } for (i = 0; i < MAX_SCORE_ENTRIES; i++) { fscanf(file, "%d", &highscore[i].Score); fgets(line, MAX_LINE_LEN, file); if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0') { strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN); highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0'; break; } } } fclose(file); } void SaveScore(int nr) { int i; char *filename = getScoreFilename(nr); FILE *file; InitScoreDirectory(leveldir_current->subdir); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save score for level %d", nr); return; } fprintf(file, "%s\n\n", SCORE_COOKIE); for (i = 0; i < MAX_SCORE_ENTRIES; i++) fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name); fclose(file); SetFilePermissions(filename, PERMS_PUBLIC); } /* ========================================================================= */ /* setup file functions */ /* ========================================================================= */ #define TOKEN_STR_PLAYER_PREFIX "player_" /* global setup */ #define SETUP_TOKEN_PLAYER_NAME 0 #define SETUP_TOKEN_SOUND 1 #define SETUP_TOKEN_SOUND_LOOPS 2 #define SETUP_TOKEN_SOUND_MUSIC 3 #define SETUP_TOKEN_SOUND_SIMPLE 4 #define SETUP_TOKEN_TOONS 5 #define SETUP_TOKEN_SCROLL_DELAY 6 #define SETUP_TOKEN_SCROLL_DELAY_VALUE 7 #define SETUP_TOKEN_SOFT_SCROLLING 8 #define SETUP_TOKEN_FADE_SCREENS 9 #define SETUP_TOKEN_AUTORECORD 10 #define SETUP_TOKEN_SHOW_TITLESCREEN 11 #define SETUP_TOKEN_QUICK_DOORS 12 #define SETUP_TOKEN_TEAM_MODE 13 #define SETUP_TOKEN_HANDICAP 14 #define SETUP_TOKEN_SKIP_LEVELS 15 #define SETUP_TOKEN_TIME_LIMIT 16 #define SETUP_TOKEN_FULLSCREEN 17 #define SETUP_TOKEN_FULLSCREEN_MODE 18 #define SETUP_TOKEN_ASK_ON_ESCAPE 19 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 20 #define SETUP_TOKEN_QUICK_SWITCH 21 #define SETUP_TOKEN_INPUT_ON_FOCUS 22 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS 23 #define SETUP_TOKEN_GAME_FRAME_DELAY 24 #define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS 25 #define SETUP_TOKEN_GRAPHICS_SET 26 #define SETUP_TOKEN_SOUNDS_SET 27 #define SETUP_TOKEN_MUSIC_SET 28 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 29 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 30 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 31 #define NUM_GLOBAL_SETUP_TOKENS 32 /* editor setup */ #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2 #define SETUP_TOKEN_EDITOR_EL_MORE 3 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 4 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 5 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 6 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 7 #define SETUP_TOKEN_EDITOR_EL_CHARS 8 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS 9 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 10 #define SETUP_TOKEN_EDITOR_EL_HEADLINES 11 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 12 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC 13 #define SETUP_TOKEN_EDITOR_EL_BY_GAME 14 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE 15 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 16 #define NUM_EDITOR_SETUP_TOKENS 17 /* editor cascade setup */ #define SETUP_TOKEN_EDITOR_CASCADE_BD 0 #define SETUP_TOKEN_EDITOR_CASCADE_EM 1 #define SETUP_TOKEN_EDITOR_CASCADE_EMC 2 #define SETUP_TOKEN_EDITOR_CASCADE_RND 3 #define SETUP_TOKEN_EDITOR_CASCADE_SB 4 #define SETUP_TOKEN_EDITOR_CASCADE_SP 5 #define SETUP_TOKEN_EDITOR_CASCADE_DC 6 #define SETUP_TOKEN_EDITOR_CASCADE_DX 7 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT 8 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT 9 #define SETUP_TOKEN_EDITOR_CASCADE_CE 10 #define SETUP_TOKEN_EDITOR_CASCADE_GE 11 #define SETUP_TOKEN_EDITOR_CASCADE_REF 12 #define SETUP_TOKEN_EDITOR_CASCADE_USER 13 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 14 #define NUM_EDITOR_CASCADE_SETUP_TOKENS 15 /* shortcut setup */ #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1 3 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2 4 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3 5 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4 6 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL 7 #define SETUP_TOKEN_SHORTCUT_TAPE_EJECT 8 #define SETUP_TOKEN_SHORTCUT_TAPE_STOP 9 #define SETUP_TOKEN_SHORTCUT_TAPE_PAUSE 10 #define SETUP_TOKEN_SHORTCUT_TAPE_RECORD 11 #define SETUP_TOKEN_SHORTCUT_TAPE_PLAY 12 #define SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE 13 #define SETUP_TOKEN_SHORTCUT_SOUND_LOOPS 14 #define SETUP_TOKEN_SHORTCUT_SOUND_MUSIC 15 #define SETUP_TOKEN_SHORTCUT_SNAP_LEFT 16 #define SETUP_TOKEN_SHORTCUT_SNAP_RIGHT 17 #define SETUP_TOKEN_SHORTCUT_SNAP_UP 18 #define SETUP_TOKEN_SHORTCUT_SNAP_DOWN 19 #define NUM_SHORTCUT_SETUP_TOKENS 20 /* player setup */ #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8 #define SETUP_TOKEN_PLAYER_JOY_DROP 9 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11 #define SETUP_TOKEN_PLAYER_KEY_UP 12 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14 #define SETUP_TOKEN_PLAYER_KEY_DROP 15 #define NUM_PLAYER_SETUP_TOKENS 16 /* system setup */ #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER 0 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 1 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 2 #define NUM_SYSTEM_SETUP_TOKENS 3 /* options setup */ #define SETUP_TOKEN_OPTIONS_VERBOSE 0 #define NUM_OPTIONS_SETUP_TOKENS 1 static struct SetupInfo si; static struct SetupEditorInfo sei; static struct SetupEditorCascadeInfo seci; static struct SetupShortcutInfo ssi; static struct SetupInputInfo sii; static struct SetupSystemInfo syi; static struct OptionInfo soi; static struct TokenInfo global_setup_tokens[] = { { TYPE_STRING, &si.player_name, "player_name" }, { TYPE_SWITCH, &si.sound, "sound" }, { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" }, { TYPE_SWITCH, &si.sound_music, "background_music" }, { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" }, { TYPE_SWITCH, &si.toons, "toons" }, { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" }, { TYPE_INTEGER,&si.scroll_delay_value, "scroll_delay_value" }, { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" }, { TYPE_SWITCH, &si.fade_screens, "fade_screens" }, { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording"}, { TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen" }, { TYPE_SWITCH, &si.quick_doors, "quick_doors" }, { TYPE_SWITCH, &si.team_mode, "team_mode" }, { TYPE_SWITCH, &si.handicap, "handicap" }, { TYPE_SWITCH, &si.skip_levels, "skip_levels" }, { TYPE_SWITCH, &si.time_limit, "time_limit" }, { TYPE_SWITCH, &si.fullscreen, "fullscreen" }, { TYPE_STRING, &si.fullscreen_mode, "fullscreen_mode" }, { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" }, { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" }, { TYPE_SWITCH, &si.quick_switch, "quick_player_switch" }, { TYPE_SWITCH, &si.input_on_focus, "input_on_focus" }, { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics" }, { TYPE_INTEGER,&si.game_frame_delay, "game_frame_delay" }, { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements" }, { TYPE_STRING, &si.graphics_set, "graphics_set" }, { TYPE_STRING, &si.sounds_set, "sounds_set" }, { TYPE_STRING, &si.music_set, "music_set" }, { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" }, { TYPE_SWITCH3,&si.override_level_sounds, "override_level_sounds" }, { TYPE_SWITCH3,&si.override_level_music, "override_level_music" }, }; static boolean not_used = FALSE; static struct TokenInfo editor_setup_tokens[] = { #if 1 { TYPE_SWITCH, ¬_used, "editor.el_boulderdash" }, { TYPE_SWITCH, ¬_used, "editor.el_emerald_mine" }, { TYPE_SWITCH, ¬_used, "editor.el_emerald_mine_club" }, { TYPE_SWITCH, ¬_used, "editor.el_more" }, { TYPE_SWITCH, ¬_used, "editor.el_sokoban" }, { TYPE_SWITCH, ¬_used, "editor.el_supaplex" }, { TYPE_SWITCH, ¬_used, "editor.el_diamond_caves" }, { TYPE_SWITCH, ¬_used, "editor.el_dx_boulderdash" }, #else { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" }, { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" }, { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"}, { TYPE_SWITCH, &sei.el_more, "editor.el_more" }, { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" }, { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" }, { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" }, { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" }, #endif { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" }, { TYPE_SWITCH, &sei.el_steel_chars, "editor.el_steel_chars" }, { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" }, #if 1 { TYPE_SWITCH, ¬_used, "editor.el_headlines" }, #else { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" }, #endif { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" }, { TYPE_SWITCH, &sei.el_dynamic, "editor.el_dynamic" }, { TYPE_SWITCH, &sei.el_by_game, "editor.el_by_game" }, { TYPE_SWITCH, &sei.el_by_type, "editor.el_by_type" }, { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token" }, }; static struct TokenInfo editor_cascade_setup_tokens[] = { { TYPE_SWITCH, &seci.el_bd, "editor.cascade.el_bd" }, { TYPE_SWITCH, &seci.el_em, "editor.cascade.el_em" }, { TYPE_SWITCH, &seci.el_emc, "editor.cascade.el_emc" }, { TYPE_SWITCH, &seci.el_rnd, "editor.cascade.el_rnd" }, { TYPE_SWITCH, &seci.el_sb, "editor.cascade.el_sb" }, { TYPE_SWITCH, &seci.el_sp, "editor.cascade.el_sp" }, { TYPE_SWITCH, &seci.el_dc, "editor.cascade.el_dc" }, { TYPE_SWITCH, &seci.el_dx, "editor.cascade.el_dx" }, { TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" }, { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" }, { TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" }, { TYPE_SWITCH, &seci.el_ge, "editor.cascade.el_ge" }, { TYPE_SWITCH, &seci.el_ref, "editor.cascade.el_ref" }, { TYPE_SWITCH, &seci.el_user, "editor.cascade.el_user" }, { TYPE_SWITCH, &seci.el_dynamic, "editor.cascade.el_dynamic" }, }; static struct TokenInfo shortcut_setup_tokens[] = { { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" }, { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" }, { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }, { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1" }, { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2" }, { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3" }, { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4" }, { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all" }, { TYPE_KEY_X11, &ssi.tape_eject, "shortcut.tape_eject" }, { TYPE_KEY_X11, &ssi.tape_stop, "shortcut.tape_stop" }, { TYPE_KEY_X11, &ssi.tape_pause, "shortcut.tape_pause" }, { TYPE_KEY_X11, &ssi.tape_record, "shortcut.tape_record" }, { TYPE_KEY_X11, &ssi.tape_play, "shortcut.tape_play" }, { TYPE_KEY_X11, &ssi.sound_simple, "shortcut.sound_simple" }, { TYPE_KEY_X11, &ssi.sound_loops, "shortcut.sound_loops" }, { TYPE_KEY_X11, &ssi.sound_music, "shortcut.sound_music" }, { TYPE_KEY_X11, &ssi.snap_left, "shortcut.snap_left" }, { TYPE_KEY_X11, &ssi.snap_right, "shortcut.snap_right" }, { TYPE_KEY_X11, &ssi.snap_up, "shortcut.snap_up" }, { TYPE_KEY_X11, &ssi.snap_down, "shortcut.snap_down" }, }; static struct TokenInfo player_setup_tokens[] = { { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" }, { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" }, { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" }, { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" }, { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" }, { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" }, { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" }, { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" }, { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" }, { TYPE_INTEGER, &sii.joy.drop, ".joy.place_bomb" }, { TYPE_KEY_X11, &sii.key.left, ".key.move_left" }, { TYPE_KEY_X11, &sii.key.right, ".key.move_right" }, { TYPE_KEY_X11, &sii.key.up, ".key.move_up" }, { TYPE_KEY_X11, &sii.key.down, ".key.move_down" }, { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" }, { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" }, }; static struct TokenInfo system_setup_tokens[] = { { TYPE_STRING, &syi.sdl_videodriver, "system.sdl_videodriver" }, { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" }, { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }, }; static struct TokenInfo options_setup_tokens[] = { { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }, }; static char *get_corrected_login_name(char *login_name) { /* needed because player name must be a fixed length string */ char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1); strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN); login_name_new[MAX_PLAYER_NAME_LEN] = '\0'; if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */ if (strchr(login_name_new, ' ')) *strchr(login_name_new, ' ') = '\0'; return login_name_new; } static void setSetupInfoToDefaults(struct SetupInfo *si) { int i; si->player_name = get_corrected_login_name(getLoginName()); si->sound = TRUE; si->sound_loops = TRUE; si->sound_music = TRUE; si->sound_simple = TRUE; si->toons = TRUE; si->scroll_delay = TRUE; si->scroll_delay_value = STD_SCROLL_DELAY; si->soft_scrolling = TRUE; si->fade_screens = TRUE; si->autorecord = TRUE; si->show_titlescreen = TRUE; si->quick_doors = FALSE; si->team_mode = FALSE; si->handicap = TRUE; si->skip_levels = TRUE; si->time_limit = TRUE; si->fullscreen = FALSE; si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE); si->ask_on_escape = TRUE; si->ask_on_escape_editor = TRUE; si->quick_switch = FALSE; si->input_on_focus = FALSE; si->prefer_aga_graphics = TRUE; si->game_frame_delay = GAME_FRAME_DELAY; si->sp_show_border_elements = FALSE; si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR); si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR); si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR); si->override_level_graphics = FALSE; si->override_level_sounds = FALSE; si->override_level_music = FALSE; si->editor.el_boulderdash = TRUE; si->editor.el_emerald_mine = TRUE; si->editor.el_emerald_mine_club = TRUE; si->editor.el_more = TRUE; si->editor.el_sokoban = TRUE; si->editor.el_supaplex = TRUE; si->editor.el_diamond_caves = TRUE; si->editor.el_dx_boulderdash = TRUE; si->editor.el_chars = TRUE; si->editor.el_steel_chars = TRUE; si->editor.el_custom = TRUE; si->editor.el_headlines = TRUE; si->editor.el_user_defined = FALSE; si->editor.el_dynamic = TRUE; si->editor.show_element_token = FALSE; si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME; si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME; si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE; si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1; si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2; si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3; si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4; si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL; si->shortcut.tape_eject = DEFAULT_KEY_TAPE_EJECT; si->shortcut.tape_stop = DEFAULT_KEY_TAPE_STOP; si->shortcut.tape_pause = DEFAULT_KEY_TAPE_PAUSE; si->shortcut.tape_record = DEFAULT_KEY_TAPE_RECORD; si->shortcut.tape_play = DEFAULT_KEY_TAPE_PLAY; si->shortcut.sound_simple = DEFAULT_KEY_SOUND_SIMPLE; si->shortcut.sound_loops = DEFAULT_KEY_SOUND_LOOPS; si->shortcut.sound_music = DEFAULT_KEY_SOUND_MUSIC; si->shortcut.snap_left = DEFAULT_KEY_SNAP_LEFT; si->shortcut.snap_right = DEFAULT_KEY_SNAP_RIGHT; si->shortcut.snap_up = DEFAULT_KEY_SNAP_UP; si->shortcut.snap_down = DEFAULT_KEY_SNAP_DOWN; for (i = 0; i < MAX_PLAYERS; i++) { si->input[i].use_joystick = FALSE; si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i)); si->input[i].joy.xleft = JOYSTICK_XLEFT; si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE; si->input[i].joy.xright = JOYSTICK_XRIGHT; si->input[i].joy.yupper = JOYSTICK_YUPPER; si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE; si->input[i].joy.ylower = JOYSTICK_YLOWER; si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0); si->input[i].joy.drop = (i == 0 ? JOY_BUTTON_2 : 0); si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED); si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED); si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED); si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED); si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED); si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED); } si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT); si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT); si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE; si->options.verbose = FALSE; #if defined(CREATE_SPECIAL_EDITION_RND_JUE) si->toons = FALSE; si->handicap = FALSE; si->fullscreen = TRUE; si->override_level_graphics = AUTO; si->override_level_sounds = AUTO; si->override_level_music = AUTO; #endif } static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) { si->editor_cascade.el_bd = TRUE; si->editor_cascade.el_em = TRUE; si->editor_cascade.el_emc = TRUE; si->editor_cascade.el_rnd = TRUE; si->editor_cascade.el_sb = TRUE; si->editor_cascade.el_sp = TRUE; si->editor_cascade.el_dc = TRUE; si->editor_cascade.el_dx = TRUE; si->editor_cascade.el_chars = FALSE; si->editor_cascade.el_steel_chars = FALSE; si->editor_cascade.el_ce = FALSE; si->editor_cascade.el_ge = FALSE; si->editor_cascade.el_ref = FALSE; si->editor_cascade.el_user = FALSE; si->editor_cascade.el_dynamic = FALSE; } static void decodeSetupFileHash(SetupFileHash *setup_file_hash) { int i, pnr; if (!setup_file_hash) return; /* global setup */ si = setup; for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++) setSetupInfo(global_setup_tokens, i, getHashEntry(setup_file_hash, global_setup_tokens[i].text)); setup = si; /* editor setup */ sei = setup.editor; for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++) setSetupInfo(editor_setup_tokens, i, getHashEntry(setup_file_hash,editor_setup_tokens[i].text)); setup.editor = sei; /* shortcut setup */ ssi = setup.shortcut; for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++) setSetupInfo(shortcut_setup_tokens, i, getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text)); setup.shortcut = ssi; /* player setup */ for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { char prefix[30]; sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1); sii = setup.input[pnr]; for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++) { char full_token[100]; sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text); setSetupInfo(player_setup_tokens, i, getHashEntry(setup_file_hash, full_token)); } setup.input[pnr] = sii; } /* system setup */ syi = setup.system; for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++) setSetupInfo(system_setup_tokens, i, getHashEntry(setup_file_hash, system_setup_tokens[i].text)); setup.system = syi; /* options setup */ soi = setup.options; for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++) setSetupInfo(options_setup_tokens, i, getHashEntry(setup_file_hash, options_setup_tokens[i].text)); setup.options = soi; } static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash) { int i; if (!setup_file_hash) return; /* editor cascade setup */ seci = setup.editor_cascade; for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++) setSetupInfo(editor_cascade_setup_tokens, i, getHashEntry(setup_file_hash, editor_cascade_setup_tokens[i].text)); setup.editor_cascade = seci; } void LoadSetup() { char *filename = getSetupFilename(); SetupFileHash *setup_file_hash = NULL; /* always start with reliable default values */ setSetupInfoToDefaults(&setup); setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash) { char *player_name_new; checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP")); decodeSetupFileHash(setup_file_hash); freeSetupFileHash(setup_file_hash); /* needed to work around problems with fixed length strings */ player_name_new = get_corrected_login_name(setup.player_name); free(setup.player_name); setup.player_name = player_name_new; /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */ if (setup.scroll_delay == FALSE) { setup.scroll_delay_value = MIN_SCROLL_DELAY; setup.scroll_delay = TRUE; /* now always "on" */ } /* make sure that scroll delay value stays inside valid range */ setup.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY); } else Error(ERR_WARN, "using default setup values"); } void LoadSetup_EditorCascade() { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); SetupFileHash *setup_file_hash = NULL; /* always start with reliable default values */ setSetupInfoToDefaults_EditorCascade(&setup); setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash) { checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP")); decodeSetupFileHash_EditorCascade(setup_file_hash); freeSetupFileHash(setup_file_hash); } free(filename); } void SaveSetup() { char *filename = getSetupFilename(); FILE *file; int i, pnr; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); return; } fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("SETUP"))); fprintf(file, "\n"); /* global setup */ si = setup; for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++) { /* just to make things nicer :) */ if (i == SETUP_TOKEN_PLAYER_NAME + 1 || i == SETUP_TOKEN_GRAPHICS_SET) fprintf(file, "\n"); fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i)); } /* editor setup */ sei = setup.editor; fprintf(file, "\n"); for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i)); /* shortcut setup */ ssi = setup.shortcut; fprintf(file, "\n"); for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i)); /* player setup */ for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { char prefix[30]; sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1); fprintf(file, "\n"); sii = setup.input[pnr]; for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i)); } /* system setup */ syi = setup.system; fprintf(file, "\n"); for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i)); /* options setup */ soi = setup.options; fprintf(file, "\n"); for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); } void SaveSetup_EditorCascade() { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); FILE *file; int i; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename); free(filename); return; } fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("SETUP"))); fprintf(file, "\n"); seci = setup.editor_cascade; fprintf(file, "\n"); for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } void LoadCustomElementDescriptions() { char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); SetupFileHash *setup_file_hash; int i; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { if (element_info[i].custom_description != NULL) { free(element_info[i].custom_description); element_info[i].custom_description = NULL; } } if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { char *token = getStringCat2(element_info[i].token_name, ".name"); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) element_info[i].custom_description = getStringCopy(value); free(token); } freeSetupFileHash(setup_file_hash); } static int getElementFromToken(char *token) { #if 1 char *value = getHashEntry(element_token_hash, token); if (value != NULL) return atoi(value); #else int i; /* !!! OPTIMIZE THIS BY USING HASH !!! */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (strEqual(token, element_info[i].token_name)) return i; #endif Error(ERR_WARN, "unknown element token '%s'", token); return EL_UNDEFINED; } static int get_token_parameter_value(char *token, char *value_raw) { char *suffix; if (token == NULL || value_raw == NULL) return ARG_UNDEFINED_VALUE; suffix = strrchr(token, '.'); if (suffix == NULL) suffix = token; #if 1 if (strEqual(suffix, ".element")) return getElementFromToken(value_raw); #endif #if 0 if (strncmp(suffix, ".font", 5) == 0) { int i; /* !!! OPTIMIZE THIS BY USING HASH !!! */ for (i = 0; i < NUM_FONTS; i++) if (strEqual(value_raw, font_info[i].token_name)) return i; /* if font not found, use reliable default value */ return FONT_INITIAL_1; } #endif /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */ return get_parameter_value(value_raw, suffix, TYPE_INTEGER); } void InitMenuDesignSettings_Static() { #if 0 static SetupFileHash *image_config_hash = NULL; #endif int i; #if 0 if (image_config_hash == NULL) { image_config_hash = newSetupFileHash(); for (i = 0; image_config[i].token != NULL; i++) setHashEntry(image_config_hash, image_config[i].token, image_config[i].value); } #endif #if 1 /* always start with reliable default values from static default config */ for (i = 0; image_config_vars[i].token != NULL; i++) { char *value = getHashEntry(image_config_hash, image_config_vars[i].token); if (value != NULL) *image_config_vars[i].value = get_token_parameter_value(image_config_vars[i].token, value); } #else int j; /* always start with reliable default values from static default config */ for (i = 0; image_config_vars[i].token != NULL; i++) for (j = 0; image_config[j].token != NULL; j++) if (strEqual(image_config_vars[i].token, image_config[j].token)) *image_config_vars[i].value = get_token_parameter_value(image_config_vars[i].token, image_config[j].value); #endif } static void InitMenuDesignSettings_SpecialPreProcessing() { int i; /* the following initializes hierarchical values from static configuration */ /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */ titlemessage_initial_default.fade_mode = title_initial_default.fade_mode; titlemessage_initial_default.fade_delay = title_initial_default.fade_delay; titlemessage_initial_default.post_delay = title_initial_default.post_delay; titlemessage_initial_default.auto_delay = title_initial_default.auto_delay; titlemessage_default.fade_mode = title_default.fade_mode; titlemessage_default.fade_delay = title_default.fade_delay; titlemessage_default.post_delay = title_default.post_delay; titlemessage_default.auto_delay = title_default.auto_delay; /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */ for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++) { titlemessage_initial[i] = titlemessage_initial_default; titlemessage[i] = titlemessage_default; } /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT]; menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT]; } /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { viewport.playfield[i] = viewport.playfield[GFX_SPECIAL_ARG_DEFAULT]; viewport.door_1[i] = viewport.door_1[GFX_SPECIAL_ARG_DEFAULT]; if (i != GFX_SPECIAL_ARG_EDITOR) /* editor value already initialized */ viewport.door_2[i] = viewport.door_2[GFX_SPECIAL_ARG_DEFAULT]; } } static void InitMenuDesignSettings_SpecialPostProcessing() { /* special case: initialize later added SETUP list size from LEVELS value */ if (menu.list_size[GAME_MODE_SETUP] == -1) menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS]; } static void LoadMenuDesignSettingsFromFilename(char *filename) { static struct TitleMessageInfo tmi; static struct TokenInfo titlemessage_tokens[] = { { TYPE_INTEGER, &tmi.x, ".x" }, { TYPE_INTEGER, &tmi.y, ".y" }, { TYPE_INTEGER, &tmi.width, ".width" }, { TYPE_INTEGER, &tmi.height, ".height" }, { TYPE_INTEGER, &tmi.chars, ".chars" }, { TYPE_INTEGER, &tmi.lines, ".lines" }, { TYPE_INTEGER, &tmi.align, ".align" }, { TYPE_INTEGER, &tmi.valign, ".valign" }, { TYPE_INTEGER, &tmi.font, ".font" }, { TYPE_BOOLEAN, &tmi.autowrap, ".autowrap" }, { TYPE_BOOLEAN, &tmi.centered, ".centered" }, { TYPE_BOOLEAN, &tmi.parse_comments, ".parse_comments" }, { TYPE_INTEGER, &tmi.sort_priority, ".sort_priority" }, { TYPE_INTEGER, &tmi.fade_mode, ".fade_mode" }, { TYPE_INTEGER, &tmi.fade_delay, ".fade_delay" }, { TYPE_INTEGER, &tmi.post_delay, ".post_delay" }, { TYPE_INTEGER, &tmi.auto_delay, ".auto_delay" }, { -1, NULL, NULL } }; static struct { struct TitleMessageInfo *array; char *text; } titlemessage_arrays[] = { { titlemessage_initial, "[titlemessage_initial]" }, { titlemessage, "[titlemessage]" }, { NULL, NULL } }; SetupFileHash *setup_file_hash; int i, j, k; #if 0 printf("LoadMenuDesignSettings from file '%s' ...\n", filename); #endif if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; /* the following initializes hierarchical values from dynamic configuration */ /* special case: initialize with default values that may be overwritten */ /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset"); char *value_3 = getHashEntry(setup_file_hash, "menu.list_size"); if (value_1 != NULL) menu.draw_xoffset[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset[i] = get_integer_from_string(value_2); if (value_3 != NULL) menu.list_size[i] = get_integer_from_string(value_3); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */ for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO"); if (value_1 != NULL) menu.draw_xoffset_info[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset_info[i] = get_integer_from_string(value_2); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */ for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP"); if (value_1 != NULL) menu.draw_xoffset_setup[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset_setup[i] = get_integer_from_string(value_2); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *token_1 = "menu.enter_screen.fade_mode"; char *token_2 = "menu.enter_screen.fade_delay"; char *token_3 = "menu.enter_screen.post_delay"; char *token_4 = "menu.leave_screen.fade_mode"; char *token_5 = "menu.leave_screen.fade_delay"; char *token_6 = "menu.leave_screen.post_delay"; char *value_1 = getHashEntry(setup_file_hash, token_1); char *value_2 = getHashEntry(setup_file_hash, token_2); char *value_3 = getHashEntry(setup_file_hash, token_3); char *value_4 = getHashEntry(setup_file_hash, token_4); char *value_5 = getHashEntry(setup_file_hash, token_5); char *value_6 = getHashEntry(setup_file_hash, token_6); if (value_1 != NULL) menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1, value_1); if (value_2 != NULL) menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2, value_2); if (value_3 != NULL) menu.enter_screen[i].post_delay = get_token_parameter_value(token_3, value_3); if (value_4 != NULL) menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4, value_4); if (value_5 != NULL) menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5, value_5); if (value_6 != NULL) menu.leave_screen[i].post_delay = get_token_parameter_value(token_6, value_6); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *token_1 = "viewport.playfield.x"; char *token_2 = "viewport.playfield.y"; char *token_3 = "viewport.playfield.width"; char *token_4 = "viewport.playfield.height"; char *token_5 = "viewport.playfield.border_size"; char *token_6 = "viewport.door_1.x"; char *token_7 = "viewport.door_1.y"; char *token_8 = "viewport.door_2.x"; char *token_9 = "viewport.door_2.y"; char *value_1 = getHashEntry(setup_file_hash, token_1); char *value_2 = getHashEntry(setup_file_hash, token_2); char *value_3 = getHashEntry(setup_file_hash, token_3); char *value_4 = getHashEntry(setup_file_hash, token_4); char *value_5 = getHashEntry(setup_file_hash, token_5); char *value_6 = getHashEntry(setup_file_hash, token_6); char *value_7 = getHashEntry(setup_file_hash, token_7); char *value_8 = getHashEntry(setup_file_hash, token_8); char *value_9 = getHashEntry(setup_file_hash, token_9); if (value_1 != NULL) viewport.playfield[i].x = get_token_parameter_value(token_1, value_1); if (value_2 != NULL) viewport.playfield[i].y = get_token_parameter_value(token_2, value_2); if (value_3 != NULL) viewport.playfield[i].width = get_token_parameter_value(token_3, value_3); if (value_4 != NULL) viewport.playfield[i].height = get_token_parameter_value(token_4,value_4); if (value_5 != NULL) viewport.playfield[i].border_size = get_token_parameter_value(token_5, value_5); if (value_6 != NULL) viewport.door_1[i].x = get_token_parameter_value(token_6, value_6); if (value_7 != NULL) viewport.door_1[i].y = get_token_parameter_value(token_7, value_7); if (value_8 != NULL) viewport.door_2[i].x = get_token_parameter_value(token_8, value_8); if (value_9 != NULL) viewport.door_2[i].y = get_token_parameter_value(token_9, value_9); } /* special case: initialize with default values that may be overwritten */ /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */ for (i = 0; titlemessage_arrays[i].array != NULL; i++) { struct TitleMessageInfo *array = titlemessage_arrays[i].array; char *base_token = titlemessage_arrays[i].text; for (j = 0; titlemessage_tokens[j].type != -1; j++) { char *token = getStringCat2(base_token, titlemessage_tokens[j].text); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) { int parameter_value = get_token_parameter_value(token, value); for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++) { tmi = array[k]; if (titlemessage_tokens[j].type == TYPE_INTEGER) *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value; else *(int *)titlemessage_tokens[j].value = (int)parameter_value; array[k] = tmi; } } free(token); } } /* read (and overwrite with) values that may be specified in config file */ for (i = 0; image_config_vars[i].token != NULL; i++) { char *value = getHashEntry(setup_file_hash, image_config_vars[i].token); /* (ignore definitions set to "[DEFAULT]" which are already initialized) */ if (value != NULL && !strEqual(value, ARG_DEFAULT)) *image_config_vars[i].value = get_token_parameter_value(image_config_vars[i].token, value); } freeSetupFileHash(setup_file_hash); } void LoadMenuDesignSettings() { char *filename_base = UNDEFINED_FILENAME, *filename_local; InitMenuDesignSettings_Static(); InitMenuDesignSettings_SpecialPreProcessing(); #if 1 if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS)) #else if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS)) #endif { /* first look for special settings configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS); if (fileExists(filename_base)) LoadMenuDesignSettingsFromFilename(filename_base); } filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); if (filename_local != NULL && !strEqual(filename_base, filename_local)) LoadMenuDesignSettingsFromFilename(filename_local); InitMenuDesignSettings_SpecialPostProcessing(); } void LoadUserDefinedEditorElementList(int **elements, int *num_elements) { char *filename = getEditorSetupFilename(); SetupFileList *setup_file_list, *list; SetupFileHash *element_hash; int num_unknown_tokens = 0; int i; if ((setup_file_list = loadSetupFileList(filename)) == NULL) return; element_hash = newSetupFileHash(); for (i = 0; i < NUM_FILE_ELEMENTS; i++) setHashEntry(element_hash, element_info[i].token_name, i_to_a(i)); /* determined size may be larger than needed (due to unknown elements) */ *num_elements = 0; for (list = setup_file_list; list != NULL; list = list->next) (*num_elements)++; /* add space for up to 3 more elements for padding that may be needed */ *num_elements += 3; /* free memory for old list of elements, if needed */ checked_free(*elements); /* allocate memory for new list of elements */ *elements = checked_malloc(*num_elements * sizeof(int)); *num_elements = 0; for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(element_hash, list->token); if (value == NULL) /* try to find obsolete token mapping */ { char *mapped_token = get_mapped_token(list->token); if (mapped_token != NULL) { value = getHashEntry(element_hash, mapped_token); free(mapped_token); } } if (value != NULL) { (*elements)[(*num_elements)++] = atoi(value); } else { if (num_unknown_tokens == 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); num_unknown_tokens++; } Error(ERR_INFO, "- token: '%s'", list->token); } } if (num_unknown_tokens > 0) Error(ERR_INFO_LINE, "-"); while (*num_elements % 4) /* pad with empty elements, if needed */ (*elements)[(*num_elements)++] = EL_EMPTY; freeSetupFileList(setup_file_list); freeSetupFileHash(element_hash); #if 0 for (i = 0; i < *num_elements; i++) printf("editor: element '%s' [%d]\n", element_info[(*elements)[i]].token_name, (*elements)[i]); #endif } static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music, boolean is_sound) { SetupFileHash *setup_file_hash = NULL; struct MusicFileInfo tmp_music_file_info, *new_music_file_info; char *filename_music, *filename_prefix, *filename_info; struct { char *token; char **value_ptr; } token_to_value_ptr[] = { { "title_header", &tmp_music_file_info.title_header }, { "artist_header", &tmp_music_file_info.artist_header }, { "album_header", &tmp_music_file_info.album_header }, { "year_header", &tmp_music_file_info.year_header }, { "title", &tmp_music_file_info.title }, { "artist", &tmp_music_file_info.artist }, { "album", &tmp_music_file_info.album }, { "year", &tmp_music_file_info.year }, { NULL, NULL }, }; int i; filename_music = (is_sound ? getCustomSoundFilename(basename) : getCustomMusicFilename(basename)); if (filename_music == NULL) return NULL; /* ---------- try to replace file extension ---------- */ filename_prefix = getStringCopy(filename_music); if (strrchr(filename_prefix, '.') != NULL) *strrchr(filename_prefix, '.') = '\0'; filename_info = getStringCat2(filename_prefix, ".txt"); #if 0 printf("trying to load file '%s'...\n", filename_info); #endif if (fileExists(filename_info)) setup_file_hash = loadSetupFileHash(filename_info); free(filename_prefix); free(filename_info); if (setup_file_hash == NULL) { /* ---------- try to add file extension ---------- */ filename_prefix = getStringCopy(filename_music); filename_info = getStringCat2(filename_prefix, ".txt"); #if 0 printf("trying to load file '%s'...\n", filename_info); #endif if (fileExists(filename_info)) setup_file_hash = loadSetupFileHash(filename_info); free(filename_prefix); free(filename_info); } if (setup_file_hash == NULL) return NULL; /* ---------- music file info found ---------- */ clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo)); for (i = 0; token_to_value_ptr[i].token != NULL; i++) { char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token); *token_to_value_ptr[i].value_ptr = getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME); } tmp_music_file_info.basename = getStringCopy(basename); tmp_music_file_info.music = music; tmp_music_file_info.is_sound = is_sound; new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo)); *new_music_file_info = tmp_music_file_info; return new_music_file_info; } static struct MusicFileInfo *get_music_file_info(char *basename, int music) { return get_music_file_info_ext(basename, music, FALSE); } static struct MusicFileInfo *get_sound_file_info(char *basename, int sound) { return get_music_file_info_ext(basename, sound, TRUE); } static boolean music_info_listed_ext(struct MusicFileInfo *list, char *basename, boolean is_sound) { for (; list != NULL; list = list->next) if (list->is_sound == is_sound && strEqual(list->basename, basename)) return TRUE; return FALSE; } static boolean music_info_listed(struct MusicFileInfo *list, char *basename) { return music_info_listed_ext(list, basename, FALSE); } static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) { return music_info_listed_ext(list, basename, TRUE); } void LoadMusicInfo() { char *music_directory = getCustomMusicDirectory(); int num_music = getMusicListSize(); int num_music_noconf = 0; int num_sounds = getSoundListSize(); DIR *dir; struct dirent *dir_entry; struct FileInfo *music, *sound; struct MusicFileInfo *next, **new; int i; while (music_file_info != NULL) { next = music_file_info->next; checked_free(music_file_info->basename); checked_free(music_file_info->title_header); checked_free(music_file_info->artist_header); checked_free(music_file_info->album_header); checked_free(music_file_info->year_header); checked_free(music_file_info->title); checked_free(music_file_info->artist); checked_free(music_file_info->album); checked_free(music_file_info->year); free(music_file_info); music_file_info = next; } new = &music_file_info; for (i = 0; i < num_music; i++) { music = getMusicListEntry(i); if (music->filename == NULL) continue; if (strEqual(music->filename, UNDEFINED_FILENAME)) continue; /* a configured file may be not recognized as music */ if (!FileIsMusic(music->filename)) continue; #if 0 printf("::: -> '%s' (configured)\n", music->filename); #endif if (!music_info_listed(music_file_info, music->filename)) { *new = get_music_file_info(music->filename, i); #if 0 if (*new != NULL) printf(":1: adding '%s' ['%s'] ...\n", (*new)->title, music->filename); #endif if (*new != NULL) new = &(*new)->next; } } if ((dir = opendir(music_directory)) == NULL) { Error(ERR_WARN, "cannot read music directory '%s'", music_directory); return; } while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { char *basename = dir_entry->d_name; boolean music_already_used = FALSE; int i; /* skip all music files that are configured in music config file */ for (i = 0; i < num_music; i++) { music = getMusicListEntry(i); if (music->filename == NULL) continue; if (strEqual(basename, music->filename)) { music_already_used = TRUE; break; } } if (music_already_used) continue; if (!FileIsMusic(basename)) continue; #if 0 printf("::: -> '%s' (found in directory)\n", basename); #endif if (!music_info_listed(music_file_info, basename)) { *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf)); #if 0 if (*new != NULL) printf(":2: adding '%s' ['%s'] ...\n", (*new)->title, basename); #endif if (*new != NULL) new = &(*new)->next; } num_music_noconf++; } closedir(dir); for (i = 0; i < num_sounds; i++) { sound = getSoundListEntry(i); if (sound->filename == NULL) continue; if (strEqual(sound->filename, UNDEFINED_FILENAME)) continue; /* a configured file may be not recognized as sound */ if (!FileIsSound(sound->filename)) continue; #if 0 printf("::: -> '%s' (configured)\n", sound->filename); #endif if (!sound_info_listed(music_file_info, sound->filename)) { *new = get_sound_file_info(sound->filename, i); if (*new != NULL) new = &(*new)->next; } } #if 0 for (next = music_file_info; next != NULL; next = next->next) printf("::: title == '%s'\n", next->title); #endif } void add_helpanim_entry(int element, int action, int direction, int delay, int *num_list_entries) { struct HelpAnimInfo *new_list_entry; (*num_list_entries)++; helpanim_info = checked_realloc(helpanim_info, *num_list_entries * sizeof(struct HelpAnimInfo)); new_list_entry = &helpanim_info[*num_list_entries - 1]; new_list_entry->element = element; new_list_entry->action = action; new_list_entry->direction = direction; new_list_entry->delay = delay; } void print_unknown_token(char *filename, char *token, int token_nr) { if (token_nr == 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); } Error(ERR_INFO, "- token: '%s'", token); } void print_unknown_token_end(int token_nr) { if (token_nr > 0) Error(ERR_INFO_LINE, "-"); } void LoadHelpAnimInfo() { char *filename = getHelpAnimFilename(); SetupFileList *setup_file_list = NULL, *list; SetupFileHash *element_hash, *action_hash, *direction_hash; int num_list_entries = 0; int num_unknown_tokens = 0; int i; if (fileExists(filename)) setup_file_list = loadSetupFileList(filename); if (setup_file_list == NULL) { /* use reliable default values from static configuration */ SetupFileList *insert_ptr; insert_ptr = setup_file_list = newSetupFileList(helpanim_config[0].token, helpanim_config[0].value); for (i = 1; helpanim_config[i].token; i++) insert_ptr = addListEntry(insert_ptr, helpanim_config[i].token, helpanim_config[i].value); } element_hash = newSetupFileHash(); action_hash = newSetupFileHash(); direction_hash = newSetupFileHash(); for (i = 0; i < MAX_NUM_ELEMENTS; i++) setHashEntry(element_hash, element_info[i].token_name, i_to_a(i)); for (i = 0; i < NUM_ACTIONS; i++) setHashEntry(action_hash, element_action_info[i].suffix, i_to_a(element_action_info[i].value)); /* do not store direction index (bit) here, but direction value! */ for (i = 0; i < NUM_DIRECTIONS_FULL; i++) setHashEntry(direction_hash, element_direction_info[i].suffix, i_to_a(1 << element_direction_info[i].value)); for (list = setup_file_list; list != NULL; list = list->next) { char *element_token, *action_token, *direction_token; char *element_value, *action_value, *direction_value; int delay = atoi(list->value); if (strEqual(list->token, "end")) { add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); continue; } /* first try to break element into element/action/direction parts; if this does not work, also accept combined "element[.act][.dir]" elements (like "dynamite.active"), which are unique elements */ if (strchr(list->token, '.') == NULL) /* token contains no '.' */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else { /* no further suffixes found -- this is not an element */ print_unknown_token(filename, list->token, num_unknown_tokens++); } continue; } /* token has format "." */ action_token = strchr(list->token, '.'); /* suffix may be action ... */ direction_token = action_token; /* ... or direction */ element_token = getStringCopy(list->token); *strchr(element_token, '.') = '\0'; element_value = getHashEntry(element_hash, element_token); if (element_value == NULL) /* this is no element */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); continue; } action_value = getHashEntry(action_hash, action_token); if (action_value != NULL) /* action found */ { add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay, &num_list_entries); free(element_token); continue; } direction_value = getHashEntry(direction_hash, direction_token); if (direction_value != NULL) /* direction found */ { add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay, &num_list_entries); free(element_token); continue; } if (strchr(action_token + 1, '.') == NULL) { /* no further suffixes found -- this is not an action nor direction */ element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); continue; } /* token has format ".." */ direction_token = strchr(action_token + 1, '.'); action_token = getStringCopy(action_token); *strchr(action_token + 1, '.') = '\0'; action_value = getHashEntry(action_hash, action_token); if (action_value == NULL) /* this is no action */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); free(action_token); continue; } direction_value = getHashEntry(direction_hash, direction_token); if (direction_value != NULL) /* direction found */ { add_helpanim_entry(atoi(element_value), atoi(action_value), atoi(direction_value), delay, &num_list_entries); free(element_token); free(action_token); continue; } /* this is no direction */ element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); free(action_token); } print_unknown_token_end(num_unknown_tokens); add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries); freeSetupFileList(setup_file_list); freeSetupFileHash(element_hash); freeSetupFileHash(action_hash); freeSetupFileHash(direction_hash); #if 0 for (i = 0; i < num_list_entries; i++) printf("::: '%s': %d, %d, %d => %d\n", EL_NAME(helpanim_info[i].element), helpanim_info[i].element, helpanim_info[i].action, helpanim_info[i].direction, helpanim_info[i].delay); #endif } void LoadHelpTextInfo() { char *filename = getHelpTextFilename(); int i; if (helptext_info != NULL) { freeSetupFileHash(helptext_info); helptext_info = NULL; } if (fileExists(filename)) helptext_info = loadSetupFileHash(filename); if (helptext_info == NULL) { /* use reliable default values from static configuration */ helptext_info = newSetupFileHash(); for (i = 0; helptext_config[i].token; i++) setHashEntry(helptext_info, helptext_config[i].token, helptext_config[i].value); } #if 0 BEGIN_HASH_ITERATION(helptext_info, itr) { printf("::: '%s' => '%s'\n", HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(hash, itr) #endif } /* ------------------------------------------------------------------------- */ /* convert levels */ /* ------------------------------------------------------------------------- */ #define MAX_NUM_CONVERT_LEVELS 1000 void ConvertLevels() { static LevelDirTree *convert_leveldir = NULL; static int convert_level_nr = -1; static int num_levels_handled = 0; static int num_levels_converted = 0; static boolean levels_failed[MAX_NUM_CONVERT_LEVELS]; int i; convert_leveldir = getTreeInfoFromIdentifier(leveldir_first, global.convert_leveldir); if (convert_leveldir == NULL) Error(ERR_EXIT, "no such level identifier: '%s'", global.convert_leveldir); leveldir_current = convert_leveldir; if (global.convert_level_nr != -1) { convert_leveldir->first_level = global.convert_level_nr; convert_leveldir->last_level = global.convert_level_nr; } convert_level_nr = convert_leveldir->first_level; printf_line("=", 79); printf("Converting levels\n"); printf_line("-", 79); printf("Level series identifier: '%s'\n", convert_leveldir->identifier); printf("Level series name: '%s'\n", convert_leveldir->name); printf("Level series author: '%s'\n", convert_leveldir->author); printf("Number of levels: %d\n", convert_leveldir->levels); printf_line("=", 79); printf("\n"); for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++) levels_failed[i] = FALSE; while (convert_level_nr <= convert_leveldir->last_level) { char *level_filename; boolean new_level; level_nr = convert_level_nr++; printf("Level %03d: ", level_nr); LoadLevel(level_nr); if (level.no_valid_file) { printf("(no level)\n"); continue; } printf("converting level ... "); level_filename = getDefaultLevelFilename(level_nr); new_level = !fileExists(level_filename); if (new_level) { SaveLevel(level_nr); num_levels_converted++; printf("converted.\n"); } else { if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS) levels_failed[level_nr] = TRUE; printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n"); } num_levels_handled++; } printf("\n"); printf_line("=", 79); printf("Number of levels handled: %d\n", num_levels_handled); printf("Number of levels converted: %d (%d%%)\n", num_levels_converted, (num_levels_handled ? num_levels_converted * 100 / num_levels_handled : 0)); printf_line("-", 79); printf("Summary (for automatic parsing by scripts):\n"); printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)", convert_leveldir->identifier, num_levels_converted, num_levels_handled, (num_levels_handled ? num_levels_converted * 100 / num_levels_handled : 0)); if (num_levels_handled != num_levels_converted) { printf(", FAILED:"); for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++) if (levels_failed[i]) printf(" %03d", i); } printf("\n"); printf_line("=", 79); CloseAllAndExit(0); } /* ------------------------------------------------------------------------- */ /* create and save images for use in level sketches (raw BMP format) */ /* ------------------------------------------------------------------------- */ void CreateLevelSketchImages() { #if defined(TARGET_SDL) Bitmap *bitmap1; Bitmap *bitmap2; int i; InitElementPropertiesGfxElement(); bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH); bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH); for (i = 0; i < NUM_FILE_ELEMENTS; i++) { Bitmap *src_bitmap; int src_x, src_y; int element = getMappedElement(i); int graphic = el2edimg(element); char basename1[16]; char basename2[16]; char *filename1; char *filename2; sprintf(basename1, "%03d.bmp", i); sprintf(basename2, "%03ds.bmp", i); filename1 = getPath2(global.create_images_dir, basename1); filename2 = getPath2(global.create_images_dir, basename2); getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0); if (SDL_SaveBMP(bitmap1->surface, filename1) != 0) Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1); getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0); if (SDL_SaveBMP(bitmap2->surface, filename2) != 0) Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2); free(filename1); free(filename2); if (options.debug) printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n')); } FreeBitmap(bitmap1); FreeBitmap(bitmap2); if (options.debug) printf("\n"); Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS); CloseAllAndExit(0); #endif } /* ------------------------------------------------------------------------- */ /* create and save images for custom and group elements (raw BMP format) */ /* ------------------------------------------------------------------------- */ void CreateCustomElementImages() { #if defined(TARGET_SDL) char *filename = "graphics.classic/RocksCE.bmp"; Bitmap *bitmap; Bitmap *src_bitmap; int dummy_graphic = IMG_CUSTOM_99; int yoffset_ce = 0; int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16); int src_x, src_y; int i; bitmap = CreateBitmap(TILEX * 16 * 2, TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16, DEFAULT_DEPTH); getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int x = i % 16; int y = i / 16; int ii = i + 1; int j; BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ce); BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, TILEX * x + TILEX * 16, TILEY * y + yoffset_ce); for (j = 2; j >= 0; j--) { int c = ii % 10; BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10, TILEX * x + 6 + j * 7, TILEY * y + 11 + yoffset_ce); BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10, TILEX * 16 + TILEX * x + 6 + j * 8, TILEY * y + 10 + yoffset_ce); ii /= 10; } } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int x = i % 16; int y = i / 16; int ii = i + 1; int j; BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ge); BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, TILEX * x + TILEX * 16, TILEY * y + yoffset_ge); for (j = 1; j >= 0; j--) { int c = ii % 10; BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10, TILEX * x + 6 + j * 10, TILEY * y + 11 + yoffset_ge); BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10, TILEX * 16 + TILEX * x + 10 + j * 8, TILEY * y + 10 + yoffset_ge); ii /= 10; } } if (SDL_SaveBMP(bitmap->surface, filename) != 0) Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename); FreeBitmap(bitmap); CloseAllAndExit(0); #endif } #if 0 void CreateLevelSketchImages_TEST() { void CreateCustomElementImages() } #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_snd.c0000644000175000017500000003250510577215024017362 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_snd.c * ***********************************************************/ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is SND_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo sound_config_suffix[] = { { ".mode_loop", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".volume", "100", TYPE_INTEGER }, { ".priority", "0", TYPE_INTEGER }, { NULL, NULL, 0 } }; struct ConfigInfo sound_config[] = { /* some default sounds */ { "[default].digging", "schlurf.wav" }, { "[default].collecting", "pong.wav" }, { "[default].snapping", "pong.wav" }, { "[default].pushing", "pusch.wav" }, { "[default].impact", "klopf.wav" }, { "[default].walking", "empty.wav" }, { "[default].passing", "gate.wav" }, { "[default].dying", "autsch.wav" }, { "[default].exploding", "roaaar.wav" }, { "[sp_default].exploding", "booom.wav" }, /* sounds for Boulder Dash style elements and actions */ { "bd_diamond.collecting", "pong.wav" }, { "bd_diamond.impact", "pling.wav" }, { "bd_rock.pushing", "pusch.wav" }, { "bd_rock.impact", "klopf.wav" }, { "bd_magic_wall.activating", "quirk.wav" }, { "bd_magic_wall.active", "miep.wav" }, { "bd_magic_wall.filling", "quirk.wav" }, { "bd_amoeba.waiting", UNDEFINED_FILENAME }, { "bd_amoeba.growing", "amoebe.wav" }, { "bd_amoeba.turning_to_gem", "pling.wav" }, { "bd_amoeba.turning_to_rock", "klopf.wav" }, { "bd_butterfly.moving", "klapper.wav" }, { "bd_butterfly.waiting", "klapper.wav" }, { "bd_firefly.moving", "roehr.wav" }, { "bd_firefly.waiting", "roehr.wav" }, /* sounds for Supaplex style elements and actions */ { "sp_base.digging", "base.wav" }, { "sp_buggy_base.digging", "base.wav" }, { "sp_buggy_base.active", "bug.wav" }, { "sp_infotron.collecting", "infotron.wav" }, { "sp_infotron.impact", "pling.wav" }, { "sp_zonk.pushing", "zonkpush.wav" }, { "sp_zonk.impact", "zonkdown.wav" }, { "sp_disk_red.collecting", "infotron.wav" }, { "sp_disk_orange.pushing", "zonkpush.wav" }, { "sp_disk_yellow.pushing", "pusch.wav" }, { "[sp_port].passing", "gate.wav" }, { "[sp_exit].passing", "exit.wav" }, { "[sp_exit].opening", UNDEFINED_FILENAME }, { "[sp_exit].closing", UNDEFINED_FILENAME }, { "sp_sniksnak.moving", UNDEFINED_FILENAME }, { "sp_sniksnak.waiting", UNDEFINED_FILENAME }, { "sp_electron.moving", UNDEFINED_FILENAME }, { "sp_electron.waiting", UNDEFINED_FILENAME }, { "sp_terminal.activating", UNDEFINED_FILENAME }, { "sp_terminal.active", UNDEFINED_FILENAME }, /* sounds for Sokoban style elements and actions */ { "[sokoban].pushing", "pusch.wav" }, { "[sokoban].filling", "deng.wav" }, { "[sokoban].emptying", UNDEFINED_FILENAME }, /* sounds for Emerald Mine style elements and actions */ { "[player].moving", "empty.wav" }, { "[player].moving.mode_loop", "false" }, { "sand.digging", "schlurf.wav" }, { "[emerald].collecting", "pong.wav" }, { "[emerald].impact", "pling.wav" }, { "diamond.collecting", "pong.wav" }, { "diamond.impact", "pling.wav" }, { "diamond.breaking", "quirk.wav" }, { "rock.pushing", "pusch.wav" }, { "rock.impact", "klopf.wav" }, { "bomb.pushing", "pusch.wav" }, { "nut.pushing", "knurk.wav" }, { "nut.breaking", "knack.wav" }, { "nut.impact", "klumpf.wav" }, { "[dynamite].collecting", "pong.wav" }, { "[dynamite].dropping", "deng.wav" }, { "[dynamite].active", "zisch.wav" }, { "[key].collecting", "pong.wav" }, { "[gate].passing", "gate.wav" }, { "bug.moving", "klapper.wav" }, { "bug.waiting", "klapper.wav" }, { "spaceship.moving", "roehr.wav" }, { "spaceship.waiting", "roehr.wav" }, { "yamyam.moving", UNDEFINED_FILENAME }, { "yamyam.waiting", "njam.wav" }, { "yamyam.digging", "njam.wav" }, { "robot.moving", "schlurf.wav" }, { "robot.moving.mode_loop", "false" }, { "robot.waiting", UNDEFINED_FILENAME }, { "robot_wheel.activating", "deng.wav" }, { "robot_wheel.active", "miep.wav" }, { "magic_wall.activating", "quirk.wav" }, { "magic_wall.active", "miep.wav" }, { "magic_wall.filling", "quirk.wav" }, { "dc_magic_wall.activating", "quirk.wav" }, { "dc_magic_wall.active", "miep.wav" }, { "dc_magic_wall.filling", "quirk.wav" }, { "[amoeba].waiting", UNDEFINED_FILENAME }, { "[amoeba].growing", "amoebe.wav" }, { "[amoeba].dropping", UNDEFINED_FILENAME }, { "acid.splashing", "blurb.wav" }, { "[quicksand].filling", UNDEFINED_FILENAME }, { "[quicksand].emptying", UNDEFINED_FILENAME }, { "[exit].opening", "oeffnen.wav" }, { "[exit].closing", "oeffnen.wav" }, { "[exit].passing", "buing.wav" }, { "[steel_exit].opening", "oeffnen.wav" }, { "[steel_exit].closing", "oeffnen.wav" }, { "[steel_exit].passing", "buing.wav" }, { "[em_exit].opening", "gong.wav" }, { "[em_exit].closing", UNDEFINED_FILENAME }, { "[em_exit].passing", "buing.wav" }, { "[em_steel_exit].opening", "gong.wav" }, { "[em_steel_exit].closing", UNDEFINED_FILENAME }, { "[em_steel_exit].passing", "buing.wav" }, { "penguin.passing", "buing.wav" }, /* sounds for Emerald Mine Club style elements and actions */ { "balloon.moving", UNDEFINED_FILENAME }, { "balloon.waiting", UNDEFINED_FILENAME }, { "balloon.pushing", "schlurf.wav" }, { "[balloon_switch].activating", UNDEFINED_FILENAME }, { "spring.moving", UNDEFINED_FILENAME }, { "spring.pushing", "pusch.wav" }, { "spring.impact", "klopf.wav" }, { "[wall].growing", UNDEFINED_FILENAME }, { "emc_android.pushing", "pusch.wav" }, { "emc_android.moving", "roehr.wav" }, { "emc_android.moving.mode_loop", "false" }, { "emc_android.dropping", "deng.wav" }, { "emc_magic_ball.dropping", "deng.wav" }, /* sounds for Diamond Caves style elements and actions */ { "pearl.collecting", "pong.wav" }, { "pearl.breaking", "knack.wav" }, { "pearl.impact", "pling.wav" }, { "crystal.collecting", "pong.wav" }, { "crystal.impact", "pling.wav" }, { "[envelope].collecting", "pong.wav" }, { "[envelope].opening", UNDEFINED_FILENAME }, { "[envelope].closing", UNDEFINED_FILENAME }, { "invisible_sand.digging", "schlurf.wav" }, { "invisible_sand.active.digging", "schlurf.wav" }, { "shield_normal.collecting", "pong.wav" }, { "shield_normal.active", UNDEFINED_FILENAME }, { "shield_deadly.collecting", "pong.wav" }, { "shield_deadly.active", UNDEFINED_FILENAME }, { "extra_time.collecting", "gong.wav" }, { "mole.moving", UNDEFINED_FILENAME }, { "mole.waiting", UNDEFINED_FILENAME }, { "mole.digging", "blurb.wav" }, { "[switchgate_switch].activating", UNDEFINED_FILENAME }, { "[switchgate].opening", "oeffnen.wav" }, { "[switchgate].closing", "oeffnen.wav" }, { "[switchgate].passing", "gate.wav" }, { "[timegate_switch].activating", "deng.wav" }, { "[timegate_switch].active", "miep.wav" }, { "[timegate_switch].deactivating", UNDEFINED_FILENAME }, { "[timegate].opening", "oeffnen.wav" }, { "[timegate].closing", "oeffnen.wav" }, { "[timegate].passing", "gate.wav" }, { "[conveyor_belt_switch].activating",UNDEFINED_FILENAME }, { "[conveyor_belt].active", UNDEFINED_FILENAME }, { "[conveyor_belt_switch].deactivating",UNDEFINED_FILENAME }, { "light_switch.activating", UNDEFINED_FILENAME }, { "light_switch.deactivating", UNDEFINED_FILENAME }, /* sounds for DX Boulderdash style elements and actions */ { "dx_supabomb.pushing", "pusch.wav" }, { "trap.digging", "schlurf.wav" }, { "trap.activating", UNDEFINED_FILENAME }, { "[tube].walking", UNDEFINED_FILENAME }, /* sounds for Rocks'n'Diamonds style elements and actions */ { "amoeba.turning_to_gem", "pling.wav" }, { "amoeba.turning_to_rock", "klopf.wav" }, { "speed_pill.collecting", "pong.wav" }, { "dynabomb_increase_number.collecting","pong.wav" }, { "dynabomb_increase_size.collecting","pong.wav" }, { "dynabomb_increase_power.collecting","pong.wav" }, { "[dynabomb].dropping", "deng.wav" }, { "[dynabomb].active", "zisch.wav" }, { "satellite.moving", UNDEFINED_FILENAME }, { "satellite.waiting", UNDEFINED_FILENAME }, { "satellite.pushing", "pusch.wav" }, { "lamp.activating", "deng.wav" }, { "lamp.deactivating", "deng.wav" }, { "time_orb_full.collecting", "gong.wav" }, { "time_orb_full.impact", "deng.wav" }, { "time_orb_empty.pushing", "pusch.wav" }, { "time_orb_empty.impact", "deng.wav" }, { "game_of_life.waiting", UNDEFINED_FILENAME }, { "game_of_life.growing", "amoebe.wav" }, { "biomaze.waiting", UNDEFINED_FILENAME }, { "biomaze.growing", "amoebe.wav" }, { "pacman.moving", UNDEFINED_FILENAME }, { "pacman.waiting", UNDEFINED_FILENAME }, { "pacman.digging", UNDEFINED_FILENAME }, { "dark_yamyam.moving", UNDEFINED_FILENAME }, { "dark_yamyam.waiting", "njam.wav" }, { "dark_yamyam.digging", UNDEFINED_FILENAME }, { "penguin.moving", UNDEFINED_FILENAME }, { "penguin.waiting", UNDEFINED_FILENAME }, { "pig.moving", UNDEFINED_FILENAME }, { "pig.waiting", UNDEFINED_FILENAME }, { "pig.digging", UNDEFINED_FILENAME }, { "dragon.moving", UNDEFINED_FILENAME }, { "dragon.waiting", UNDEFINED_FILENAME }, { "dragon.attacking", UNDEFINED_FILENAME }, /* sounds not associated to game elements (used for menu screens etc.) */ /* keyword to stop parser: "NO_MORE_ELEMENT_SOUNDS" <-- do not change! */ /* sounds for other game actions */ { "game.starting", UNDEFINED_FILENAME }, { "game.running_out_of_time", "gong.wav" }, { "game.leveltime_bonus", "sirr.wav" }, { "game.losing", "lachen.wav" }, { "game.winning", UNDEFINED_FILENAME }, { "game.sokoban_solving", "buing.wav" }, /* sounds for other non-game actions */ { "door.opening", "oeffnen.wav" }, { "door.closing", "oeffnen.wav" }, /* sounds for menu actions */ { "menu.item.activating", "empty.wav" }, { "menu.item.selecting", "base.wav" }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.SCORES", "halloffame.wav" }, { "background.SCORES.mode_loop", "false" }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", UNDEFINED_FILENAME }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1",UNDEFINED_FILENAME }, { "background.titlemessage_initial_2",UNDEFINED_FILENAME }, { "background.titlemessage_initial_3",UNDEFINED_FILENAME }, { "background.titlemessage_initial_4",UNDEFINED_FILENAME }, { "background.titlemessage_initial_5",UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, #if 0 { "[not used]", "antigrav.wav" }, { "[not used]", "bong.wav" }, { "[not used]", "fuel.wav" }, { "[not used]", "holz.wav" }, { "[not used]", "hui.wav" }, { "[not used]", "kabumm.wav" }, { "[not used]", "kink.wav" }, { "[not used]", "kling.wav" }, { "[not used]", "krach.wav" }, { "[not used]", "laser.wav" }, { "[not used]", "quiek.wav" }, { "[not used]", "rumms.wav" }, { "[not used]", "schlopp.wav" }, { "[not used]", "schrff.wav" }, { "[not used]", "schwirr.wav" }, { "[not used]", "slurp.wav" }, { "[not used]", "sproing.wav" }, { "[not used]", "warnton.wav" }, { "[not used]", "whoosh.wav" }, { "[not used]", "boom.wav" }, #endif { NULL, NULL } }; rocksndiamonds-3.3.0.1+dfsg1/src/screens.h0000644000175000017500000000301710534314447017236 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * screens.h * ***********************************************************/ #ifndef SCREENS_H #define SCREENS_H #include "main.h" /* (arbitrary, but unique) values for HandleChooseTree() */ #define SCROLL_LINE (1 * SCR_FIELDY) #define SCROLL_PAGE (2 * SCR_FIELDY) int effectiveGameStatus(); void DrawMainMenuExt(int, boolean); void DrawAndFadeInMainMenu(int); void DrawMainMenu(void); void DrawHallOfFame(int); void RedrawSetupScreenAfterFullscreenToggle(); void HandleTitleScreen(int, int, int, int, int); void HandleMainMenu(int, int, int, int, int); void HandleChooseLevel(int, int, int, int, int); void HandleHallOfFame(int, int, int, int, int); void HandleInfoScreen(int, int, int, int, int); void HandleSetupScreen(int, int, int, int, int); void HandleTypeName(int, Key); void HandleGameActions(void); void CreateScreenGadgets(); void FreeScreenGadgets(); #endif /* SCREENS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/cartoons.c0000644000175000017500000000545011270150522017410 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * cartoons.c * ***********************************************************/ #include "cartoons.h" #include "main.h" #include "tools.h" /* values for toon definition */ #define MAX_NUM_TOONS 20 static struct ToonInfo toons[MAX_NUM_TOONS]; static void PrepareBackbuffer() { if (game_status != GAME_MODE_PLAYING) return; if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { BlitScreenToBitmap_EM(backbuffer); } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { BlitScreenToBitmap_SP(backbuffer); } else if (setup.soft_scrolling) /* GAME_ENGINE_TYPE_RND */ { int fx = FX, fy = FY; fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0); fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0); BlitBitmap(fieldbuffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY); } } boolean ToonNeedsRedraw() { return TRUE; } void InitToons() { int num_toons = MAX_NUM_TOONS; int i; if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS) num_toons = global.num_toons; for (i = 0; i < num_toons; i++) { int graphic = IMG_TOON_1 + i; struct FileInfo *image = getImageListEntryFromImageID(graphic); toons[i].bitmap = graphic_info[graphic].bitmap; toons[i].src_x = graphic_info[graphic].src_x; toons[i].src_y = graphic_info[graphic].src_y; toons[i].width = graphic_info[graphic].width; toons[i].height = graphic_info[graphic].height; toons[i].anim_frames = graphic_info[graphic].anim_frames; toons[i].anim_delay = graphic_info[graphic].anim_delay; toons[i].anim_mode = graphic_info[graphic].anim_mode; toons[i].anim_start_frame = graphic_info[graphic].anim_start_frame; toons[i].step_offset = graphic_info[graphic].step_offset; toons[i].step_delay = graphic_info[graphic].step_delay; toons[i].direction = image->parameter[GFX_ARG_DIRECTION]; toons[i].position = image->parameter[GFX_ARG_POSITION]; } #if 1 InitToonScreen(bitmap_db_toons, #else InitToonScreen(bitmap_db_door, #endif BackToFront, PrepareBackbuffer, ToonNeedsRedraw, toons, num_toons, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, GAME_FRAME_DELAY); } rocksndiamonds-3.3.0.1+dfsg1/src/game.c0000644000175000017500000157364011362667235016525 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * game.c * ***********************************************************/ #include "libgame/libgame.h" #include "game.h" #include "init.h" #include "tools.h" #include "screens.h" #include "files.h" #include "tape.h" #include "network.h" /* EXPERIMENTAL STUFF */ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ #define USE_NEW_STUFF ( 1) #define USE_NEW_SP_SLIPPERY (USE_NEW_STUFF * 1) #define USE_NEW_CUSTOM_VALUE (USE_NEW_STUFF * 1) #define USE_NEW_PLAYER_ANIM (USE_NEW_STUFF * 1) #define USE_NEW_ALL_SLIPPERY (USE_NEW_STUFF * 1) #define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1) #define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1) #define USE_NEW_SNAP_DELAY (USE_NEW_STUFF * 1) #define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) #define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) #define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1) #define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1) #define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1) #define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1) #define USE_NEW_CONTINUOUS_SNAPPING (USE_NEW_STUFF * 1) #define USE_GFX_RESET_GFX_ANIMATION (USE_NEW_STUFF * 1) #define USE_BOTH_SWITCHGATE_SWITCHES (USE_NEW_STUFF * 1) #define USE_PLAYER_GRAVITY (USE_NEW_STUFF * 1) #define USE_FIXED_BORDER_RUNNING_GFX (USE_NEW_STUFF * 1) #define USE_QUICKSAND_BD_ROCK_BUGFIX (USE_NEW_STUFF * 0) #define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) #define USE_CODE_THAT_BREAKS_SNAKE_BITE (USE_NEW_STUFF * 1) #define USE_UFAST_PLAYER_EXIT_BUGFIX (USE_NEW_STUFF * 1) #define USE_GFX_RESET_ONLY_WHEN_MOVING (USE_NEW_STUFF * 1) #define USE_GFX_RESET_PLAYER_ARTWORK (USE_NEW_STUFF * 1) #define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) #define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) #define USE_FIX_CE_ACTION_WITH_PLAYER (USE_NEW_STUFF * 1) #define USE_FIX_NO_ACTION_AFTER_CHANGE (USE_NEW_STUFF * 1) #define USE_PLAYER_REANIMATION (USE_NEW_STUFF * 1) #define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1) #define USE_NEW_PLAYER_ASSIGNMENTS (USE_NEW_STUFF * 1) #define USE_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 0) #if USE_DELAYED_GFX_REDRAW #define TEST_DrawLevelField(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE #define TEST_DrawLevelFieldCrumbled(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS #define TEST_DrawTwinkleOnField(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_TWINKLED #else #define TEST_DrawLevelField(x, y) \ DrawLevelField(x, y) #define TEST_DrawLevelFieldCrumbled(x, y) \ DrawLevelFieldCrumbled(x, y) #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ DrawLevelFieldCrumbledNeighbours(x, y) #define TEST_DrawTwinkleOnField(x, y) \ DrawTwinkleOnField(x, y) #endif /* for DigField() */ #define DF_NO_PUSH 0 #define DF_DIG 1 #define DF_SNAP 2 /* for MovePlayer() */ #define MP_NO_ACTION 0 #define MP_MOVING 1 #define MP_ACTION 2 #define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION) /* for ScrollPlayer() */ #define SCROLL_INIT 0 #define SCROLL_GO_ON 1 /* for Bang()/Explode() */ #define EX_PHASE_START 0 #define EX_TYPE_NONE 0 #define EX_TYPE_NORMAL (1 << 0) #define EX_TYPE_CENTER (1 << 1) #define EX_TYPE_BORDER (1 << 2) #define EX_TYPE_CROSS (1 << 3) #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) #define PANEL_OFF() (local_player->LevelSolved_PanelOff) #define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) #define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p)) #define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p)) /* special positions in the game control window (relative to control window) */ #define XX_LEVEL1 (PANEL_XPOS(game.panel.level)) #define XX_LEVEL2 (PANEL_XPOS(game.panel.level) - 1) #define XX_LEVEL (PANEL_XPOS(game.panel.level)) #define YY_LEVEL (PANEL_YPOS(game.panel.level)) #define XX_EMERALDS (PANEL_XPOS(game.panel.gems)) #define YY_EMERALDS (PANEL_YPOS(game.panel.gems)) #define XX_DYNAMITE (PANEL_XPOS(game.panel.inventory)) #define YY_DYNAMITE (PANEL_YPOS(game.panel.inventory)) #define XX_KEYS (PANEL_XPOS(game.panel.keys)) #define YY_KEYS (PANEL_YPOS(game.panel.keys)) #define XX_SCORE (PANEL_XPOS(game.panel.score)) #define YY_SCORE (PANEL_YPOS(game.panel.score)) #define XX_TIME1 (PANEL_XPOS(game.panel.time)) #define XX_TIME2 (PANEL_XPOS(game.panel.time) + 1) #define XX_TIME (PANEL_XPOS(game.panel.time)) #define YY_TIME (PANEL_YPOS(game.panel.time)) /* special positions in the game control window (relative to main window) */ #define DX_LEVEL1 (DX + XX_LEVEL1) #define DX_LEVEL2 (DX + XX_LEVEL2) #define DX_LEVEL (DX + XX_LEVEL) #define DY_LEVEL (DY + YY_LEVEL) #define DX_EMERALDS (DX + XX_EMERALDS) #define DY_EMERALDS (DY + YY_EMERALDS) #define DX_DYNAMITE (DX + XX_DYNAMITE) #define DY_DYNAMITE (DY + YY_DYNAMITE) #define DX_KEYS (DX + XX_KEYS) #define DY_KEYS (DY + YY_KEYS) #define DX_SCORE (DX + XX_SCORE) #define DY_SCORE (DY + YY_SCORE) #define DX_TIME1 (DX + XX_TIME1) #define DX_TIME2 (DX + XX_TIME2) #define DX_TIME (DX + XX_TIME) #define DY_TIME (DY + YY_TIME) #if 1 /* game panel display and control definitions */ #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 #define GAME_PANEL_INVENTORY_COUNT 2 #define GAME_PANEL_INVENTORY_FIRST_1 3 #define GAME_PANEL_INVENTORY_FIRST_2 4 #define GAME_PANEL_INVENTORY_FIRST_3 5 #define GAME_PANEL_INVENTORY_FIRST_4 6 #define GAME_PANEL_INVENTORY_FIRST_5 7 #define GAME_PANEL_INVENTORY_FIRST_6 8 #define GAME_PANEL_INVENTORY_FIRST_7 9 #define GAME_PANEL_INVENTORY_FIRST_8 10 #define GAME_PANEL_INVENTORY_LAST_1 11 #define GAME_PANEL_INVENTORY_LAST_2 12 #define GAME_PANEL_INVENTORY_LAST_3 13 #define GAME_PANEL_INVENTORY_LAST_4 14 #define GAME_PANEL_INVENTORY_LAST_5 15 #define GAME_PANEL_INVENTORY_LAST_6 16 #define GAME_PANEL_INVENTORY_LAST_7 17 #define GAME_PANEL_INVENTORY_LAST_8 18 #define GAME_PANEL_KEY_1 19 #define GAME_PANEL_KEY_2 20 #define GAME_PANEL_KEY_3 21 #define GAME_PANEL_KEY_4 22 #define GAME_PANEL_KEY_5 23 #define GAME_PANEL_KEY_6 24 #define GAME_PANEL_KEY_7 25 #define GAME_PANEL_KEY_8 26 #define GAME_PANEL_KEY_WHITE 27 #define GAME_PANEL_KEY_WHITE_COUNT 28 #define GAME_PANEL_SCORE 29 #define GAME_PANEL_HIGHSCORE 30 #define GAME_PANEL_TIME 31 #define GAME_PANEL_TIME_HH 32 #define GAME_PANEL_TIME_MM 33 #define GAME_PANEL_TIME_SS 34 #define GAME_PANEL_FRAME 35 #define GAME_PANEL_SHIELD_NORMAL 36 #define GAME_PANEL_SHIELD_NORMAL_TIME 37 #define GAME_PANEL_SHIELD_DEADLY 38 #define GAME_PANEL_SHIELD_DEADLY_TIME 39 #define GAME_PANEL_EXIT 40 #define GAME_PANEL_EMC_MAGIC_BALL 41 #define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 42 #define GAME_PANEL_LIGHT_SWITCH 43 #define GAME_PANEL_LIGHT_SWITCH_TIME 44 #define GAME_PANEL_TIMEGATE_SWITCH 45 #define GAME_PANEL_TIMEGATE_SWITCH_TIME 46 #define GAME_PANEL_SWITCHGATE_SWITCH 47 #define GAME_PANEL_EMC_LENSES 48 #define GAME_PANEL_EMC_LENSES_TIME 49 #define GAME_PANEL_EMC_MAGNIFIER 50 #define GAME_PANEL_EMC_MAGNIFIER_TIME 51 #define GAME_PANEL_BALLOON_SWITCH 52 #define GAME_PANEL_DYNABOMB_NUMBER 53 #define GAME_PANEL_DYNABOMB_SIZE 54 #define GAME_PANEL_DYNABOMB_POWER 55 #define GAME_PANEL_PENGUINS 56 #define GAME_PANEL_SOKOBAN_OBJECTS 57 #define GAME_PANEL_SOKOBAN_FIELDS 58 #define GAME_PANEL_ROBOT_WHEEL 59 #define GAME_PANEL_CONVEYOR_BELT_1 60 #define GAME_PANEL_CONVEYOR_BELT_2 61 #define GAME_PANEL_CONVEYOR_BELT_3 62 #define GAME_PANEL_CONVEYOR_BELT_4 63 #define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 64 #define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 65 #define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 66 #define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 67 #define GAME_PANEL_MAGIC_WALL 68 #define GAME_PANEL_MAGIC_WALL_TIME 69 #define GAME_PANEL_GRAVITY_STATE 70 #define GAME_PANEL_GRAPHIC_1 71 #define GAME_PANEL_GRAPHIC_2 72 #define GAME_PANEL_GRAPHIC_3 73 #define GAME_PANEL_GRAPHIC_4 74 #define GAME_PANEL_GRAPHIC_5 75 #define GAME_PANEL_GRAPHIC_6 76 #define GAME_PANEL_GRAPHIC_7 77 #define GAME_PANEL_GRAPHIC_8 78 #define GAME_PANEL_ELEMENT_1 79 #define GAME_PANEL_ELEMENT_2 80 #define GAME_PANEL_ELEMENT_3 81 #define GAME_PANEL_ELEMENT_4 82 #define GAME_PANEL_ELEMENT_5 83 #define GAME_PANEL_ELEMENT_6 84 #define GAME_PANEL_ELEMENT_7 85 #define GAME_PANEL_ELEMENT_8 86 #define GAME_PANEL_ELEMENT_COUNT_1 87 #define GAME_PANEL_ELEMENT_COUNT_2 88 #define GAME_PANEL_ELEMENT_COUNT_3 89 #define GAME_PANEL_ELEMENT_COUNT_4 90 #define GAME_PANEL_ELEMENT_COUNT_5 91 #define GAME_PANEL_ELEMENT_COUNT_6 92 #define GAME_PANEL_ELEMENT_COUNT_7 93 #define GAME_PANEL_ELEMENT_COUNT_8 94 #define GAME_PANEL_CE_SCORE_1 95 #define GAME_PANEL_CE_SCORE_2 96 #define GAME_PANEL_CE_SCORE_3 97 #define GAME_PANEL_CE_SCORE_4 98 #define GAME_PANEL_CE_SCORE_5 99 #define GAME_PANEL_CE_SCORE_6 100 #define GAME_PANEL_CE_SCORE_7 101 #define GAME_PANEL_CE_SCORE_8 102 #define GAME_PANEL_CE_SCORE_1_ELEMENT 103 #define GAME_PANEL_CE_SCORE_2_ELEMENT 104 #define GAME_PANEL_CE_SCORE_3_ELEMENT 105 #define GAME_PANEL_CE_SCORE_4_ELEMENT 106 #define GAME_PANEL_CE_SCORE_5_ELEMENT 107 #define GAME_PANEL_CE_SCORE_6_ELEMENT 108 #define GAME_PANEL_CE_SCORE_7_ELEMENT 109 #define GAME_PANEL_CE_SCORE_8_ELEMENT 110 #define GAME_PANEL_PLAYER_NAME 111 #define GAME_PANEL_LEVEL_NAME 112 #define GAME_PANEL_LEVEL_AUTHOR 113 #define NUM_GAME_PANEL_CONTROLS 114 struct GamePanelOrderInfo { int nr; int sort_priority; }; static struct GamePanelOrderInfo game_panel_order[NUM_GAME_PANEL_CONTROLS]; struct GamePanelControlInfo { int nr; struct TextPosInfo *pos; int type; int value, last_value; int frame, last_frame; int gfx_frame; int gfx_random; }; static struct GamePanelControlInfo game_panel_controls[] = { { GAME_PANEL_LEVEL_NUMBER, &game.panel.level_number, TYPE_INTEGER, }, { GAME_PANEL_GEMS, &game.panel.gems, TYPE_INTEGER, }, { GAME_PANEL_INVENTORY_COUNT, &game.panel.inventory_count, TYPE_INTEGER, }, { GAME_PANEL_INVENTORY_FIRST_1, &game.panel.inventory_first[0], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_2, &game.panel.inventory_first[1], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_3, &game.panel.inventory_first[2], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_4, &game.panel.inventory_first[3], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_5, &game.panel.inventory_first[4], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_6, &game.panel.inventory_first[5], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_7, &game.panel.inventory_first[6], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_8, &game.panel.inventory_first[7], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_1, &game.panel.inventory_last[0], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_2, &game.panel.inventory_last[1], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_3, &game.panel.inventory_last[2], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_4, &game.panel.inventory_last[3], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_5, &game.panel.inventory_last[4], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_6, &game.panel.inventory_last[5], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_7, &game.panel.inventory_last[6], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_8, &game.panel.inventory_last[7], TYPE_ELEMENT, }, { GAME_PANEL_KEY_1, &game.panel.key[0], TYPE_ELEMENT, }, { GAME_PANEL_KEY_2, &game.panel.key[1], TYPE_ELEMENT, }, { GAME_PANEL_KEY_3, &game.panel.key[2], TYPE_ELEMENT, }, { GAME_PANEL_KEY_4, &game.panel.key[3], TYPE_ELEMENT, }, { GAME_PANEL_KEY_5, &game.panel.key[4], TYPE_ELEMENT, }, { GAME_PANEL_KEY_6, &game.panel.key[5], TYPE_ELEMENT, }, { GAME_PANEL_KEY_7, &game.panel.key[6], TYPE_ELEMENT, }, { GAME_PANEL_KEY_8, &game.panel.key[7], TYPE_ELEMENT, }, { GAME_PANEL_KEY_WHITE, &game.panel.key_white, TYPE_ELEMENT, }, { GAME_PANEL_KEY_WHITE_COUNT, &game.panel.key_white_count, TYPE_INTEGER, }, { GAME_PANEL_SCORE, &game.panel.score, TYPE_INTEGER, }, { GAME_PANEL_HIGHSCORE, &game.panel.highscore, TYPE_INTEGER, }, { GAME_PANEL_TIME, &game.panel.time, TYPE_INTEGER, }, { GAME_PANEL_TIME_HH, &game.panel.time_hh, TYPE_INTEGER, }, { GAME_PANEL_TIME_MM, &game.panel.time_mm, TYPE_INTEGER, }, { GAME_PANEL_TIME_SS, &game.panel.time_ss, TYPE_INTEGER, }, { GAME_PANEL_FRAME, &game.panel.frame, TYPE_INTEGER, }, { GAME_PANEL_SHIELD_NORMAL, &game.panel.shield_normal, TYPE_ELEMENT, }, { GAME_PANEL_SHIELD_NORMAL_TIME, &game.panel.shield_normal_time, TYPE_INTEGER, }, { GAME_PANEL_SHIELD_DEADLY, &game.panel.shield_deadly, TYPE_ELEMENT, }, { GAME_PANEL_SHIELD_DEADLY_TIME, &game.panel.shield_deadly_time, TYPE_INTEGER, }, { GAME_PANEL_EXIT, &game.panel.exit, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGIC_BALL, &game.panel.emc_magic_ball, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGIC_BALL_SWITCH, &game.panel.emc_magic_ball_switch, TYPE_ELEMENT, }, { GAME_PANEL_LIGHT_SWITCH, &game.panel.light_switch, TYPE_ELEMENT, }, { GAME_PANEL_LIGHT_SWITCH_TIME, &game.panel.light_switch_time, TYPE_INTEGER, }, { GAME_PANEL_TIMEGATE_SWITCH, &game.panel.timegate_switch, TYPE_ELEMENT, }, { GAME_PANEL_TIMEGATE_SWITCH_TIME, &game.panel.timegate_switch_time, TYPE_INTEGER, }, { GAME_PANEL_SWITCHGATE_SWITCH, &game.panel.switchgate_switch, TYPE_ELEMENT, }, { GAME_PANEL_EMC_LENSES, &game.panel.emc_lenses, TYPE_ELEMENT, }, { GAME_PANEL_EMC_LENSES_TIME, &game.panel.emc_lenses_time, TYPE_INTEGER, }, { GAME_PANEL_EMC_MAGNIFIER, &game.panel.emc_magnifier, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGNIFIER_TIME, &game.panel.emc_magnifier_time, TYPE_INTEGER, }, { GAME_PANEL_BALLOON_SWITCH, &game.panel.balloon_switch, TYPE_ELEMENT, }, { GAME_PANEL_DYNABOMB_NUMBER, &game.panel.dynabomb_number, TYPE_INTEGER, }, { GAME_PANEL_DYNABOMB_SIZE, &game.panel.dynabomb_size, TYPE_INTEGER, }, { GAME_PANEL_DYNABOMB_POWER, &game.panel.dynabomb_power, TYPE_ELEMENT, }, { GAME_PANEL_PENGUINS, &game.panel.penguins, TYPE_INTEGER, }, { GAME_PANEL_SOKOBAN_OBJECTS, &game.panel.sokoban_objects, TYPE_INTEGER, }, { GAME_PANEL_SOKOBAN_FIELDS, &game.panel.sokoban_fields, TYPE_INTEGER, }, { GAME_PANEL_ROBOT_WHEEL, &game.panel.robot_wheel, TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_1, &game.panel.conveyor_belt[0], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_2, &game.panel.conveyor_belt[1], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_3, &game.panel.conveyor_belt[2], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_4, &game.panel.conveyor_belt[3], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_1_SWITCH, &game.panel.conveyor_belt_switch[0], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_2_SWITCH, &game.panel.conveyor_belt_switch[1], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_3_SWITCH, &game.panel.conveyor_belt_switch[2], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_4_SWITCH, &game.panel.conveyor_belt_switch[3], TYPE_ELEMENT, }, { GAME_PANEL_MAGIC_WALL, &game.panel.magic_wall, TYPE_ELEMENT, }, { GAME_PANEL_MAGIC_WALL_TIME, &game.panel.magic_wall_time, TYPE_INTEGER, }, { GAME_PANEL_GRAVITY_STATE, &game.panel.gravity_state, TYPE_STRING, }, { GAME_PANEL_GRAPHIC_1, &game.panel.graphic[0], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_2, &game.panel.graphic[1], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_3, &game.panel.graphic[2], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_4, &game.panel.graphic[3], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_5, &game.panel.graphic[4], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_6, &game.panel.graphic[5], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_7, &game.panel.graphic[6], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_8, &game.panel.graphic[7], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_1, &game.panel.element[0], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_2, &game.panel.element[1], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_3, &game.panel.element[2], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_4, &game.panel.element[3], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_5, &game.panel.element[4], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_6, &game.panel.element[5], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_7, &game.panel.element[6], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_8, &game.panel.element[7], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_COUNT_1, &game.panel.element_count[0], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_2, &game.panel.element_count[1], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_3, &game.panel.element_count[2], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_4, &game.panel.element_count[3], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_5, &game.panel.element_count[4], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_6, &game.panel.element_count[5], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_7, &game.panel.element_count[6], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_8, &game.panel.element_count[7], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_1, &game.panel.ce_score[0], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_2, &game.panel.ce_score[1], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_3, &game.panel.ce_score[2], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_4, &game.panel.ce_score[3], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_5, &game.panel.ce_score[4], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_6, &game.panel.ce_score[5], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_7, &game.panel.ce_score[6], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_8, &game.panel.ce_score[7], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_1_ELEMENT, &game.panel.ce_score_element[0], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_2_ELEMENT, &game.panel.ce_score_element[1], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_3_ELEMENT, &game.panel.ce_score_element[2], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_4_ELEMENT, &game.panel.ce_score_element[3], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_5_ELEMENT, &game.panel.ce_score_element[4], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_6_ELEMENT, &game.panel.ce_score_element[5], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_7_ELEMENT, &game.panel.ce_score_element[6], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_8_ELEMENT, &game.panel.ce_score_element[7], TYPE_ELEMENT, }, { GAME_PANEL_PLAYER_NAME, &game.panel.player_name, TYPE_STRING, }, { GAME_PANEL_LEVEL_NAME, &game.panel.level_name, TYPE_STRING, }, { GAME_PANEL_LEVEL_AUTHOR, &game.panel.level_author, TYPE_STRING, }, { -1, NULL, -1, } }; #endif /* values for delayed check of falling and moving elements and for collision */ #define CHECK_DELAY_MOVING 3 #define CHECK_DELAY_FALLING CHECK_DELAY_MOVING #define CHECK_DELAY_COLLISION 2 #define CHECK_DELAY_IMPACT CHECK_DELAY_COLLISION /* values for initial player move delay (initial delay counter value) */ #define INITIAL_MOVE_DELAY_OFF -1 #define INITIAL_MOVE_DELAY_ON 0 /* values for player movement speed (which is in fact a delay value) */ #define MOVE_DELAY_MIN_SPEED 32 #define MOVE_DELAY_NORMAL_SPEED 8 #define MOVE_DELAY_HIGH_SPEED 4 #define MOVE_DELAY_MAX_SPEED 1 #define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x)) #define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x)) #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY( (p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) /* values for other actions */ #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) #define MOVE_STEPSIZE_MIN (1) #define MOVE_STEPSIZE_MAX (TILEX) #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0) #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0) #define INIT_GFX_RANDOM() (GetSimpleRandom(1000000)) #define GET_NEW_PUSH_DELAY(e) ( (element_info[e].push_delay_fixed) + \ RND(element_info[e].push_delay_random)) #define GET_NEW_DROP_DELAY(e) ( (element_info[e].drop_delay_fixed) + \ RND(element_info[e].drop_delay_random)) #define GET_NEW_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ RND(element_info[e].move_delay_random)) #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ (element_info[e].move_delay_random)) #define GET_NEW_CE_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\ RND(element_info[e].ce_value_random_initial)) #define GET_CE_SCORE(e) ( (element_info[e].collect_score)) #define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \ RND((c)->delay_random * (c)->delay_frames)) #define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \ RND((c)->delay_random)) #define GET_VALID_RUNTIME_ELEMENT(e) \ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e)) #define RESOLVED_REFERENCE_ELEMENT(be, e) \ ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \ (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ (be) + (e) - EL_SELF) #define GET_PLAYER_FROM_BITS(p) \ (EL_PLAYER_1 + ((p) != PLAYER_BITS_ANY ? log_2(p) : 0)) #define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \ (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ (e) == EL_CURRENT_CE_VALUE ? (cv) : \ (e) == EL_CURRENT_CE_SCORE ? (cs) : \ (e) >= EL_PREV_CE_8 && (e) <= EL_NEXT_CE_8 ? \ RESOLVED_REFERENCE_ELEMENT(be, e) : \ (e)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (DONT_COLLIDE_WITH(e) && \ IS_PLAYER(x, y) && \ !PLAYER_ENEMY_PROTECTED(x, y)))) #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0) #define SATELLITE_CAN_ENTER_FIELD(x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0) #define ANDROID_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT) #define ANDROID_CAN_CLONE_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \ CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT))) #define ENEMY_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND) #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y])) #define PACMAN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y])) #define PIG_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y])) #define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_EM_EXIT_OPEN || \ Feld[x][y] == EL_STEEL_EXIT_OPEN || \ Feld[x][y] == EL_EM_STEEL_EXIT_OPEN || \ IS_FOOD_PENGUIN(Feld[x][y]))) #define DRAGON_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition)) #define SPRING_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define SPRING_CAN_BUMP_FROM_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \ Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE)) #define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define CE_ENTER_FIELD_COND(e, x, y) \ (!IS_PLAYER(x, y) && \ IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))) #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) #define IN_LEV_FIELD_AND_IS_FREE(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y)) #define ACCESS_FROM(e, d) (element_info[e].access_direction &(d)) #define IS_WALKABLE_FROM(e, d) (IS_WALKABLE(e) && ACCESS_FROM(e, d)) #define IS_PASSABLE_FROM(e, d) (IS_PASSABLE(e) && ACCESS_FROM(e, d)) #define IS_ACCESSIBLE_FROM(e, d) (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d)) /* game button identifiers */ #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 #define SOUND_CTRL_ID_MUSIC 3 #define SOUND_CTRL_ID_LOOPS 4 #define SOUND_CTRL_ID_SIMPLE 5 #define NUM_GAME_BUTTONS 6 /* forward declaration for internal use */ static void CreateField(int, int, int); static void ResetGfxAnimation(int, int); static void SetPlayerWaiting(struct PlayerInfo *, boolean); static void AdvanceFrameAndPlayerCounters(int); static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int); static boolean MovePlayer(struct PlayerInfo *, int, int); static void ScrollPlayer(struct PlayerInfo *, int); static void ScrollScreen(struct PlayerInfo *, int); static int DigField(struct PlayerInfo *, int, int, int, int, int, int, int); static boolean DigFieldByCE(int, int, int); static boolean SnapField(struct PlayerInfo *, int, int); static boolean DropElement(struct PlayerInfo *); static void InitBeltMovement(void); static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *); static void KillPlayerUnlessEnemyProtected(int, int); static void KillPlayerUnlessExplosionProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); static void TestIfElementHitsCustomElement(int, int, int); #if 0 static void TestIfElementSmashesCustomElement(int, int, int); #endif static void HandleElementChange(int, int, int); static void ExecuteCustomElementAction(int, int, int, int); static boolean ChangeElement(int, int, int, int); static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); #define CheckTriggeredElementChange(x, y, e, ev) \ CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1) #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \ CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1) #define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \ CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1) #define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \ CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, p) static boolean CheckElementChangeExt(int, int, int, int, int, int, int); #define CheckElementChange(x, y, e, te, ev) \ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY) #define CheckElementChangeByPlayer(x, y, e, ev, p, s) \ CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s) #define CheckElementChangeBySide(x, y, e, te, ev, s) \ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s) static void PlayLevelSound(int, int, int); static void PlayLevelSoundNearest(int, int, int); static void PlayLevelSoundAction(int, int, int); static void PlayLevelSoundElementAction(int, int, int, int); static void PlayLevelSoundElementActionIfLoop(int, int, int, int); static void PlayLevelSoundActionIfLoop(int, int, int); static void StopLevelSoundActionIfLoop(int, int, int); static void PlayLevelMusic(); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); int AmoebeNachbarNr(int, int); void AmoebeUmwandeln(int, int); void ContinueMoving(int, int); void Bang(int, int); void InitMovDir(int, int); void InitAmoebaNr(int, int); int NewHiScore(void); void TestIfGoodThingHitsBadThing(int, int, int); void TestIfBadThingHitsGoodThing(int, int, int); void TestIfPlayerTouchesBadThing(int, int); void TestIfPlayerRunsIntoBadThing(int, int, int); void TestIfBadThingTouchesPlayer(int, int); void TestIfBadThingRunsIntoPlayer(int, int, int); void TestIfFriendTouchesBadThing(int, int); void TestIfBadThingTouchesFriend(int, int); void TestIfBadThingTouchesOtherBadThing(int, int); void TestIfGoodThingGetsHitByBadThing(int, int, int); void KillPlayer(struct PlayerInfo *); void BuryPlayer(struct PlayerInfo *); void RemovePlayer(struct PlayerInfo *); static int getInvisibleActiveFromInvisibleElement(int); static int getInvisibleFromInvisibleActiveElement(int); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; /* for detection of endless loops, caused by custom element programming */ /* (using maximal playfield width x 10 is just a rough approximation) */ #define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH * 10) #define RECURSION_LOOP_DETECTION_START(e, rc) \ { \ if (recursion_loop_detected) \ return (rc); \ \ if (recursion_loop_depth > MAX_ELEMENT_CHANGE_RECURSION_DEPTH) \ { \ recursion_loop_detected = TRUE; \ recursion_loop_element = (e); \ } \ \ recursion_loop_depth++; \ } #define RECURSION_LOOP_DETECTION_END() \ { \ recursion_loop_depth--; \ } static int recursion_loop_depth; static boolean recursion_loop_detected; static boolean recursion_loop_element; static int map_player_action[MAX_PLAYERS]; /* ------------------------------------------------------------------------- */ /* definition of elements that automatically change to other elements after */ /* a specified time, eventually calling a function when changing */ /* ------------------------------------------------------------------------- */ /* forward declaration for changer functions */ static void InitBuggyBase(int, int); static void WarnBuggyBase(int, int); static void InitTrap(int, int); static void ActivateTrap(int, int); static void ChangeActiveTrap(int, int); static void InitRobotWheel(int, int); static void RunRobotWheel(int, int); static void StopRobotWheel(int, int); static void InitTimegateWheel(int, int); static void RunTimegateWheel(int, int); static void InitMagicBallDelay(int, int); static void ActivateMagicBall(int, int); struct ChangingElementInfo { int element; int target_element; int change_delay; void (*pre_change_function)(int x, int y); void (*change_function)(int x, int y); void (*post_change_function)(int x, int y); }; static struct ChangingElementInfo change_delay_list[] = { { EL_NUT_BREAKING, EL_EMERALD, 6, NULL, NULL, NULL }, { EL_PEARL_BREAKING, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_EXIT_OPENING, EL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EXIT_CLOSING, EL_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_STEEL_EXIT_OPENING, EL_STEEL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_STEEL_EXIT_CLOSING, EL_STEEL_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_EM_EXIT_OPENING, EL_EM_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EM_EXIT_CLOSING, #if 1 EL_EMPTY, #else EL_EM_EXIT_CLOSED, #endif 29, NULL, NULL, NULL }, { EL_EM_STEEL_EXIT_OPENING, EL_EM_STEEL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EM_STEEL_EXIT_CLOSING, #if 1 EL_STEELWALL, #else EL_EM_STEEL_EXIT_CLOSED, #endif 29, NULL, NULL, NULL }, { EL_SP_EXIT_OPENING, EL_SP_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_SP_EXIT_CLOSING, EL_SP_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, 29, NULL, NULL, NULL }, { EL_SWITCHGATE_CLOSING, EL_SWITCHGATE_CLOSED, 29, NULL, NULL, NULL }, { EL_TIMEGATE_OPENING, EL_TIMEGATE_OPEN, 29, NULL, NULL, NULL }, { EL_TIMEGATE_CLOSING, EL_TIMEGATE_CLOSED, 29, NULL, NULL, NULL }, { EL_ACID_SPLASH_LEFT, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_ACID_SPLASH_RIGHT, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, 0, InitBuggyBase, NULL, NULL }, { EL_SP_BUGGY_BASE_ACTIVATING, EL_SP_BUGGY_BASE_ACTIVE, 0, InitBuggyBase, NULL, NULL }, { EL_SP_BUGGY_BASE_ACTIVE, EL_SP_BUGGY_BASE, 0, InitBuggyBase, WarnBuggyBase, NULL }, { EL_TRAP, EL_TRAP_ACTIVE, 0, InitTrap, NULL, ActivateTrap }, { EL_TRAP_ACTIVE, EL_TRAP, 31, NULL, ChangeActiveTrap, NULL }, { EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, 0, InitRobotWheel, RunRobotWheel, StopRobotWheel }, { EL_TIMEGATE_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, 0, InitTimegateWheel, RunTimegateWheel, NULL }, { EL_DC_TIMEGATE_SWITCH_ACTIVE, EL_DC_TIMEGATE_SWITCH, 0, InitTimegateWheel, RunTimegateWheel, NULL }, { EL_EMC_MAGIC_BALL_ACTIVE, EL_EMC_MAGIC_BALL_ACTIVE, 0, InitMagicBallDelay, NULL, ActivateMagicBall }, { EL_EMC_SPRING_BUMPER_ACTIVE, EL_EMC_SPRING_BUMPER, 8, NULL, NULL, NULL }, { EL_DIAGONAL_SHRINKING, EL_UNDEFINED, 0, NULL, NULL, NULL }, { EL_DIAGONAL_GROWING, EL_UNDEFINED, 0, NULL, NULL, NULL, }, { EL_UNDEFINED, EL_UNDEFINED, -1, NULL, NULL, NULL } }; struct { int element; int push_delay_fixed, push_delay_random; } push_delay_list[] = { { EL_SPRING, 0, 0 }, { EL_BALLOON, 0, 0 }, { EL_SOKOBAN_OBJECT, 2, 0 }, { EL_SOKOBAN_FIELD_FULL, 2, 0 }, { EL_SATELLITE, 2, 0 }, { EL_SP_DISK_YELLOW, 2, 0 }, { EL_UNDEFINED, 0, 0 }, }; struct { int element; int move_stepsize; } move_stepsize_list[] = { { EL_AMOEBA_DROP, 2 }, { EL_AMOEBA_DROPPING, 2 }, { EL_QUICKSAND_FILLING, 1 }, { EL_QUICKSAND_EMPTYING, 1 }, { EL_QUICKSAND_FAST_FILLING, 2 }, { EL_QUICKSAND_FAST_EMPTYING, 2 }, { EL_MAGIC_WALL_FILLING, 2 }, { EL_MAGIC_WALL_EMPTYING, 2 }, { EL_BD_MAGIC_WALL_FILLING, 2 }, { EL_BD_MAGIC_WALL_EMPTYING, 2 }, { EL_DC_MAGIC_WALL_FILLING, 2 }, { EL_DC_MAGIC_WALL_EMPTYING, 2 }, { EL_UNDEFINED, 0 }, }; struct { int element; int count; } collect_count_list[] = { { EL_EMERALD, 1 }, { EL_BD_DIAMOND, 1 }, { EL_EMERALD_YELLOW, 1 }, { EL_EMERALD_RED, 1 }, { EL_EMERALD_PURPLE, 1 }, { EL_DIAMOND, 3 }, { EL_SP_INFOTRON, 1 }, { EL_PEARL, 5 }, { EL_CRYSTAL, 8 }, { EL_UNDEFINED, 0 }, }; struct { int element; int direction; } access_direction_list[] = { { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN }, { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN }, { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP }, { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN }, { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP }, { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN }, { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP }, { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN }, { EL_SP_PORT_LEFT, MV_RIGHT }, { EL_SP_PORT_RIGHT, MV_LEFT }, { EL_SP_PORT_UP, MV_DOWN }, { EL_SP_PORT_DOWN, MV_UP }, { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT }, { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN }, { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_PORT_DOWN, MV_UP }, { EL_SP_GRAVITY_ON_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_ON_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_ON_PORT_DOWN, MV_UP }, { EL_SP_GRAVITY_OFF_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_OFF_PORT_DOWN, MV_UP }, { EL_UNDEFINED, MV_NONE } }; static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS]; #define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY]) #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0) #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \ IS_JUST_CHANGING(x, y)) #define CE_PAGE(e, ce) (element_info[e].event_page[ce]) /* static variables for playfield scan mode (scanning forward or backward) */ static int playfield_scan_start_x = 0; static int playfield_scan_start_y = 0; static int playfield_scan_delta_x = 1; static int playfield_scan_delta_y = 1; #define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \ (y) >= 0 && (y) <= lev_fieldy - 1; \ (y) += playfield_scan_delta_y) \ for ((x) = playfield_scan_start_x; \ (x) >= 0 && (x) <= lev_fieldx - 1; \ (x) += playfield_scan_delta_x) #ifdef DEBUG void DEBUG_SetMaximumDynamite() { int i; for (i = 0; i < MAX_INVENTORY_SIZE; i++) if (local_player->inventory_size < MAX_INVENTORY_SIZE) local_player->inventory_element[local_player->inventory_size++] = EL_DYNAMITE; } #endif static void InitPlayfieldScanModeVars() { if (game.use_reverse_scan_direction) { playfield_scan_start_x = lev_fieldx - 1; playfield_scan_start_y = lev_fieldy - 1; playfield_scan_delta_x = -1; playfield_scan_delta_y = -1; } else { playfield_scan_start_x = 0; playfield_scan_start_y = 0; playfield_scan_delta_x = 1; playfield_scan_delta_y = 1; } } static void InitPlayfieldScanMode(int mode) { game.use_reverse_scan_direction = (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE); InitPlayfieldScanModeVars(); } static int get_move_delay_from_stepsize(int move_stepsize) { move_stepsize = MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX); /* make sure that stepsize value is always a power of 2 */ move_stepsize = (1 << log_2(move_stepsize)); return TILEX / move_stepsize; } static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, boolean init_game) { int player_nr = player->index_nr; int move_delay = get_move_delay_from_stepsize(move_stepsize); boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE); /* do no immediately change move delay -- the player might just be moving */ player->move_delay_value_next = move_delay; /* information if player can move must be set separately */ player->cannot_move = cannot_move; if (init_game) { player->move_delay = game.initial_move_delay[player_nr]; player->move_delay_value = game.initial_move_delay_value[player_nr]; player->move_delay_value_next = -1; player->move_delay_reset_counter = 0; } } void GetPlayerConfig() { GameFrameDelay = setup.game_frame_delay; if (!audio.sound_available) setup.sound_simple = FALSE; if (!audio.loops_available) setup.sound_loops = FALSE; if (!audio.music_available) setup.sound_music = FALSE; if (!video.fullscreen_available) setup.fullscreen = FALSE; setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music); SetAudioMode(setup.sound); InitJoysticks(); } int GetElementFromGroupElement(int element) { if (IS_GROUP_ELEMENT(element)) { struct ElementGroupInfo *group = element_info[element].group; int last_anim_random_frame = gfx.anim_random_frame; int element_pos; if (group->choice_mode == ANIM_RANDOM) gfx.anim_random_frame = RND(group->num_elements_resolved); element_pos = getAnimationFrame(group->num_elements_resolved, 1, group->choice_mode, 0, group->choice_pos); if (group->choice_mode == ANIM_RANDOM) gfx.anim_random_frame = last_anim_random_frame; group->choice_pos++; element = group->element_resolved[element_pos]; } return element; } static void InitPlayerField(int x, int y, int element, boolean init_game) { if (element == EL_SP_MURPHY) { if (init_game) { if (stored_player[0].present) { Feld[x][y] = EL_SP_MURPHY_CLONE; return; } else { stored_player[0].initial_element = element; stored_player[0].use_murphy = TRUE; if (!level.use_artwork_element[0]) stored_player[0].artwork_element = EL_SP_MURPHY; } Feld[x][y] = EL_PLAYER_1; } } if (init_game) { struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1]; int jx = player->jx, jy = player->jy; player->present = TRUE; player->block_last_field = (element == EL_SP_MURPHY ? level.sp_block_last_field : level.block_last_field); /* ---------- initialize player's last field block delay --------------- */ /* always start with reliable default value (no adjustment needed) */ player->block_delay_adjustment = 0; /* special case 1: in Supaplex, Murphy blocks last field one more frame */ if (player->block_last_field && element == EL_SP_MURPHY) player->block_delay_adjustment = 1; /* special case 2: in game engines before 3.1.1, blocking was different */ if (game.use_block_last_field_bug) player->block_delay_adjustment = (player->block_last_field ? -1 : 1); if (!options.network || player->connected) { player->active = TRUE; /* remove potentially duplicate players */ if (StorePlayer[jx][jy] == Feld[x][y]) StorePlayer[jx][jy] = 0; StorePlayer[x][y] = Feld[x][y]; if (options.debug) { printf("Player %d activated.\n", player->element_nr); printf("[Local player is %d and currently %s.]\n", local_player->element_nr, local_player->active ? "active" : "not active"); } } Feld[x][y] = EL_EMPTY; player->jx = player->last_jx = x; player->jy = player->last_jy = y; } #if USE_PLAYER_REANIMATION if (!init_game) { int player_nr = GET_PLAYER_NR(element); struct PlayerInfo *player = &stored_player[player_nr]; if (player->active && player->killed) player->reanimated = TRUE; /* if player was just killed, reanimate him */ } #endif } static void InitField(int x, int y, boolean init_game) { int element = Feld[x][y]; switch (element) { case EL_SP_MURPHY: case EL_PLAYER_1: case EL_PLAYER_2: case EL_PLAYER_3: case EL_PLAYER_4: InitPlayerField(x, y, element, init_game); break; case EL_SOKOBAN_FIELD_PLAYER: element = Feld[x][y] = EL_PLAYER_1; InitField(x, y, init_game); element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY; InitField(x, y, init_game); break; case EL_SOKOBAN_FIELD_EMPTY: local_player->sokobanfields_still_needed++; break; case EL_STONEBLOCK: if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID) Feld[x][y] = EL_ACID_POOL_TOPLEFT; else if (x > 0 && Feld[x-1][y] == EL_ACID) Feld[x][y] = EL_ACID_POOL_TOPRIGHT; else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT) Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT; else if (y > 0 && Feld[x][y-1] == EL_ACID) Feld[x][y] = EL_ACID_POOL_BOTTOM; else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT) Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT; break; case EL_BUG: case EL_BUG_RIGHT: case EL_BUG_UP: case EL_BUG_LEFT: case EL_BUG_DOWN: case EL_SPACESHIP: case EL_SPACESHIP_RIGHT: case EL_SPACESHIP_UP: case EL_SPACESHIP_LEFT: case EL_SPACESHIP_DOWN: case EL_BD_BUTTERFLY: case EL_BD_BUTTERFLY_RIGHT: case EL_BD_BUTTERFLY_UP: case EL_BD_BUTTERFLY_LEFT: case EL_BD_BUTTERFLY_DOWN: case EL_BD_FIREFLY: case EL_BD_FIREFLY_RIGHT: case EL_BD_FIREFLY_UP: case EL_BD_FIREFLY_LEFT: case EL_BD_FIREFLY_DOWN: case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: case EL_YAMYAM: case EL_YAMYAM_LEFT: case EL_YAMYAM_RIGHT: case EL_YAMYAM_UP: case EL_YAMYAM_DOWN: case EL_DARK_YAMYAM: case EL_ROBOT: case EL_PACMAN: case EL_SP_SNIKSNAK: case EL_SP_ELECTRON: case EL_MOLE: case EL_MOLE_LEFT: case EL_MOLE_RIGHT: case EL_MOLE_UP: case EL_MOLE_DOWN: InitMovDir(x, y); break; case EL_AMOEBA_FULL: case EL_BD_AMOEBA: InitAmoebaNr(x, y); break; case EL_AMOEBA_DROP: if (y == lev_fieldy - 1) { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; } break; case EL_DYNAMITE_ACTIVE: case EL_SP_DISK_RED_ACTIVE: case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: case EL_DYNABOMB_PLAYER_4_ACTIVE: MovDelay[x][y] = 96; break; case EL_EM_DYNAMITE_ACTIVE: MovDelay[x][y] = 32; break; case EL_LAMP: local_player->lights_still_needed++; break; case EL_PENGUIN: local_player->friends_still_needed++; break; case EL_PIG: case EL_DRAGON: GfxDir[x][y] = MovDir[x][y] = 1 << RND(4); break; case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_1_SWITCH_RIGHT: case EL_CONVEYOR_BELT_2_SWITCH_LEFT: case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_2_SWITCH_RIGHT: case EL_CONVEYOR_BELT_3_SWITCH_LEFT: case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_3_SWITCH_RIGHT: case EL_CONVEYOR_BELT_4_SWITCH_LEFT: case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_4_SWITCH_RIGHT: if (init_game) { int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]); int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]); int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]); if (game.belt_dir_nr[belt_nr] == 3) /* initial value */ { game.belt_dir[belt_nr] = belt_dir; game.belt_dir_nr[belt_nr] = belt_dir_nr; } else /* more than one switch -- set it like the first switch */ { Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr]; } } break; #if !USE_BOTH_SWITCHGATE_SWITCHES case EL_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */ if (init_game) Feld[x][y] = EL_SWITCHGATE_SWITCH_UP; break; case EL_DC_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */ if (init_game) Feld[x][y] = EL_DC_SWITCHGATE_SWITCH_UP; break; #endif case EL_LIGHT_SWITCH_ACTIVE: if (init_game) game.light_time_left = level.time_light * FRAMES_PER_SECOND; break; case EL_INVISIBLE_STEELWALL: case EL_INVISIBLE_WALL: case EL_INVISIBLE_SAND: if (game.light_time_left > 0 || game.lenses_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); break; case EL_EMC_MAGIC_BALL: if (game.ball_state) Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; break; case EL_EMC_MAGIC_BALL_SWITCH: if (game.ball_state) Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; break; case EL_TRIGGER_PLAYER: case EL_TRIGGER_ELEMENT: case EL_TRIGGER_CE_VALUE: case EL_TRIGGER_CE_SCORE: case EL_SELF: case EL_ANY_ELEMENT: case EL_CURRENT_CE_VALUE: case EL_CURRENT_CE_SCORE: case EL_PREV_CE_1: case EL_PREV_CE_2: case EL_PREV_CE_3: case EL_PREV_CE_4: case EL_PREV_CE_5: case EL_PREV_CE_6: case EL_PREV_CE_7: case EL_PREV_CE_8: case EL_NEXT_CE_1: case EL_NEXT_CE_2: case EL_NEXT_CE_3: case EL_NEXT_CE_4: case EL_NEXT_CE_5: case EL_NEXT_CE_6: case EL_NEXT_CE_7: case EL_NEXT_CE_8: /* reference elements should not be used on the playfield */ Feld[x][y] = EL_EMPTY; break; default: if (IS_CUSTOM_ELEMENT(element)) { if (CAN_MOVE(element)) InitMovDir(x, y); #if USE_NEW_CUSTOM_VALUE if (!element_info[element].use_last_ce_value || init_game) CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); #endif } else if (IS_GROUP_ELEMENT(element)) { Feld[x][y] = GetElementFromGroupElement(element); InitField(x, y, init_game); } break; } if (!init_game) CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); } static inline void InitField_WithBug1(int x, int y, boolean init_game) { InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(Feld[x][y])) InitMovDir(x, y); } static inline void InitField_WithBug2(int x, int y, boolean init_game) { int old_element = Feld[x][y]; InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(old_element) && (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) InitMovDir(x, y); /* this case is in fact a combination of not less than three bugs: first, it calls InitMovDir() for elements that can move, although this is already done by InitField(); then, it checks the element that was at this field _before_ the call to InitField() (which can change it); lastly, it was not called for "mole with direction" elements, which were treated as "cannot move" due to (fixed) wrong element initialization in "src/init.c" */ } #if 1 static int get_key_element_from_nr(int key_nr) { int key_base_element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS : level.game_engine_type == GAME_ENGINE_TYPE_EM ? EL_EM_KEY_1 : EL_KEY_1); return key_base_element + key_nr; } static int get_next_dropped_element(struct PlayerInfo *player) { return (player->inventory_size > 0 ? player->inventory_element[player->inventory_size - 1] : player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left > 0 ? EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); } static int get_inventory_element_from_pos(struct PlayerInfo *player, int pos) { /* pos >= 0: get element from bottom of the stack; pos < 0: get element from top of the stack */ if (pos < 0) { int min_inventory_size = -pos; int inventory_pos = player->inventory_size - min_inventory_size; int min_dynabombs_left = min_inventory_size - player->inventory_size; return (player->inventory_size >= min_inventory_size ? player->inventory_element[inventory_pos] : player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left >= min_dynabombs_left ? EL_DYNABOMB_PLAYER_1 + player->index_nr : EL_UNDEFINED); } else { int min_dynabombs_left = pos + 1; int min_inventory_size = pos + 1 - player->dynabombs_left; int inventory_pos = pos - player->dynabombs_left; return (player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left >= min_dynabombs_left ? EL_DYNABOMB_PLAYER_1 + player->index_nr : player->inventory_size >= min_inventory_size ? player->inventory_element[inventory_pos] : EL_UNDEFINED); } } static int compareGamePanelOrderInfo(const void *object1, const void *object2) { const struct GamePanelOrderInfo *gpo1 = (struct GamePanelOrderInfo *)object1; const struct GamePanelOrderInfo *gpo2 = (struct GamePanelOrderInfo *)object2; int compare_result; if (gpo1->sort_priority != gpo2->sort_priority) compare_result = gpo1->sort_priority - gpo2->sort_priority; else compare_result = gpo1->nr - gpo2->nr; return compare_result; } void InitGameControlValues() { int i; for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; struct GamePanelOrderInfo *gpo = &game_panel_order[i]; struct TextPosInfo *pos = gpc->pos; int nr = gpc->nr; int type = gpc->type; if (nr != i) { Error(ERR_INFO, "'game_panel_controls' structure corrupted at %d", i); Error(ERR_EXIT, "this should not happen -- please debug"); } /* force update of game controls after initialization */ gpc->value = gpc->last_value = -1; gpc->frame = gpc->last_frame = -1; gpc->gfx_frame = -1; /* determine panel value width for later calculation of alignment */ if (type == TYPE_INTEGER || type == TYPE_STRING) { pos->width = pos->size * getFontWidth(pos->font); pos->height = getFontHeight(pos->font); } else if (type == TYPE_ELEMENT) { pos->width = pos->size; pos->height = pos->size; } /* fill structure for game panel draw order */ gpo->nr = gpc->nr; gpo->sort_priority = pos->sort_priority; } /* sort game panel controls according to sort_priority and control number */ qsort(game_panel_order, NUM_GAME_PANEL_CONTROLS, sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo); } void UpdatePlayfieldElementCount() { boolean use_element_count = FALSE; int i, j, x, y; /* first check if it is needed at all to calculate playfield element count */ for (i = GAME_PANEL_ELEMENT_COUNT_1; i <= GAME_PANEL_ELEMENT_COUNT_8; i++) if (!PANEL_DEACTIVATED(game_panel_controls[i].pos)) use_element_count = TRUE; if (!use_element_count) return; for (i = 0; i < MAX_NUM_ELEMENTS; i++) element_info[i].element_count = 0; SCAN_PLAYFIELD(x, y) { element_info[Feld[x][y]].element_count++; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (IS_IN_GROUP(j, i)) element_info[EL_GROUP_START + i].element_count += element_info[j].element_count; } void UpdateGameControlValues() { int i, k; int time = (local_player->LevelSolved ? local_player->LevelSolved_CountingTime : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->time : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->time_played : level.time == 0 ? TimePlayed : TimeLeft); int score = (local_player->LevelSolved ? local_player->LevelSolved_CountingScore : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->score : local_player->score); int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->infotrons_still_needed : local_player->gems_still_needed); int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required > 0 : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->infotrons_still_needed > 0 : local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0); UpdatePlayfieldElementCount(); /* update game panel control values */ game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr; game_panel_controls[GAME_PANEL_GEMS].value = gems; game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0; for (i = 0; i < MAX_NUM_KEYS; i++) game_panel_controls[GAME_PANEL_KEY_1 + i].value = EL_EMPTY; game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_EMPTY; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value = 0; if (game.centered_player_nr == -1) { for (i = 0; i < MAX_PLAYERS; i++) { /* only one player in Supaplex game engine */ if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0) break; for (k = 0; k < MAX_NUM_KEYS; k++) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->ply[i]->keys & (1 << k)) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } else if (stored_player[i].key[k]) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } if (level.game_engine_type == GAME_ENGINE_TYPE_EM) game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += level.native_em_level->ply[i]->dynamite; else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += level.native_sp_level->game_sp->red_disk_count; else game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += stored_player[i].inventory_size; if (stored_player[i].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[i].num_white_keys; } } else { int player_nr = game.centered_player_nr; for (k = 0; k < MAX_NUM_KEYS; k++) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->ply[player_nr]->keys & (1 << k)) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } else if (stored_player[player_nr].key[k]) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } if (level.game_engine_type == GAME_ENGINE_TYPE_EM) game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += level.native_em_level->ply[player_nr]->dynamite; else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += level.native_sp_level->game_sp->red_disk_count; else game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += stored_player[player_nr].inventory_size; if (stored_player[player_nr].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[player_nr].num_white_keys; } for (i = 0; i < NUM_PANEL_INVENTORY; i++) { game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value = get_inventory_element_from_pos(local_player, i); game_panel_controls[GAME_PANEL_INVENTORY_LAST_1 + i].value = get_inventory_element_from_pos(local_player, -i - 1); } game_panel_controls[GAME_PANEL_SCORE].value = score; game_panel_controls[GAME_PANEL_HIGHSCORE].value = highscore[0].Score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_TIME_HH].value = time / 3600; game_panel_controls[GAME_PANEL_TIME_MM].value = (time / 60) % 60; game_panel_controls[GAME_PANEL_TIME_SS].value = time % 60; game_panel_controls[GAME_PANEL_FRAME].value = FrameCounter; game_panel_controls[GAME_PANEL_SHIELD_NORMAL].value = (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE : EL_EMPTY); game_panel_controls[GAME_PANEL_SHIELD_NORMAL_TIME].value = local_player->shield_normal_time_left; game_panel_controls[GAME_PANEL_SHIELD_DEADLY].value = (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE : EL_EMPTY); game_panel_controls[GAME_PANEL_SHIELD_DEADLY_TIME].value = local_player->shield_deadly_time_left; game_panel_controls[GAME_PANEL_EXIT].value = (exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN); game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL].value = (game.ball_state ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL); game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL_SWITCH].value = (game.ball_state ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE : EL_EMC_MAGIC_BALL_SWITCH); game_panel_controls[GAME_PANEL_LIGHT_SWITCH].value = (game.light_time_left > 0 ? EL_LIGHT_SWITCH_ACTIVE : EL_LIGHT_SWITCH); game_panel_controls[GAME_PANEL_LIGHT_SWITCH_TIME].value = game.light_time_left; game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH].value = (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED); game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH_TIME].value = game.timegate_time_left; game_panel_controls[GAME_PANEL_SWITCHGATE_SWITCH].value = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; game_panel_controls[GAME_PANEL_EMC_LENSES].value = (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY); game_panel_controls[GAME_PANEL_EMC_LENSES_TIME].value = game.lenses_time_left; game_panel_controls[GAME_PANEL_EMC_MAGNIFIER].value = (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY); game_panel_controls[GAME_PANEL_EMC_MAGNIFIER_TIME].value = game.magnify_time_left; game_panel_controls[GAME_PANEL_BALLOON_SWITCH].value = (game.wind_direction == MV_LEFT ? EL_BALLOON_SWITCH_LEFT : game.wind_direction == MV_RIGHT ? EL_BALLOON_SWITCH_RIGHT : game.wind_direction == MV_UP ? EL_BALLOON_SWITCH_UP : game.wind_direction == MV_DOWN ? EL_BALLOON_SWITCH_DOWN : EL_BALLOON_SWITCH_NONE); game_panel_controls[GAME_PANEL_DYNABOMB_NUMBER].value = local_player->dynabomb_count; game_panel_controls[GAME_PANEL_DYNABOMB_SIZE].value = local_player->dynabomb_size; game_panel_controls[GAME_PANEL_DYNABOMB_POWER].value = (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY); game_panel_controls[GAME_PANEL_PENGUINS].value = local_player->friends_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = local_player->sokobanfields_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = local_player->sokobanfields_still_needed; game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); for (i = 0; i < NUM_BELTS; i++) { game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1 + i].value = (game.belt_dir[i] != MV_NONE ? EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE : EL_CONVEYOR_BELT_1_MIDDLE) + i; game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1_SWITCH + i].value = getBeltSwitchElementFromBeltNrAndBeltDir(i, game.belt_dir[i]); } game_panel_controls[GAME_PANEL_MAGIC_WALL].value = (game.magic_wall_active ? EL_MAGIC_WALL_ACTIVE : EL_MAGIC_WALL); game_panel_controls[GAME_PANEL_MAGIC_WALL_TIME].value = game.magic_wall_time_left; #if USE_PLAYER_GRAVITY game_panel_controls[GAME_PANEL_GRAVITY_STATE].value = local_player->gravity; #else game_panel_controls[GAME_PANEL_GRAVITY_STATE].value = game.gravity; #endif for (i = 0; i < NUM_PANEL_GRAPHICS; i++) game_panel_controls[GAME_PANEL_GRAPHIC_1 + i].value = EL_GRAPHIC_1 + i; for (i = 0; i < NUM_PANEL_ELEMENTS; i++) game_panel_controls[GAME_PANEL_ELEMENT_1 + i].value = (IS_DRAWABLE_ELEMENT(game.panel.element[i].id) ? game.panel.element[i].id : EL_UNDEFINED); for (i = 0; i < NUM_PANEL_ELEMENTS; i++) game_panel_controls[GAME_PANEL_ELEMENT_COUNT_1 + i].value = (IS_VALID_ELEMENT(game.panel.element_count[i].id) ? element_info[game.panel.element_count[i].id].element_count : 0); for (i = 0; i < NUM_PANEL_CE_SCORE; i++) game_panel_controls[GAME_PANEL_CE_SCORE_1 + i].value = (IS_CUSTOM_ELEMENT(game.panel.ce_score[i].id) ? element_info[game.panel.ce_score[i].id].collect_score : 0); for (i = 0; i < NUM_PANEL_CE_SCORE; i++) game_panel_controls[GAME_PANEL_CE_SCORE_1_ELEMENT + i].value = (IS_CUSTOM_ELEMENT(game.panel.ce_score_element[i].id) ? element_info[game.panel.ce_score_element[i].id].collect_score : EL_UNDEFINED); game_panel_controls[GAME_PANEL_PLAYER_NAME].value = 0; game_panel_controls[GAME_PANEL_LEVEL_NAME].value = 0; game_panel_controls[GAME_PANEL_LEVEL_AUTHOR].value = 0; /* update game panel control frames */ for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; if (gpc->type == TYPE_ELEMENT) { if (gpc->value != EL_UNDEFINED && gpc->value != EL_EMPTY) { int last_anim_random_frame = gfx.anim_random_frame; int element = gpc->value; int graphic = el2panelimg(element); if (gpc->value != gpc->last_value) { gpc->gfx_frame = 0; gpc->gfx_random = INIT_GFX_RANDOM(); } else { gpc->gfx_frame++; if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(gpc->gfx_frame, graphic)) gpc->gfx_random = INIT_GFX_RANDOM(); } if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = gpc->gfx_random; if (ANIM_MODE(graphic) == ANIM_CE_SCORE) gpc->gfx_frame = element_info[element].collect_score; gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value), gpc->gfx_frame); if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = last_anim_random_frame; } } } } void DisplayGameControlValues() { boolean redraw_panel = FALSE; int i; for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; if (PANEL_DEACTIVATED(gpc->pos)) continue; if (gpc->value == gpc->last_value && gpc->frame == gpc->last_frame) continue; redraw_panel = TRUE; } if (!redraw_panel) return; /* copy default game door content to main double buffer */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); /* redraw game control buttons */ #if 1 RedrawGameButtons(); #else UnmapGameButtons(); MapGameButtons(); #endif game_status = GAME_MODE_PSEUDO_PANEL; #if 1 for (i = 0; i < NUM_GAME_PANEL_CONTROLS; i++) #else for (i = 0; game_panel_controls[i].nr != -1; i++) #endif { #if 1 int nr = game_panel_order[i].nr; struct GamePanelControlInfo *gpc = &game_panel_controls[nr]; #else struct GamePanelControlInfo *gpc = &game_panel_controls[i]; int nr = gpc->nr; #endif struct TextPosInfo *pos = gpc->pos; int type = gpc->type; int value = gpc->value; int frame = gpc->frame; #if 0 int last_value = gpc->last_value; int last_frame = gpc->last_frame; #endif int size = pos->size; int font = pos->font; boolean draw_masked = pos->draw_masked; int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_OPAQUE); if (PANEL_DEACTIVATED(pos)) continue; #if 0 if (value == last_value && frame == last_frame) continue; #endif gpc->last_value = value; gpc->last_frame = frame; #if 0 printf("::: value %d changed from %d to %d\n", nr, last_value, value); #endif if (type == TYPE_INTEGER) { if (nr == GAME_PANEL_LEVEL_NUMBER || nr == GAME_PANEL_TIME) { boolean use_dynamic_size = (size == -1 ? TRUE : FALSE); if (use_dynamic_size) /* use dynamic number of digits */ { int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000); int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3); int size2 = size1 + 1; int font1 = pos->font; int font2 = pos->font_alt; size = (value < value_change ? size1 : size2); font = (value < value_change ? font1 : font2); #if 0 /* clear background if value just changed its size (dynamic digits) */ if ((last_value < value_change) != (value < value_change)) { int width1 = size1 * getFontWidth(font1); int width2 = size2 * getFontWidth(font2); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); pos->width = max_width; ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), max_width, max_height); } #endif } } #if 1 /* correct text size if "digits" is zero or less */ if (size <= 0) size = strlen(int2str(value, size)); /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); #endif DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, size), font, mask_mode); } else if (type == TYPE_ELEMENT) { int element, graphic; Bitmap *src_bitmap; int src_x, src_y; int width, height; int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); #if 1 if (value != EL_UNDEFINED && value != EL_EMPTY) { element = value; graphic = el2panelimg(value); // printf("::: %d, '%s' [%d]\n", element, EL_NAME(element), size); #if 1 if (element >= EL_GRAPHIC_1 && element <= EL_GRAPHIC_8 && size == 0) size = TILESIZE; #endif getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x, &src_y); width = graphic_info[graphic].width * size / TILESIZE; height = graphic_info[graphic].height * size / TILESIZE; if (draw_masked) { SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } else { BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } } #else if (value == EL_UNDEFINED || value == EL_EMPTY) { element = (last_value == EL_UNDEFINED ? EL_EMPTY : last_value); graphic = el2panelimg(element); src_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; src_x = DOOR_GFX_PAGEX5 + ALIGNED_TEXT_XPOS(pos); src_y = DOOR_GFX_PAGEY1 + ALIGNED_TEXT_YPOS(pos); } else { element = value; graphic = el2panelimg(value); getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x,&src_y); } width = graphic_info[graphic].width * size / TILESIZE; height = graphic_info[graphic].height * size / TILESIZE; BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); #endif } else if (type == TYPE_STRING) { boolean active = (value != 0); char *state_normal = "off"; char *state_active = "on"; char *state = (active ? state_active : state_normal); char *s = (nr == GAME_PANEL_GRAVITY_STATE ? state : nr == GAME_PANEL_PLAYER_NAME ? setup.player_name : nr == GAME_PANEL_LEVEL_NAME ? level.name : nr == GAME_PANEL_LEVEL_AUTHOR ? level.author : NULL); if (nr == GAME_PANEL_GRAVITY_STATE) { int font1 = pos->font; /* (used for normal state) */ int font2 = pos->font_alt; /* (used for active state) */ #if 0 int size1 = strlen(state_normal); int size2 = strlen(state_active); int width1 = size1 * getFontWidth(font1); int width2 = size2 * getFontWidth(font2); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); pos->width = max_width; /* clear background for values that may have changed its size */ ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), max_width, max_height); #endif font = (active ? font2 : font1); } if (s != NULL) { char *s_cut; #if 1 if (size <= 0) { /* don't truncate output if "chars" is zero or less */ size = strlen(s); /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); } #endif s_cut = getStringCopyN(s, size); DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), s_cut, font, mask_mode); free(s_cut); } } redraw_mask |= REDRAW_DOOR_1; } game_status = GAME_MODE_PLAYING; } void UpdateAndDisplayGameControlValues() { if (tape.warp_forward) return; UpdateGameControlValues(); DisplayGameControlValues(); } void DrawGameValue_Emeralds(int value) { struct TextPosInfo *pos = &game.panel.gems; #if 1 int font_nr = pos->font; #else int font_nr = FONT_TEXT_2; #endif int font_width = getFontWidth(font_nr); int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ #endif if (PANEL_DEACTIVATED(pos)) return; pos->width = chars * font_width; DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Dynamite(int value) { struct TextPosInfo *pos = &game.panel.inventory_count; #if 1 int font_nr = pos->font; #else int font_nr = FONT_TEXT_2; #endif int font_width = getFontWidth(font_nr); int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ #endif if (PANEL_DEACTIVATED(pos)) return; pos->width = chars * font_width; DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Score(int value) { struct TextPosInfo *pos = &game.panel.score; #if 1 int font_nr = pos->font; #else int font_nr = FONT_TEXT_2; #endif int font_width = getFontWidth(font_nr); int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ #endif if (PANEL_DEACTIVATED(pos)) return; pos->width = chars * font_width; DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Time(int value) { struct TextPosInfo *pos = &game.panel.time; static int last_value = -1; int chars1 = 3; int chars2 = 4; int chars = pos->size; #if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; #else int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; #endif int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); #if 1 return; /* !!! USE NEW STUFF !!! */ #endif if (PANEL_DEACTIVATED(pos)) return; if (use_dynamic_chars) /* use dynamic number of chars */ { chars = (value < 1000 ? chars1 : chars2); font_nr = (value < 1000 ? font1_nr : font2_nr); } /* clear background if value just changed its size (dynamic chars only) */ if (use_dynamic_chars && (last_value < 1000) != (value < 1000)) { int width1 = chars1 * getFontWidth(font1_nr); int width2 = chars2 * getFontWidth(font2_nr); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1_nr), getFontHeight(font2_nr)); pos->width = max_width; ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), max_width, max_height); } pos->width = chars * getFontWidth(font_nr); DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); last_value = value; } void DrawGameValue_Level(int value) { struct TextPosInfo *pos = &game.panel.level_number; int chars1 = 2; int chars2 = 3; int chars = pos->size; #if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; #else int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; #endif int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); #if 1 return; /* !!! USE NEW STUFF !!! */ #endif if (PANEL_DEACTIVATED(pos)) return; if (use_dynamic_chars) /* use dynamic number of chars */ { chars = (level_nr < 100 ? chars1 : chars2); font_nr = (level_nr < 100 ? font1_nr : font2_nr); } pos->width = chars * getFontWidth(font_nr); DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) { #if 0 struct TextPosInfo *pos = &game.panel.keys; #endif #if 0 int base_key_graphic = EL_KEY_1; #endif int i; #if 1 return; /* !!! USE NEW STUFF !!! */ #endif #if 0 if (PANEL_DEACTIVATED(pos)) return; #endif #if 0 if (level.game_engine_type == GAME_ENGINE_TYPE_EM) base_key_graphic = EL_EM_KEY_1; #endif #if 0 pos->width = 4 * MINI_TILEX; #endif #if 1 for (i = 0; i < MAX_NUM_KEYS; i++) #else /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) #endif { #if 1 struct TextPosInfo *pos = &game.panel.key[i]; #endif int src_x = DOOR_GFX_PAGEX5 + 18 + (i % 4) * MINI_TILEX; int src_y = DOOR_GFX_PAGEY1 + 123; #if 1 int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); #else int dst_x = PANEL_XPOS(pos) + i * MINI_TILEX; int dst_y = PANEL_YPOS(pos); #endif #if 1 int element = (i >= STD_NUM_KEYS ? EL_EMC_KEY_5 - 4 : level.game_engine_type == GAME_ENGINE_TYPE_EM ? EL_EM_KEY_1 : EL_KEY_1) + i; int graphic = el2edimg(element); #endif #if 1 if (PANEL_DEACTIVATED(pos)) continue; #endif #if 0 /* masked blit with tiles from half-size scaled bitmap does not work yet (no mask bitmap created for these sizes after loading and scaling) -- solution: load without creating mask, scale, then create final mask */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); if (key[i]) { #if 0 int graphic = el2edimg(base_key_graphic + i); #endif Bitmap *src_bitmap; int src_x, src_y; getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); } #else #if 1 if (key[i]) DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); #else if (key[i]) DrawMiniGraphicExt(drawto, dst_x, dst_y, el2edimg(base_key_graphic + i)); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); #endif #endif } } #else void DrawGameValue_Emeralds(int value) { int font_nr = FONT_TEXT_2; int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.gems)) return; DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), font_nr); } void DrawGameValue_Dynamite(int value) { int font_nr = FONT_TEXT_2; int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.inventory_count)) return; DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); } void DrawGameValue_Score(int value) { int font_nr = FONT_TEXT_2; int xpos = (5 * 14 - 5 * getFontWidth(font_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.score)) return; DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), font_nr); } void DrawGameValue_Time(int value) { int font1_nr = FONT_TEXT_2; #if 1 int font2_nr = FONT_TEXT_1; #else int font2_nr = FONT_LEVEL_NUMBER; #endif int xpos3 = (3 * 14 - 3 * getFontWidth(font1_nr)) / 2; int xpos4 = (4 * 10 - 4 * getFontWidth(font2_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.time)) return; /* clear background if value just changed its size */ if (value == 999 || value == 1000) ClearRectangleOnBackground(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); if (value < 1000) DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), font1_nr); else DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), font2_nr); } void DrawGameValue_Level(int value) { int font1_nr = FONT_TEXT_2; #if 1 int font2_nr = FONT_TEXT_1; #else int font2_nr = FONT_LEVEL_NUMBER; #endif if (PANEL_DEACTIVATED(game.panel.level)) return; if (level_nr < 100) DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), font1_nr); else DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), font2_nr); } void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) { int base_key_graphic = EL_KEY_1; int i; if (PANEL_DEACTIVATED(game.panel.keys)) return; if (level.game_engine_type == GAME_ENGINE_TYPE_EM) base_key_graphic = EL_EM_KEY_1; /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) { int x = XX_KEYS + i * MINI_TILEX; int y = YY_KEYS; if (key[i]) DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); } } #endif void DrawAllGameValues(int emeralds, int dynamite, int score, int time, int key_bits) { int key[MAX_NUM_KEYS]; int i; /* prevent EM engine from updating time/score values parallel to GameWon() */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM && local_player->LevelSolved) return; for (i = 0; i < MAX_NUM_KEYS; i++) key[i] = key_bits & (1 << i); DrawGameValue_Level(level_nr); DrawGameValue_Emeralds(emeralds); DrawGameValue_Dynamite(dynamite); DrawGameValue_Score(score); DrawGameValue_Time(time); DrawGameValue_Keys(key); } void UpdateGameDoorValues() { UpdateGameControlValues(); } void DrawGameDoorValues() { DisplayGameControlValues(); } void DrawGameDoorValues_OLD() { int time_value = (level.time == 0 ? TimePlayed : TimeLeft); int dynamite_value = 0; int score_value = (local_player->LevelSolved ? local_player->score_final : local_player->score); int gems_value = local_player->gems_still_needed; int key_bits = 0; int i, j; if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { DrawGameDoorValues_EM(); return; } if (game.centered_player_nr == -1) { for (i = 0; i < MAX_PLAYERS; i++) { for (j = 0; j < MAX_NUM_KEYS; j++) if (stored_player[i].key[j]) key_bits |= (1 << j); dynamite_value += stored_player[i].inventory_size; } } else { int player_nr = game.centered_player_nr; for (i = 0; i < MAX_NUM_KEYS; i++) if (stored_player[player_nr].key[i]) key_bits |= (1 << i); dynamite_value = stored_player[player_nr].inventory_size; } DrawAllGameValues(gems_value, dynamite_value, score_value, time_value, key_bits); } /* ============================================================================= InitGameEngine() ----------------------------------------------------------------------------- initialize game engine due to level / tape version number ============================================================================= */ static void InitGameEngine() { int i, j, k, l, x, y; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : level.game_version); /* ---------------------------------------------------------------------- */ /* set flags for bugs and changes according to active game engine version */ /* ---------------------------------------------------------------------- */ /* Summary of bugfix/change: Fixed handling for custom elements that change when pushed by the player. Fixed/changed in version: 3.1.0 Description: Before 3.1.0, custom elements that "change when pushing" changed directly after the player started pushing them (until then handled in "DigField()"). Since 3.1.0, these custom elements are not changed until the "pushing" move of the element is finished (now handled in "ContinueMoving()"). Affected levels/tapes: The first condition is generally needed for all levels/tapes before version 3.1.0, which might use the old behaviour before it was changed; known tapes that are affected are some tapes from the level set "Walpurgis Gardens" by Jamie Cullen. The second condition is an exception from the above case and is needed for the special case of tapes recorded with game (not engine!) version 3.1.0 or above (including some development versions of 3.1.0), but before it was known that this change would break tapes like the above and was fixed in 3.1.1, so that the changed behaviour was active although the engine version while recording maybe was before 3.1.0. There is at least one tape that is affected by this exception, which is the tape for the one-level set "Bug Machine" by Juergen Bonhagen. */ game.use_change_when_pushing_bug = (game.engine_version < VERSION_IDENT(3,1,0,0) && !(tape.playing && tape.game_version >= VERSION_IDENT(3,1,0,0) && tape.game_version < VERSION_IDENT(3,1,1,0))); /* Summary of bugfix/change: Fixed handling for blocking the field the player leaves when moving. Fixed/changed in version: 3.1.1 Description: Before 3.1.1, when "block last field when moving" was enabled, the field the player is leaving when moving was blocked for the time of the move, and was directly unblocked afterwards. This resulted in the last field being blocked for exactly one less than the number of frames of one player move. Additionally, even when blocking was disabled, the last field was blocked for exactly one frame. Since 3.1.1, due to changes in player movement handling, the last field is not blocked at all when blocking is disabled. When blocking is enabled, the last field is blocked for exactly the number of frames of one player move. Additionally, if the player is Murphy, the hero of Supaplex, the last field is blocked for exactly one more than the number of frames of one player move. Affected levels/tapes: (!!! yet to be determined -- probably many !!!) */ game.use_block_last_field_bug = (game.engine_version < VERSION_IDENT(3,1,1,0)); /* Summary of bugfix/change: Changed behaviour of CE changes with multiple changes per single frame. Fixed/changed in version: 3.2.0-6 Description: Before 3.2.0-6, only one single CE change was allowed in each engine frame. This resulted in race conditions where CEs seem to behave strange in some situations (where triggered CE changes were just skipped because there was already a CE change on that tile in the playfield in that engine frame). Since 3.2.0-6, this was changed to allow up to MAX_NUM_CHANGES_PER_FRAME. (The number of changes per frame must be limited in any case, because else it is easily possible to define CE changes that would result in an infinite loop, causing the whole game to freeze. The MAX_NUM_CHANGES_PER_FRAME value should be set large enough so that it would only be reached in cases where the corresponding CE change conditions run into a loop. Therefore, it seems to be reasonable to set MAX_NUM_CHANGES_PER_FRAME to the same value as the maximal number of change pages for custom elements.) Affected levels/tapes: Probably many. */ #if USE_ONLY_ONE_CHANGE_PER_FRAME game.max_num_changes_per_frame = 1; #else game.max_num_changes_per_frame = (game.engine_version < VERSION_IDENT(3,2,0,6) ? 1 : 32); #endif /* ---------------------------------------------------------------------- */ /* default scan direction: scan playfield from top/left to bottom/right */ InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL); /* dynamically adjust element properties according to game engine version */ InitElementPropertiesEngine(game.engine_version); #if 0 printf("level %d: level version == %06d\n", level_nr, level.game_version); printf(" tape version == %06d [%s] [file: %06d]\n", tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"), tape.file_version); printf(" => game.engine_version == %06d\n", game.engine_version); #endif /* ---------- initialize player's initial move delay --------------------- */ /* dynamically adjust player properties according to level information */ for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay_value[i] = get_move_delay_from_stepsize(level.initial_player_stepsize[i]); /* dynamically adjust player properties according to game engine version */ for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay[i] = (game.engine_version <= VERSION_IDENT(2,0,1,0) ? game.initial_move_delay_value[i] : 0); /* ---------- initialize player's initial push delay --------------------- */ /* dynamically adjust player properties according to game engine version */ game.initial_push_delay_value = (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1); /* ---------- initialize changing elements ------------------------------- */ /* initialize changing elements information */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; /* this pointer might have been changed in the level editor */ ei->change = &ei->change_page[0]; if (!IS_CUSTOM_ELEMENT(i)) { ei->change->target_element = EL_EMPTY_SPACE; ei->change->delay_fixed = 0; ei->change->delay_random = 0; ei->change->delay_frames = 1; } for (j = 0; j < NUM_CHANGE_EVENTS; j++) { ei->has_change_event[j] = FALSE; ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; } } /* add changing elements from pre-defined list */ for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++) { struct ChangingElementInfo *ch_delay = &change_delay_list[i]; struct ElementInfo *ei = &element_info[ch_delay->element]; ei->change->target_element = ch_delay->target_element; ei->change->delay_fixed = ch_delay->change_delay; ei->change->pre_change_function = ch_delay->pre_change_function; ei->change->change_function = ch_delay->change_function; ei->change->post_change_function = ch_delay->post_change_function; ei->change->can_change = TRUE; ei->change->can_change_or_has_action = TRUE; ei->has_change_event[CE_DELAY] = TRUE; SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE); SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE); } /* ---------- initialize internal run-time variables --------------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].can_change_or_has_action = (ei->change_page[j].can_change | ei->change_page[j].has_action); } } /* add change events from custom element configuration */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change_or_has_action) continue; for (k = 0; k < NUM_CHANGE_EVENTS; k++) { /* only add event page for the first page found with this event */ if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k])) { ei->has_change_event[k] = TRUE; ei->event_page_nr[k] = j; ei->event_page[k] = &ei->change_page[j]; } } } } #if 1 /* ---------- initialize reference elements in change conditions --------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { int trigger_element = ei->change_page[j].initial_trigger_element; if (trigger_element >= EL_PREV_CE_8 && trigger_element <= EL_NEXT_CE_8) trigger_element = RESOLVED_REFERENCE_ELEMENT(element, trigger_element); ei->change_page[j].trigger_element = trigger_element; } } #endif /* ---------- initialize run-time trigger player and element ------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].actual_trigger_element = EL_EMPTY; ei->change_page[j].actual_trigger_player = EL_EMPTY; ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE; ei->change_page[j].actual_trigger_side = CH_SIDE_NONE; ei->change_page[j].actual_trigger_ce_value = 0; ei->change_page[j].actual_trigger_ce_score = 0; } } /* ---------- initialize trigger events ---------------------------------- */ /* initialize trigger events information */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_CHANGE_EVENTS; j++) trigger_events[i][j] = FALSE; /* add trigger events from element change event properties */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change_or_has_action) continue; if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION]) { int trigger_element = ei->change_page[j].trigger_element; for (k = 0; k < NUM_CHANGE_EVENTS; k++) { if (ei->change_page[j].has_event[k]) { if (IS_GROUP_ELEMENT(trigger_element)) { struct ElementGroupInfo *group = element_info[trigger_element].group; for (l = 0; l < group->num_elements_resolved; l++) trigger_events[group->element_resolved[l]][k] = TRUE; } else if (trigger_element == EL_ANY_ELEMENT) for (l = 0; l < MAX_NUM_ELEMENTS; l++) trigger_events[l][k] = TRUE; else trigger_events[trigger_element][k] = TRUE; } } } } } /* ---------- initialize push delay -------------------------------------- */ /* initialize push delay values to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { /* set default push delay values (corrected since version 3.0.7-1) */ if (game.engine_version < VERSION_IDENT(3,0,7,1)) { element_info[i].push_delay_fixed = 2; element_info[i].push_delay_random = 8; } else { element_info[i].push_delay_fixed = 8; element_info[i].push_delay_random = 8; } } } /* set push delay value for certain elements from pre-defined list */ for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++) { int e = push_delay_list[i].element; element_info[e].push_delay_fixed = push_delay_list[i].push_delay_fixed; element_info[e].push_delay_random = push_delay_list[i].push_delay_random; } /* set push delay value for Supaplex elements for newer engine versions */ if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_SP_ELEMENT(i)) { /* set SP push delay to just enough to push under a falling zonk */ int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6); element_info[i].push_delay_fixed = delay; element_info[i].push_delay_random = 0; } } } /* ---------- initialize move stepsize ----------------------------------- */ /* initialize move stepsize values to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL; /* set move stepsize value for certain elements from pre-defined list */ for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++) { int e = move_stepsize_list[i].element; element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; } /* ---------- initialize collect score ----------------------------------- */ /* initialize collect score values for custom elements from initial value */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (IS_CUSTOM_ELEMENT(i)) element_info[i].collect_score = element_info[i].collect_score_initial; /* ---------- initialize collect count ----------------------------------- */ /* initialize collect count values for non-custom elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].collect_count_initial = 0; /* add collect count values for all elements from pre-defined list */ for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++) element_info[collect_count_list[i].element].collect_count_initial = collect_count_list[i].count; /* ---------- initialize access direction -------------------------------- */ /* initialize access direction values to default (access from every side) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].access_direction = MV_ALL_DIRECTIONS; /* set access direction value for certain elements from pre-defined list */ for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++) element_info[access_direction_list[i].element].access_direction = access_direction_list[i].direction; /* ---------- initialize explosion content ------------------------------- */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_CUSTOM_ELEMENT(i)) continue; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */ element_info[i].content.e[x][y] = (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW : i == EL_PLAYER_2 ? EL_EMERALD_RED : i == EL_PLAYER_3 ? EL_EMERALD : i == EL_PLAYER_4 ? EL_EMERALD_PURPLE : i == EL_MOLE ? EL_EMERALD_RED : i == EL_PENGUIN ? EL_EMERALD_PURPLE : i == EL_BUG ? (x == 1 && y == 1 ? EL_DIAMOND : EL_EMERALD) : i == EL_BD_BUTTERFLY ? EL_BD_DIAMOND : i == EL_SP_ELECTRON ? EL_SP_INFOTRON : i == EL_AMOEBA_TO_DIAMOND ? level.amoeba_content : i == EL_WALL_EMERALD ? EL_EMERALD : i == EL_WALL_DIAMOND ? EL_DIAMOND : i == EL_WALL_BD_DIAMOND ? EL_BD_DIAMOND : i == EL_WALL_EMERALD_YELLOW ? EL_EMERALD_YELLOW : i == EL_WALL_EMERALD_RED ? EL_EMERALD_RED : i == EL_WALL_EMERALD_PURPLE ? EL_EMERALD_PURPLE : i == EL_WALL_PEARL ? EL_PEARL : i == EL_WALL_CRYSTAL ? EL_CRYSTAL : EL_EMPTY); } } /* ---------- initialize recursion detection ------------------------------ */ recursion_loop_depth = 0; recursion_loop_detected = FALSE; recursion_loop_element = EL_UNDEFINED; /* ---------- initialize graphics engine ---------------------------------- */ game.scroll_delay_value = (game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value : setup.scroll_delay ? setup.scroll_delay_value : 0); game.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); } int get_num_special_action(int element, int action_first, int action_last) { int num_special_action = 0; int i, j; for (i = action_first; i <= action_last; i++) { boolean found = FALSE; for (j = 0; j < NUM_DIRECTIONS; j++) if (el_act_dir2img(element, i, j) != el_act_dir2img(element, ACTION_DEFAULT, j)) found = TRUE; if (found) num_special_action++; else break; } return num_special_action; } /* ============================================================================= InitGame() ----------------------------------------------------------------------------- initialize and start new game ============================================================================= */ void InitGame() { boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ #if 0 boolean do_fading = (game_status == GAME_MODE_MAIN); #endif #if 1 int initial_move_dir = MV_DOWN; #else int initial_move_dir = MV_NONE; #endif int i, j, x, y; game_status = GAME_MODE_PLAYING; #if 1 /* needed if different viewport properties defined for playing */ ChangeViewportPropertiesIfNeeded(); #endif #if 1 DrawCompleteVideoDisplay(); #endif InitGameEngine(); InitGameControlValues(); /* don't play tapes over network */ network_playing = (options.network && !tape.playing); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; player->index_nr = i; player->index_bit = (1 << i); player->element_nr = EL_PLAYER_1 + i; player->present = FALSE; player->active = FALSE; player->mapped = FALSE; player->killed = FALSE; player->reanimated = FALSE; player->action = 0; player->effective_action = 0; player->programmed_action = 0; player->score = 0; player->score_final = 0; player->gems_still_needed = level.gems_needed; player->sokobanfields_still_needed = 0; player->lights_still_needed = 0; player->friends_still_needed = 0; for (j = 0; j < MAX_NUM_KEYS; j++) player->key[j] = FALSE; player->num_white_keys = 0; player->dynabomb_count = 0; player->dynabomb_size = 1; player->dynabombs_left = 0; player->dynabomb_xl = FALSE; player->MovDir = initial_move_dir; player->MovPos = 0; player->GfxPos = 0; player->GfxDir = initial_move_dir; player->GfxAction = ACTION_DEFAULT; player->Frame = 0; player->StepFrame = 0; player->initial_element = player->element_nr; player->artwork_element = (level.use_artwork_element[i] ? level.artwork_element[i] : player->element_nr); player->use_murphy = FALSE; player->block_last_field = FALSE; /* initialized in InitPlayerField() */ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ player->gravity = level.initial_player_gravity[i]; player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr); player->actual_frame_counter = 0; player->step_counter = 0; player->last_move_dir = initial_move_dir; player->is_active = FALSE; player->is_waiting = FALSE; player->is_moving = FALSE; player->is_auto_moving = FALSE; player->is_digging = FALSE; player->is_snapping = FALSE; player->is_collecting = FALSE; player->is_pushing = FALSE; player->is_switching = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->is_bored = FALSE; player->is_sleeping = FALSE; player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; player->anim_delay_counter = 0; player->post_delay_counter = 0; player->dir_waiting = initial_move_dir; player->action_waiting = ACTION_DEFAULT; player->last_action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; player->special_action_sleeping = ACTION_DEFAULT; player->switch_x = -1; player->switch_y = -1; player->drop_x = -1; player->drop_y = -1; player->show_envelope = 0; SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE); player->push_delay = -1; /* initialized when pushing starts */ player->push_delay_value = game.initial_push_delay_value; player->drop_delay = 0; player->drop_pressed_delay = 0; player->last_jx = -1; player->last_jy = -1; player->jx = -1; player->jy = -1; player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; if (level.use_initial_inventory[i]) { for (j = 0; j < level.initial_inventory_size[i]; j++) { int element = level.initial_inventory_content[i][j]; int collect_count = element_info[element].collect_count_initial; int k; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } } DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); player->LevelSolved = FALSE; player->GameOver = FALSE; player->LevelSolved_GameWon = FALSE; player->LevelSolved_GameEnd = FALSE; player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; player->LevelSolved_CountingTime = 0; player->LevelSolved_CountingScore = 0; map_player_action[i] = i; } network_player_action_received = FALSE; #if defined(NETWORK_AVALIABLE) /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NONE); #endif ZX = ZY = -1; ExitX = ExitY = -1; FrameCounter = 0; TimeFrames = 0; TimePlayed = 0; TimeLeft = level.time; TapeTime = 0; ScreenMovDir = MV_NONE; ScreenMovPos = 0; ScreenGfxPos = 0; ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */ AllPlayersGone = FALSE; game.yamyam_content_nr = 0; game.robot_wheel_active = FALSE; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; game.light_time_left = 0; game.timegate_time_left = 0; game.switchgate_pos = 0; game.wind_direction = level.wind_direction_initial; #if !USE_PLAYER_GRAVITY game.gravity = FALSE; game.explosions_delayed = TRUE; #endif game.lenses_time_left = 0; game.magnify_time_left = 0; game.ball_state = level.ball_state_initial; game.ball_content_nr = 0; game.envelope_active = FALSE; /* set focus to local player for network games, else to all players */ game.centered_player_nr = (network_playing ? local_player->index_nr : -1); game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; if (network_playing && tape.recording) { /* store client dependent player focus when recording network games */ tape.centered_player_nr_next = game.centered_player_nr_next; tape.set_centered_player = TRUE; } for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; game.belt_dir_nr[i] = 3; /* not moving, next moving left */ } for (i = 0; i < MAX_NUM_AMOEBA; i++) AmoebaCnt[i] = AmoebaCnt2[i] = 0; SCAN_PLAYFIELD(x, y) { Feld[x][y] = level.field[x][y]; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; #if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; /* initialized in InitField() */ #endif Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; WasJustFalling[x][y] = 0; CheckCollision[x][y] = 0; CheckImpact[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; ExplodePhase[x][y] = 0; ExplodeDelay[x][y] = 0; ExplodeField[x][y] = EX_TYPE_NONE; RunnerVisit[x][y] = 0; PlayerVisit[x][y] = 0; GfxFrame[x][y] = 0; GfxRandom[x][y] = INIT_GFX_RANDOM(); GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; GfxRedraw[x][y] = GFX_REDRAW_NONE; } SCAN_PLAYFIELD(x, y) { if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y])) emulate_bd = FALSE; if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y])) emulate_sb = FALSE; if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y])) emulate_sp = FALSE; InitField(x, y, TRUE); ResetGfxAnimation(x, y); } InitBeltMovement(); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; /* set number of special actions for bored and sleeping animation */ player->num_special_action_bored = get_num_special_action(player->artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); player->num_special_action_sleeping = get_num_special_action(player->artwork_element, ACTION_SLEEPING_1, ACTION_SLEEPING_LAST); } game.emulation = (emulate_bd ? EMU_BOULDERDASH : emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); #if USE_NEW_ALL_SLIPPERY /* initialize type of slippery elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { /* default: elements slip down either to the left or right randomly */ element_info[i].slippery_type = SLIPPERY_ANY_RANDOM; /* SP style elements prefer to slip down on the left side */ if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i)) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; /* BD style elements prefer to slip down on the left side */ if (game.emulation == EMU_BOULDERDASH) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; } } #endif /* initialize explosion and ignition delay */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { int num_phase = 8; int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) && game.engine_version >= VERSION_IDENT(3,1,0,0)) || game.emulation == EMU_SUPAPLEX ? 3 : 2); int last_phase = (num_phase + 1) * delay; int half_phase = (num_phase / 2) * delay; element_info[i].explosion_delay = last_phase - 1; element_info[i].ignition_delay = half_phase; if (i == EL_BLACK_ORB) element_info[i].ignition_delay = 1; } #if 0 if (element_info[i].explosion_delay < 1) /* !!! check again !!! */ element_info[i].explosion_delay = 1; if (element_info[i].ignition_delay < 1) /* !!! check again !!! */ element_info[i].ignition_delay = 1; #endif } /* correct non-moving belts to start moving left */ for (i = 0; i < NUM_BELTS; i++) if (game.belt_dir[i] == MV_NONE) game.belt_dir_nr[i] = 3; /* not moving, next moving left */ #if USE_NEW_PLAYER_ASSIGNMENTS /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ /* choose default local player */ local_player = &stored_player[0]; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = FALSE; local_player->connected = TRUE; /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ if (tape.playing) { /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) stored_player[i].connected = TRUE; } else if (setup.team_mode && !options.network) { /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ for (i = 0; i < MAX_PLAYERS; i++) if (setup.input[i].use_joystick || setup.input[i].key.left != KSYM_UNDEFINED) stored_player[i].connected = TRUE; } #if 0 for (i = 0; i < MAX_PLAYERS; i++) printf("::: player %d: %s\n", i, (stored_player[i].connected ? "connected" : "not connected")); for (i = 0; i < MAX_PLAYERS; i++) printf("::: player %d: %s\n", i, (stored_player[i].present ? "present" : "not present")); #endif /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->connected && !player->present) { struct PlayerInfo *field_player = NULL; #if 0 printf("::: looking for field player for player %d ...\n", i); #endif /* assign first free player found that is present in the playfield */ /* first try: look for unmapped playfield player that is not connected */ if (field_player == NULL) for (j = 0; j < MAX_PLAYERS; j++) if (stored_player[j].present && !stored_player[j].mapped && !stored_player[j].connected) field_player = &stored_player[j]; /* second try: look for *any* unmapped playfield player */ if (field_player == NULL) for (j = 0; j < MAX_PLAYERS; j++) if (stored_player[j].present && !stored_player[j].mapped) field_player = &stored_player[j]; if (field_player != NULL) { int jx = field_player->jx, jy = field_player->jy; #if 0 printf("::: found player figure %d\n", field_player->index_nr); #endif player->present = FALSE; player->active = FALSE; field_player->present = TRUE; field_player->active = TRUE; /* player->initial_element = field_player->initial_element; player->artwork_element = field_player->artwork_element; player->block_last_field = field_player->block_last_field; player->block_delay_adjustment = field_player->block_delay_adjustment; */ StorePlayer[jx][jy] = field_player->element_nr; field_player->jx = field_player->last_jx = jx; field_player->jy = field_player->last_jy = jy; if (local_player == player) local_player = field_player; map_player_action[field_player->index_nr] = i; field_player->mapped = TRUE; #if 0 printf("::: map_player_action[%d] == %d\n", field_player->index_nr, i); #endif } } if (player->connected && player->present) player->mapped = TRUE; } #else /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->connected && !player->present) { for (j = 0; j < MAX_PLAYERS; j++) { struct PlayerInfo *field_player = &stored_player[j]; int jx = field_player->jx, jy = field_player->jy; /* assign first free player found that is present in the playfield */ if (field_player->present && !field_player->connected) { player->present = TRUE; player->active = TRUE; field_player->present = FALSE; field_player->active = FALSE; player->initial_element = field_player->initial_element; player->artwork_element = field_player->artwork_element; player->block_last_field = field_player->block_last_field; player->block_delay_adjustment = field_player->block_delay_adjustment; StorePlayer[jx][jy] = player->element_nr; player->jx = player->last_jx = jx; player->jy = player->last_jy = jy; break; } } } } #endif #if 0 printf("::: local_player->present == %d\n", local_player->present); #endif if (tape.playing) { /* when playing a tape, eliminate all players who do not participate */ #if USE_NEW_PLAYER_ASSIGNMENTS for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && !tape.player_participates[map_player_action[i]]) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } #else for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && !tape.player_participates[i]) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } #endif } else if (!options.network && !setup.team_mode) /* && !tape.playing */ { /* when in single player mode, eliminate all but the first active player */ for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active) { for (j = i + 1; j < MAX_PLAYERS; j++) { if (stored_player[j].active) { struct PlayerInfo *player = &stored_player[j]; int jx = player->jx, jy = player->jy; player->active = FALSE; player->present = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } } } } /* when recording the game, store which players take part in the game */ if (tape.recording) { #if USE_NEW_PLAYER_ASSIGNMENTS for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].connected) tape.player_participates[i] = TRUE; #else for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) tape.player_participates[i] = TRUE; #endif } if (options.debug) { for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; printf("Player %d: present == %d, connected == %d, active == %d.\n", i+1, player->present, player->connected, player->active); if (local_player == player) printf("Player %d is local player.\n", i+1); } } if (BorderElement == EL_EMPTY) { SBX_Left = 0; SBX_Right = lev_fieldx - SCR_FIELDX; SBY_Upper = 0; SBY_Lower = lev_fieldy - SCR_FIELDY; } else { SBX_Left = -1; SBX_Right = lev_fieldx - SCR_FIELDX + 1; SBY_Upper = -1; SBY_Lower = lev_fieldy - SCR_FIELDY + 1; } if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX) SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY) SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; /* if local player not found, look for custom element that might create the player (make some assumptions about the right custom element) */ if (!local_player->present) { int start_x = 0, start_y = 0; int found_rating = 0; int found_element = EL_UNDEFINED; int player_nr = local_player->index_nr; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; int content; int xx, yy; boolean is_player; if (level.use_start_element[player_nr] && level.start_element[player_nr] == element && found_rating < 4) { start_x = x; start_y = y; found_rating = 4; found_element = element; } if (!IS_CUSTOM_ELEMENT(element)) continue; if (CAN_CHANGE(element)) { for (i = 0; i < element_info[element].num_change_pages; i++) { /* check for player created from custom element as single target */ content = element_info[element].change_page[i].target_element; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 3 || (found_rating == 3 && element < found_element))) { start_x = x; start_y = y; found_rating = 3; found_element = element; } } } for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++) { /* check for player created from custom element as explosion content */ content = element_info[element].content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 2 || (found_rating == 2 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; found_rating = 2; found_element = element; } if (!CAN_CHANGE(element)) continue; for (i = 0; i < element_info[element].num_change_pages; i++) { /* check for player created from custom element as extended target */ content = element_info[element].change_page[i].target_content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 1 || (found_rating == 1 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; found_rating = 1; found_element = element; } } } } scroll_x = (start_x < SBX_Left + MIDPOSX ? SBX_Left : start_x > SBX_Right + MIDPOSX ? SBX_Right : start_x - MIDPOSX); scroll_y = (start_y < SBY_Upper + MIDPOSY ? SBY_Upper : start_y > SBY_Lower + MIDPOSY ? SBY_Lower : start_y - MIDPOSY); } else { scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : local_player->jx - MIDPOSX); scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : local_player->jy - MIDPOSY); } #if 0 /* do not use PLAYING mask for fading out from main screen */ game_status = GAME_MODE_MAIN; #endif StopAnimation(); if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); #if 1 if (level_editor_test_game) FadeSkipNextFadeIn(); else FadeSetEnterScreen(); #else if (level_editor_test_game) fading = fading_none; else fading = menu.destination; #endif #if 1 FadeOut(REDRAW_FIELD); #else if (do_fading) FadeOut(REDRAW_FIELD); #endif #if 0 game_status = GAME_MODE_PLAYING; #endif /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { InitGameEngine_EM(); /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_EM(backbuffer); } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { InitGameEngine_SP(); /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_SP(backbuffer); } else { DrawLevel(); DrawAllPlayers(); /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) CloseAllOpenTimegates(); /* blit playfield from scroll buffer to normal back buffer for fading in */ if (setup.soft_scrolling) BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); redraw_mask |= REDRAW_FROM_BACKBUFFER; } /* !!! FIX THIS (END) !!! */ #if 1 FadeIn(REDRAW_FIELD); #else if (do_fading) FadeIn(REDRAW_FIELD); BackToFront(); #endif if (!game.restart_level) { /* copy default game door content to main double buffer */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); } SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); #if 1 UpdateAndDisplayGameControlValues(); #else UpdateGameDoorValues(); DrawGameDoorValues(); #endif if (!game.restart_level) { UnmapGameButtons(); UnmapTapeButtons(); game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; MapGameButtons(); MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); OpenDoor(DOOR_OPEN_ALL); PlaySound(SND_GAME_STARTING); if (setup.sound_music) PlayLevelMusic(); KeyboardAutoRepeatOffUnlessAutoplay(); if (options.debug) { for (i = 0; i < MAX_PLAYERS; i++) printf("Player %d %sactive.\n", i + 1, (stored_player[i].active ? "" : "not ")); } } #if 1 UnmapAllGadgets(); MapGameButtons(); MapTapeButtons(); #endif game.restart_level = FALSE; } void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y) { /* this is used for non-R'n'D game engines to update certain engine values */ /* needed to determine if sounds are played within the visible screen area */ scroll_x = actual_scroll_x; scroll_y = actual_scroll_y; } void InitMovDir(int x, int y) { int i, element = Feld[x][y]; static int xy[4][2] = { { 0, +1 }, { +1, 0 }, { 0, -1 }, { -1, 0 } }; static int direction[3][4] = { { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN }, { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }, { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN } }; switch (element) { case EL_BUG_RIGHT: case EL_BUG_UP: case EL_BUG_LEFT: case EL_BUG_DOWN: Feld[x][y] = EL_BUG; MovDir[x][y] = direction[0][element - EL_BUG_RIGHT]; break; case EL_SPACESHIP_RIGHT: case EL_SPACESHIP_UP: case EL_SPACESHIP_LEFT: case EL_SPACESHIP_DOWN: Feld[x][y] = EL_SPACESHIP; MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT]; break; case EL_BD_BUTTERFLY_RIGHT: case EL_BD_BUTTERFLY_UP: case EL_BD_BUTTERFLY_LEFT: case EL_BD_BUTTERFLY_DOWN: Feld[x][y] = EL_BD_BUTTERFLY; MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT]; break; case EL_BD_FIREFLY_RIGHT: case EL_BD_FIREFLY_UP: case EL_BD_FIREFLY_LEFT: case EL_BD_FIREFLY_DOWN: Feld[x][y] = EL_BD_FIREFLY; MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT]; break; case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: Feld[x][y] = EL_PACMAN; MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT]; break; case EL_YAMYAM_LEFT: case EL_YAMYAM_RIGHT: case EL_YAMYAM_UP: case EL_YAMYAM_DOWN: Feld[x][y] = EL_YAMYAM; MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT]; break; case EL_SP_SNIKSNAK: MovDir[x][y] = MV_UP; break; case EL_SP_ELECTRON: MovDir[x][y] = MV_LEFT; break; case EL_MOLE_LEFT: case EL_MOLE_RIGHT: case EL_MOLE_UP: case EL_MOLE_DOWN: Feld[x][y] = EL_MOLE; MovDir[x][y] = direction[2][element - EL_MOLE_LEFT]; break; default: if (IS_CUSTOM_ELEMENT(element)) { struct ElementInfo *ei = &element_info[element]; int move_direction_initial = ei->move_direction_initial; int move_pattern = ei->move_pattern; if (move_direction_initial == MV_START_PREVIOUS) { if (MovDir[x][y] != MV_NONE) return; move_direction_initial = MV_START_AUTOMATIC; } if (move_direction_initial == MV_START_RANDOM) MovDir[x][y] = 1 << RND(4); else if (move_direction_initial & MV_ANY_DIRECTION) MovDir[x][y] = move_direction_initial; else if (move_pattern == MV_ALL_DIRECTIONS || move_pattern == MV_TURNING_LEFT || move_pattern == MV_TURNING_RIGHT || move_pattern == MV_TURNING_LEFT_RIGHT || move_pattern == MV_TURNING_RIGHT_LEFT || move_pattern == MV_TURNING_RANDOM) MovDir[x][y] = 1 << RND(4); else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); else if (move_pattern & MV_ANY_DIRECTION) MovDir[x][y] = element_info[element].move_pattern; else if (move_pattern == MV_ALONG_LEFT_SIDE || move_pattern == MV_ALONG_RIGHT_SIDE) { /* use random direction as default start direction */ if (game.engine_version >= VERSION_IDENT(3,1,0,0)) MovDir[x][y] = 1 << RND(4); for (i = 0; i < NUM_DIRECTIONS; i++) { int x1 = x + xy[i][0]; int y1 = y + xy[i][1]; if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1)) { if (move_pattern == MV_ALONG_RIGHT_SIDE) MovDir[x][y] = direction[0][i]; else MovDir[x][y] = direction[1][i]; break; } } } } else { MovDir[x][y] = 1 << RND(4); if (element != EL_BUG && element != EL_SPACESHIP && element != EL_BD_BUTTERFLY && element != EL_BD_FIREFLY) break; for (i = 0; i < NUM_DIRECTIONS; i++) { int x1 = x + xy[i][0]; int y1 = y + xy[i][1]; if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1)) { if (element == EL_BUG || element == EL_BD_BUTTERFLY) { MovDir[x][y] = direction[0][i]; break; } else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY || element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { MovDir[x][y] = direction[1][i]; break; } } } } break; } GfxDir[x][y] = MovDir[x][y]; } void InitAmoebaNr(int x, int y) { int i; int group_nr = AmoebeNachbarNr(x, y); if (group_nr == 0) { for (i = 1; i < MAX_NUM_AMOEBA; i++) { if (AmoebaCnt[i] == 0) { group_nr = i; break; } } } AmoebaNr[x][y] = group_nr; AmoebaCnt[group_nr]++; AmoebaCnt2[group_nr]++; } static void PlayerWins(struct PlayerInfo *player) { player->LevelSolved = TRUE; player->GameOver = TRUE; player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : player->score); player->LevelSolved_CountingTime = (level.time == 0 ? TimePlayed : TimeLeft); player->LevelSolved_CountingScore = player->score_final; } void GameWon() { static int time, time_final; static int score, score_final; static int game_over_delay_1 = 0; static int game_over_delay_2 = 0; int game_over_delay_value_1 = 50; int game_over_delay_value_2 = 50; if (!local_player->LevelSolved_GameWon) { int i; /* do not start end game actions before the player stops moving (to exit) */ if (local_player->MovPos) return; local_player->LevelSolved_GameWon = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; if (tape.auto_play) /* tape might already be stopped here */ tape.auto_play_level_solved = TRUE; #if 1 TapeStop(); #endif game_over_delay_1 = game_over_delay_value_1; game_over_delay_2 = game_over_delay_value_2; time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; if (TimeLeft > 0) { time_final = 0; score_final += TimeLeft * level.score[SC_TIME_BONUS]; } else if (level.time == 0 && TimePlayed < 999) { time_final = 999; score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS]; } local_player->score_final = score_final; if (level_editor_test_game) { time = time_final; score = score_final; #if 1 local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); #else DrawGameValue_Time(time); DrawGameValue_Score(score); #endif } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */ { /* close exit door after last player */ if ((AllPlayersGone && (Feld[ExitX][ExitY] == EL_EXIT_OPEN || Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) || Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN || Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN) { int element = Feld[ExitX][ExitY]; #if 0 if (element == EL_EM_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN) { Bang(ExitX, ExitY); } else #endif { Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING: EL_EM_STEEL_EXIT_CLOSING); PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); } } /* player disappears */ DrawLevelField(ExitX, ExitY); } for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->present) { RemovePlayer(player); /* player disappears */ DrawLevelField(player->jx, player->jy); } } } PlaySound(SND_GAME_WINNING); } if (game_over_delay_1 > 0) { game_over_delay_1--; return; } if (time != time_final) { int time_to_go = ABS(time_final - time); int time_count_dir = (time < time_final ? +1 : -1); int time_count_steps = (time_to_go > 100 && time_to_go % 10 == 0 ? 10 : 1); time += time_count_steps * time_count_dir; score += time_count_steps * level.score[SC_TIME_BONUS]; #if 1 local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); #else DrawGameValue_Time(time); DrawGameValue_Score(score); #endif if (time == time_final) StopSound(SND_GAME_LEVELTIME_BONUS); else if (setup.sound_loops) PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); return; } local_player->LevelSolved_PanelOff = TRUE; if (game_over_delay_2 > 0) { game_over_delay_2--; return; } #if 1 GameEnd(); #endif } void GameEnd() { int hi_pos; boolean raise_level = FALSE; local_player->LevelSolved_GameEnd = TRUE; CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) { #if 0 TapeStop(); #endif #if 1 SaveTapeChecked(tape.level_nr); /* ask to save tape */ #else SaveTape(tape.level_nr); /* ask to save tape */ #endif } if (level_editor_test_game) { game_status = GAME_MODE_MAIN; #if 1 DrawAndFadeInMainMenu(REDRAW_FIELD); #else DrawMainMenu(); #endif return; } if (!local_player->LevelSolved_SaveScore) { #if 1 FadeOut(REDRAW_FIELD); #endif game_status = GAME_MODE_MAIN; DrawAndFadeInMainMenu(REDRAW_FIELD); return; } if (level_nr == leveldir_current->handicap_level) { leveldir_current->handicap_level++; SaveLevelSetup_SeriesInfo(); } if (level_nr < leveldir_current->last_level) raise_level = TRUE; /* advance to next level */ if ((hi_pos = NewHiScore()) >= 0) { game_status = GAME_MODE_SCORES; DrawHallOfFame(hi_pos); if (raise_level) { level_nr++; TapeErase(); } } else { #if 1 FadeOut(REDRAW_FIELD); #endif game_status = GAME_MODE_MAIN; if (raise_level) { level_nr++; TapeErase(); } DrawAndFadeInMainMenu(REDRAW_FIELD); } } int NewHiScore() { int k, l; int position = -1; LoadScore(level_nr); if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) || local_player->score_final < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; for (k = 0; k < MAX_SCORE_ENTRIES; k++) { if (local_player->score_final > highscore[k].Score) { /* player has made it to the hall of fame */ if (k < MAX_SCORE_ENTRIES - 1) { int m = MAX_SCORE_ENTRIES - 1; #ifdef ONE_PER_NAME for (l = k; l < MAX_SCORE_ENTRIES; l++) if (strEqual(setup.player_name, highscore[l].Name)) m = l; if (m == k) /* player's new highscore overwrites his old one */ goto put_into_list; #endif for (l = m; l > k; l--) { strcpy(highscore[l].Name, highscore[l - 1].Name); highscore[l].Score = highscore[l - 1].Score; } } #ifdef ONE_PER_NAME put_into_list: #endif strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN); highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0'; highscore[k].Score = local_player->score_final; position = k; break; } #ifdef ONE_PER_NAME else if (!strncmp(setup.player_name, highscore[k].Name, MAX_PLAYER_NAME_LEN)) break; /* player already there with a higher score */ #endif } if (position >= 0) SaveScore(level_nr); return position; } inline static int getElementMoveStepsizeExt(int x, int y, int direction) { int element = Feld[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int horiz_move = (dx != 0); int sign = (horiz_move ? dx : dy); int step = sign * element_info[element].move_stepsize; /* special values for move stepsize for spring and things on conveyor belt */ if (horiz_move) { if (CAN_FALL(element) && y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1])) step = sign * MOVE_STEPSIZE_NORMAL / 2; else if (element == EL_SPRING) step = sign * MOVE_STEPSIZE_NORMAL * 2; } return step; } inline static int getElementMoveStepsize(int x, int y) { return getElementMoveStepsizeExt(x, y, MovDir[x][y]); } void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) { if (player->GfxAction != action || player->GfxDir != dir) { #if 0 printf("Player frame reset! (%d => %d, %d => %d)\n", player->GfxAction, action, player->GfxDir, dir); #endif player->GfxAction = action; player->GfxDir = dir; player->Frame = 0; player->StepFrame = 0; } } #if USE_GFX_RESET_GFX_ANIMATION static void ResetGfxFrame(int x, int y, boolean redraw) { int element = Feld[x][y]; int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); int last_gfx_frame = GfxFrame[x][y]; if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element].collect_score; else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) GfxFrame[x][y] = ChangeDelay[x][y]; if (redraw && GfxFrame[x][y] != last_gfx_frame) DrawLevelGraphicAnimation(x, y, graphic); } #endif static void ResetGfxAnimation(int x, int y) { GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MovDir[x][y]; GfxFrame[x][y] = 0; #if USE_GFX_RESET_GFX_ANIMATION ResetGfxFrame(x, y, FALSE); #endif } static void ResetRandomAnimationValue(int x, int y) { GfxRandom[x][y] = INIT_GFX_RANDOM(); } void InitMovingField(int x, int y, int direction) { int element = Feld[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; boolean is_moving_before, is_moving_after; #if 0 boolean continues_moving = (WasJustMoving[x][y] && direction == MovDir[x][y]); #endif /* check if element was/is moving or being moved before/after mode change */ #if 1 #if 1 is_moving_before = (WasJustMoving[x][y] != 0); #else /* (!!! this does not work -- WasJustMoving is NOT a boolean value !!!) */ is_moving_before = WasJustMoving[x][y]; #endif #else is_moving_before = (getElementMoveStepsizeExt(x, y, MovDir[x][y]) != 0); #endif is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0); /* reset animation only for moving elements which change direction of moving or which just started or stopped moving (else CEs with property "can move" / "not moving" are reset each frame) */ #if USE_GFX_RESET_ONLY_WHEN_MOVING #if 1 if (is_moving_before != is_moving_after || direction != MovDir[x][y]) ResetGfxAnimation(x, y); #else if ((is_moving_before || is_moving_after) && !continues_moving) ResetGfxAnimation(x, y); #endif #else if (!continues_moving) ResetGfxAnimation(x, y); #endif MovDir[x][y] = direction; GfxDir[x][y] = direction; #if USE_GFX_RESET_ONLY_WHEN_MOVING GfxAction[x][y] = (!is_moving_after ? ACTION_WAITING : direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); #else GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); #endif /* this is needed for CEs with property "can move" / "not moving" */ if (is_moving_after) { if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; MovDir[newx][newy] = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE CustomValue[newx][newy] = CustomValue[x][y]; #endif GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; GfxAction[newx][newy] = GfxAction[x][y]; GfxDir[newx][newy] = GfxDir[x][y]; } } void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) { int direction = MovDir[x][y]; int newx = x + (direction & MV_LEFT ? -1 : direction & MV_RIGHT ? +1 : 0); int newy = y + (direction & MV_UP ? -1 : direction & MV_DOWN ? +1 : 0); *goes_to_x = newx; *goes_to_y = newy; } void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y) { int oldx = x, oldy = y; int direction = MovDir[x][y]; if (direction == MV_LEFT) oldx++; else if (direction == MV_RIGHT) oldx--; else if (direction == MV_UP) oldy++; else if (direction == MV_DOWN) oldy--; *comes_from_x = oldx; *comes_from_y = oldy; } int MovingOrBlocked2Element(int x, int y) { int element = Feld[x][y]; if (element == EL_BLOCKED) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); return Feld[oldx][oldy]; } else return element; } static int MovingOrBlocked2ElementIfNotLeaving(int x, int y) { /* like MovingOrBlocked2Element(), but if element is moving and (x,y) is the field the moving element is just leaving, return EL_BLOCKED instead of the element value */ int element = Feld[x][y]; if (IS_MOVING(x, y)) { if (element == EL_BLOCKED) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); return Feld[oldx][oldy]; } else return EL_BLOCKED; } else return element; } static void RemoveField(int x, int y) { Feld[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; #if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; #endif AmoebaNr[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; Pushed[x][y] = FALSE; #if 0 ExplodeField[x][y] = EX_TYPE_NONE; #endif GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; #if 0 /* !!! this would prevent the removed tile from being redrawn !!! */ GfxRedraw[x][y] = GFX_REDRAW_NONE; #endif } void RemoveMovingField(int x, int y) { int oldx = x, oldy = y, newx = x, newy = y; int element = Feld[x][y]; int next_element = EL_UNDEFINED; if (element != EL_BLOCKED && !IS_MOVING(x, y)) return; if (IS_MOVING(x, y)) { Moving2Blocked(x, y, &newx, &newy); if (Feld[newx][newy] != EL_BLOCKED) { /* element is moving, but target field is not free (blocked), but already occupied by something different (example: acid pool); in this case, only remove the moving field, but not the target */ RemoveField(oldx, oldy); Store[oldx][oldy] = Store2[oldx][oldy] = 0; TEST_DrawLevelField(oldx, oldy); return; } } else if (element == EL_BLOCKED) { Blocked2Moving(x, y, &oldx, &oldy); if (!IS_MOVING(oldx, oldy)) return; } if (element == EL_BLOCKED && (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING || Feld[oldx][oldy] == EL_QUICKSAND_FAST_EMPTYING || Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_DC_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_AMOEBA_DROPPING)) next_element = get_next_element(Feld[oldx][oldy]); RemoveField(oldx, oldy); RemoveField(newx, newy); Store[oldx][oldy] = Store2[oldx][oldy] = 0; if (next_element != EL_UNDEFINED) Feld[oldx][oldy] = next_element; TEST_DrawLevelField(oldx, oldy); TEST_DrawLevelField(newx, newy); } void DrawDynamite(int x, int y) { int sx = SCREENX(x), sy = SCREENY(y); int graphic = el2img(Feld[x][y]); int frame; if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y)) return; if (IS_WALKABLE_INSIDE(Back[x][y])) return; if (Back[x][y]) DrawGraphic(sx, sy, el2img(Back[x][y]), 0); else if (Store[x][y]) DrawGraphic(sx, sy, el2img(Store[x][y]), 0); frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (Back[x][y] || Store[x][y]) DrawGraphicThruMask(sx, sy, graphic, frame); else DrawGraphic(sx, sy, graphic, frame); } void CheckDynamite(int x, int y) { if (MovDelay[x][y] != 0) /* dynamite is still waiting to explode */ { MovDelay[x][y]--; if (MovDelay[x][y] != 0) { DrawDynamite(x, y); PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); return; } } StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); Bang(x, y); } static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2) { boolean num_checked_players = 0; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active) { int sx = stored_player[i].jx; int sy = stored_player[i].jy; if (num_checked_players == 0) { *sx1 = *sx2 = sx; *sy1 = *sy2 = sy; } else { *sx1 = MIN(*sx1, sx); *sy1 = MIN(*sy1, sy); *sx2 = MAX(*sx2, sx); *sy2 = MAX(*sy2, sy); } num_checked_players++; } } } static boolean checkIfAllPlayersFitToScreen_RND() { int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); return (sx2 - sx1 < SCR_FIELDX && sy2 - sy1 < SCR_FIELDY); } static void setScreenCenteredToAllPlayers(int *sx, int *sy) { int sx1 = scroll_x, sy1 = scroll_y, sx2 = scroll_x, sy2 = scroll_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *sx = (sx1 + sx2) / 2; *sy = (sy1 + sy2) / 2; } void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, boolean center_screen, boolean quick_relocation) { boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); if (quick_relocation) { if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen) { if (!level.shifted_relocation || center_screen) { /* quick relocation (without scrolling), with centering of screen */ scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper : y > SBY_Lower + MIDPOSY ? SBY_Lower : y - MIDPOSY); } else { /* quick relocation (without scrolling), but do not center screen */ int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : old_x > SBX_Right + MIDPOSX ? SBX_Right : old_x - MIDPOSX); int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : old_y > SBY_Lower + MIDPOSY ? SBY_Lower : old_y - MIDPOSY); int offset_x = x + (scroll_x - center_scroll_x); int offset_y = y + (scroll_y - center_scroll_y); scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : offset_x > SBX_Right + MIDPOSX ? SBX_Right : offset_x - MIDPOSX); scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : offset_y - MIDPOSY); } } else { #if 1 if (!level.shifted_relocation || center_screen) { /* quick relocation (without scrolling), with centering of screen */ scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper : y > SBY_Lower + MIDPOSY ? SBY_Lower : y - MIDPOSY); } else { /* quick relocation (without scrolling), but do not center screen */ int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : old_x > SBX_Right + MIDPOSX ? SBX_Right : old_x - MIDPOSX); int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : old_y > SBY_Lower + MIDPOSY ? SBY_Lower : old_y - MIDPOSY); int offset_x = x + (scroll_x - center_scroll_x); int offset_y = y + (scroll_y - center_scroll_y); scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : offset_x > SBX_Right + MIDPOSX ? SBX_Right : offset_x - MIDPOSX); scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : offset_y - MIDPOSY); } #else /* quick relocation (without scrolling), inside visible screen area */ int offset = game.scroll_delay_value; if ((move_dir == MV_LEFT && scroll_x > x - MIDPOSX + offset) || (move_dir == MV_RIGHT && scroll_x < x - MIDPOSX - offset)) scroll_x = x - MIDPOSX + (scroll_x < x - MIDPOSX ? -offset : +offset); if ((move_dir == MV_UP && scroll_y > y - MIDPOSY + offset) || (move_dir == MV_DOWN && scroll_y < y - MIDPOSY - offset)) scroll_y = y - MIDPOSY + (scroll_y < y - MIDPOSY ? -offset : +offset); /* don't scroll over playfield boundaries */ if (scroll_x < SBX_Left || scroll_x > SBX_Right) scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); /* don't scroll over playfield boundaries */ if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); #endif } RedrawPlayfield(TRUE, 0,0,0,0); } else { #if 1 int scroll_xx, scroll_yy; if (!level.shifted_relocation || center_screen) { /* visible relocation (with scrolling), with centering of screen */ scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : y > SBY_Lower + MIDPOSY ? SBY_Lower : y - MIDPOSY); } else { /* visible relocation (with scrolling), but do not center screen */ int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : old_x > SBX_Right + MIDPOSX ? SBX_Right : old_x - MIDPOSX); int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : old_y > SBY_Lower + MIDPOSY ? SBY_Lower : old_y - MIDPOSY); int offset_x = x + (scroll_x - center_scroll_x); int offset_y = y + (scroll_y - center_scroll_y); scroll_xx = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : offset_x > SBX_Right + MIDPOSX ? SBX_Right : offset_x - MIDPOSX); scroll_yy = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : offset_y - MIDPOSY); } #else /* visible relocation (with scrolling), with centering of screen */ int scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); int scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : y > SBY_Lower + MIDPOSY ? SBY_Lower : y - MIDPOSY); #endif ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ while (scroll_x != scroll_xx || scroll_y != scroll_yy) { int dx = 0, dy = 0; int fx = FX, fy = FY; dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; scroll_x -= dx; scroll_y -= dy; fx += dx * TILEX / 2; fy += dy * TILEY / 2; ScrollLevel(dx, dy); DrawAllPlayers(); /* scroll in two steps of half tile size to make things smoother */ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); FlushDisplay(); Delay(wait_delay_value); /* scroll second step to align at full tile size */ BackToFront(); Delay(wait_delay_value); } DrawAllPlayers(); BackToFront(); Delay(wait_delay_value); } } void RelocatePlayer(int jx, int jy, int el_player_raw) { int el_player = GET_PLAYER_ELEMENT(el_player_raw); int player_nr = GET_PLAYER_NR(el_player); struct PlayerInfo *player = &stored_player[player_nr]; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); int old_jx = player->jx; int old_jy = player->jy; int old_element = Feld[old_jx][old_jy]; int element = Feld[jx][jy]; boolean player_relocated = (old_jx != jx || old_jy != jy); int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0); int move_dir_vert = (jy < old_jy ? MV_UP : jy > old_jy ? MV_DOWN : 0); int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz); int enter_side_vert = MV_DIR_OPPOSITE(move_dir_vert); int leave_side_horiz = move_dir_horiz; int leave_side_vert = move_dir_vert; int enter_side = enter_side_horiz | enter_side_vert; int leave_side = leave_side_horiz | leave_side_vert; if (player->GameOver) /* do not reanimate dead player */ return; if (!player_relocated) /* no need to relocate the player */ return; if (IS_PLAYER(jx, jy)) /* player already placed at new position */ { RemoveField(jx, jy); /* temporarily remove newly placed player */ DrawLevelField(jx, jy); } if (player->present) { while (player->MovPos) { ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); AdvanceFrameAndPlayerCounters(player->index_nr); DrawPlayer(player); BackToFront(); Delay(wait_delay_value); } DrawPlayer(player); /* needed here only to cleanup last field */ DrawLevelField(player->jx, player->jy); /* remove player graphic */ player->is_moving = FALSE; } if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); Feld[jx][jy] = el_player; InitPlayerField(jx, jy, el_player, TRUE); /* "InitPlayerField()" above sets Feld[jx][jy] to EL_EMPTY, but it may be possible that the relocation target field did not contain a player element, but a walkable element, to which the new player was relocated -- in this case, restore that (already initialized!) element on the player field */ if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */ { Feld[jx][jy] = element; /* restore previously existing element */ #if 0 /* !!! do not initialize already initialized element a second time !!! */ /* (this causes at least problems with "element creation" CE trigger for already existing elements, and existing Sokoban fields counted twice) */ InitField(jx, jy, FALSE); #endif } /* only visually relocate centered player */ DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir, FALSE, level.instant_relocation); TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); if (IS_CUSTOM_ELEMENT(element)) CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); #if 1 if (player->is_switching) { /* ensure that relocation while still switching an element does not cause a new element to be treated as also switched directly after relocation (this is important for teleporter switches that teleport the player to a place where another teleporter switch is in the same direction, which would then incorrectly be treated as immediately switched before the direction key that caused the switch was released) */ player->switch_x += jx - old_jx; player->switch_y += jy - old_jy; } #endif } void Explode(int ex, int ey, int phase, int mode) { int x, y; int last_phase; int border_element; /* !!! eliminate this variable !!! */ int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); if (game.explosions_delayed) { ExplodeField[ex][ey] = mode; return; } if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ { int center_element = Feld[ex][ey]; int artwork_element, explosion_element; /* set these values later */ #if 0 /* --- This is only really needed (and now handled) in "Impact()". --- */ /* do not explode moving elements that left the explode field in time */ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && center_element == EL_EMPTY && (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)) return; #endif #if 0 /* !!! at this place, the center element may be EL_BLOCKED !!! */ if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); #endif /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) Back[ex][ey] = 0; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) { /* put moving element to center field (and let it explode there) */ center_element = MovingOrBlocked2Element(ex, ey); RemoveMovingField(ex, ey); Feld[ex][ey] = center_element; } /* now "center_element" is finally determined -- set related values now */ artwork_element = center_element; /* for custom player artwork */ explosion_element = center_element; /* for custom player artwork */ if (IS_PLAYER(ex, ey)) { int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]); artwork_element = stored_player[player_nr].artwork_element; if (level.use_explosion_element[player_nr]) { explosion_element = level.explosion_element[player_nr]; artwork_element = explosion_element; } } #if 1 if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); #endif last_phase = element_info[explosion_element].explosion_delay + 1; for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { int xx = x - ex + 1; int yy = y - ey + 1; int element; if (!IN_LEV_FIELD(x, y) || (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) || (mode == EX_TYPE_CROSS && (x != ex && y != ey))) continue; element = Feld[x][y]; if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) { element = MovingOrBlocked2Element(x, y); if (!IS_EXPLOSION_PROOF(element)) RemoveMovingField(x, y); } /* indestructible elements can only explode in center (but not flames) */ if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) || element == EL_FLAMES) continue; /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy behaviour, for example when touching a yamyam that explodes to rocks with active deadly shield, a rock is created under the player !!! */ /* (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) */ #if 0 if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) && (game.engine_version < VERSION_IDENT(3,1,0,0) || (x == ex && y == ey && mode != EX_TYPE_BORDER))) #else if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y))) #endif { if (IS_ACTIVE_BOMB(element)) { /* re-activate things under the bomb like gate or penguin */ Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY); Back[x][y] = 0; } continue; } /* save walkable background elements while explosion on same tile */ if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) Back[x][y] = element; /* ignite explodable elements reached by other explosion */ if (element == EL_EXPLOSION) element = Store2[x][y]; if (AmoebaNr[x][y] && (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA || element == EL_AMOEBA_GROWING)) { AmoebaCnt[AmoebaNr[x][y]]--; AmoebaCnt2[AmoebaNr[x][y]]--; } RemoveField(x, y); if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey)) { int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1; Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr; if (PLAYERINFO(ex, ey)->use_murphy) Store[x][y] = EL_EMPTY; } /* !!! check this case -- currently needed for rnd_rado_negundo_v, !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */ else if (ELEM_IS_PLAYER(center_element)) Store[x][y] = EL_EMPTY; else if (center_element == EL_YAMYAM) Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy]; else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY) Store[x][y] = element_info[center_element].content.e[xx][yy]; #if 1 /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE" (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond otherwise) -- FIX THIS !!! */ else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY) Store[x][y] = element_info[element].content.e[1][1]; #else else if (!CAN_EXPLODE(element)) Store[x][y] = element_info[element].content.e[1][1]; #endif else Store[x][y] = EL_EMPTY; if (x != ex || y != ey || mode == EX_TYPE_BORDER || center_element == EL_AMOEBA_TO_DIAMOND) Store2[x][y] = element; Feld[x][y] = EL_EXPLOSION; GfxElement[x][y] = artwork_element; ExplodePhase[x][y] = 1; ExplodeDelay[x][y] = last_phase; Stop[x][y] = TRUE; } if (center_element == EL_YAMYAM) game.yamyam_content_nr = (game.yamyam_content_nr + 1) % level.num_yamyam_contents; return; } if (Stop[ex][ey]) return; x = ex; y = ey; if (phase == 1) GfxFrame[x][y] = 0; /* restart explosion animation */ last_phase = ExplodeDelay[x][y]; ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); #ifdef DEBUG /* activate this even in non-DEBUG version until cause for crash in getGraphicAnimationFrame() (see below) is found and eliminated */ #endif #if 1 #if 1 /* this can happen if the player leaves an explosion just in time */ if (GfxElement[x][y] == EL_UNDEFINED) GfxElement[x][y] = EL_EMPTY; #else if (GfxElement[x][y] == EL_UNDEFINED) { printf("\n\n"); printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y); printf("Explode(): This should never happen!\n"); printf("\n\n"); GfxElement[x][y] = EL_EMPTY; } #endif #endif border_element = Store2[x][y]; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) border_element = StorePlayer[x][y]; if (phase == element_info[border_element].ignition_delay || phase == last_phase) { boolean border_explosion = FALSE; if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present && !PLAYER_EXPLOSION_PROTECTED(x, y)) { KillPlayerUnlessExplosionProtected(x, y); border_explosion = TRUE; } else if (CAN_EXPLODE_BY_EXPLOSION(border_element)) { Feld[x][y] = Store2[x][y]; Store2[x][y] = 0; Bang(x, y); border_explosion = TRUE; } else if (border_element == EL_AMOEBA_TO_DIAMOND) { AmoebeUmwandeln(x, y); Store2[x][y] = 0; border_explosion = TRUE; } /* if an element just explodes due to another explosion (chain-reaction), do not immediately end the new explosion when it was the last frame of the explosion (as it would be done in the following "if"-statement!) */ if (border_explosion && phase == last_phase) return; } if (phase == last_phase) { int element; element = Feld[x][y] = Store[x][y]; Store[x][y] = Store2[x][y] = 0; GfxElement[x][y] = EL_UNDEFINED; /* player can escape from explosions and might therefore be still alive */ if (element >= EL_PLAYER_IS_EXPLODING_1 && element <= EL_PLAYER_IS_EXPLODING_4) { int player_nr = element - EL_PLAYER_IS_EXPLODING_1; int explosion_element = EL_PLAYER_1 + player_nr; int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2); int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2); if (level.use_explosion_element[player_nr]) explosion_element = level.explosion_element[player_nr]; Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY : element_info[explosion_element].content.e[xx][yy]); } /* restore probably existing indestructible background element */ if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y])) element = Feld[x][y] = Back[x][y]; Back[x][y] = 0; MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; GfxDir[x][y] = MV_NONE; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; #if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; #endif InitField_WithBug2(x, y, FALSE); TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); if (GFX_CRUMBLED(element)) TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present) StorePlayer[x][y] = 0; if (ELEM_IS_PLAYER(element)) RelocatePlayer(x, y, element); } else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING); int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (phase == delay) TEST_DrawLevelFieldCrumbled(x, y); if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY) { DrawLevelElement(x, y, Back[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame); } else if (IS_WALKABLE_UNDER(Back[x][y])) { DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); DrawLevelElementThruMask(x, y, Back[x][y]); } else if (!IS_WALKABLE_INSIDE(Back[x][y])) DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); } } void DynaExplode(int ex, int ey) { int i, j; int dynabomb_element = Feld[ex][ey]; int dynabomb_size = 1; boolean dynabomb_xl = FALSE; struct PlayerInfo *player; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (IS_ACTIVE_BOMB(dynabomb_element)) { player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE]; dynabomb_size = player->dynabomb_size; dynabomb_xl = player->dynabomb_xl; player->dynabombs_left++; } Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER); for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 1; j <= dynabomb_size; j++) { int x = ex + j * xy[i][0]; int y = ey + j * xy[i][1]; int element; if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y])) break; element = Feld[x][y]; /* do not restart explosions of fields with active bombs */ if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y])) continue; Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER); if (element != EL_EMPTY && element != EL_EXPLOSION && !IS_DIGGABLE(element) && !dynabomb_xl) break; } } } void Bang(int x, int y) { int element = MovingOrBlocked2Element(x, y); int explosion_type = EX_TYPE_NORMAL; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) { struct PlayerInfo *player = PLAYERINFO(x, y); #if USE_FIX_CE_ACTION_WITH_PLAYER element = Feld[x][y] = player->initial_element; #else element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY : player->element_nr); #endif if (level.use_explosion_element[player->index_nr]) { int explosion_element = level.explosion_element[player->index_nr]; if (element_info[explosion_element].explosion_type == EXPLODES_CROSS) explosion_type = EX_TYPE_CROSS; else if (element_info[explosion_element].explosion_type == EXPLODES_1X1) explosion_type = EX_TYPE_CENTER; } } switch (element) { case EL_BUG: case EL_SPACESHIP: case EL_BD_BUTTERFLY: case EL_BD_FIREFLY: case EL_YAMYAM: case EL_DARK_YAMYAM: case EL_ROBOT: case EL_PACMAN: case EL_MOLE: RaiseScoreElement(element); break; case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: case EL_DYNABOMB_PLAYER_4_ACTIVE: case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: case EL_DYNABOMB_INCREASE_POWER: explosion_type = EX_TYPE_DYNA; break; case EL_DC_LANDMINE: #if 0 case EL_EM_EXIT_OPEN: case EL_EM_STEEL_EXIT_OPEN: #endif explosion_type = EX_TYPE_CENTER; break; case EL_PENGUIN: case EL_LAMP: case EL_LAMP_ACTIVE: case EL_AMOEBA_TO_DIAMOND: if (!IS_PLAYER(x, y)) /* penguin and player may be at same field */ explosion_type = EX_TYPE_CENTER; break; default: if (element_info[element].explosion_type == EXPLODES_CROSS) explosion_type = EX_TYPE_CROSS; else if (element_info[element].explosion_type == EXPLODES_1X1) explosion_type = EX_TYPE_CENTER; break; } if (explosion_type == EX_TYPE_DYNA) DynaExplode(x, y); else Explode(x, y, EX_PHASE_START, explosion_type); CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); } void SplashAcid(int x, int y) { if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) && (!IN_LEV_FIELD(x - 1, y - 2) || !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2)))) Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT; if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) && (!IN_LEV_FIELD(x + 1, y - 2) || !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2)))) Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT; PlayLevelSound(x, y, SND_ACID_SPLASHING); } static void InitBeltMovement() { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; int x, y, i, j; /* set frame order for belt animation graphic according to belt direction */ for (i = 0; i < NUM_BELTS; i++) { int belt_nr = i; for (j = 0; j < NUM_BELT_PARTS; j++) { int element = belt_base_active_element[belt_nr] + j; int graphic_1 = el2img(element); int graphic_2 = el2panelimg(element); if (game.belt_dir[i] == MV_LEFT) { graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; } else { graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; } } } SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; for (i = 0; i < NUM_BELTS; i++) { if (IS_BELT(element) && game.belt_dir[i] != MV_NONE) { int e_belt_nr = getBeltNrFromBeltElement(element); int belt_nr = i; if (e_belt_nr == belt_nr) { int belt_part = Feld[x][y] - belt_base_element[belt_nr]; Feld[x][y] = belt_base_active_element[belt_nr] + belt_part; } } } } } static void ToggleBeltSwitch(int x, int y) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; static int belt_base_switch_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; static int belt_move_dir[4] = { MV_LEFT, MV_NONE, MV_RIGHT, MV_NONE, }; int element = Feld[x][y]; int belt_nr = getBeltNrFromBeltSwitchElement(element); int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4; int belt_dir = belt_move_dir[belt_dir_nr]; int xx, yy, i; if (!IS_BELT_SWITCH(element)) return; game.belt_dir_nr[belt_nr] = belt_dir_nr; game.belt_dir[belt_nr] = belt_dir; if (belt_dir_nr == 3) belt_dir_nr = 1; /* set frame order for belt animation graphic according to belt direction */ for (i = 0; i < NUM_BELT_PARTS; i++) { int element = belt_base_active_element[belt_nr] + i; int graphic_1 = el2img(element); int graphic_2 = el2panelimg(element); if (belt_dir == MV_LEFT) { graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; } else { graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; } } SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; if (IS_BELT_SWITCH(element)) { int e_belt_nr = getBeltNrFromBeltSwitchElement(element); if (e_belt_nr == belt_nr) { Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr; TEST_DrawLevelField(xx, yy); } } else if (IS_BELT(element) && belt_dir != MV_NONE) { int e_belt_nr = getBeltNrFromBeltElement(element); if (e_belt_nr == belt_nr) { int belt_part = Feld[xx][yy] - belt_base_element[belt_nr]; Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part; TEST_DrawLevelField(xx, yy); } } else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE) { int e_belt_nr = getBeltNrFromBeltActiveElement(element); if (e_belt_nr == belt_nr) { int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr]; Feld[xx][yy] = belt_base_element[belt_nr] + belt_part; TEST_DrawLevelField(xx, yy); } } } } static void ToggleSwitchgateSwitch(int x, int y) { int xx, yy; game.switchgate_pos = !game.switchgate_pos; SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; #if !USE_BOTH_SWITCHGATE_SWITCHES if (element == EL_SWITCHGATE_SWITCH_UP || element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_UP || element == EL_DC_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP + game.switchgate_pos; TEST_DrawLevelField(xx, yy); } #else if (element == EL_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN; TEST_DrawLevelField(xx, yy); } else if (element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP; TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_DOWN; TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP; TEST_DrawLevelField(xx, yy); } #endif else if (element == EL_SWITCHGATE_OPEN || element == EL_SWITCHGATE_OPENING) { Feld[xx][yy] = EL_SWITCHGATE_CLOSING; PlayLevelSoundAction(xx, yy, ACTION_CLOSING); } else if (element == EL_SWITCHGATE_CLOSED || element == EL_SWITCHGATE_CLOSING) { Feld[xx][yy] = EL_SWITCHGATE_OPENING; PlayLevelSoundAction(xx, yy, ACTION_OPENING); } } } static int getInvisibleActiveFromInvisibleElement(int element) { return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE : element == EL_INVISIBLE_WALL ? EL_INVISIBLE_WALL_ACTIVE : element == EL_INVISIBLE_SAND ? EL_INVISIBLE_SAND_ACTIVE : element); } static int getInvisibleFromInvisibleActiveElement(int element) { return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL : element == EL_INVISIBLE_WALL_ACTIVE ? EL_INVISIBLE_WALL : element == EL_INVISIBLE_SAND_ACTIVE ? EL_INVISIBLE_SAND : element); } static void RedrawAllLightSwitchesAndInvisibleElements() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_LIGHT_SWITCH && game.light_time_left > 0) { Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_LIGHT_SWITCH_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_LIGHT_SWITCH; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER && game.light_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || element == EL_INVISIBLE_SAND) { if (game.light_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || element == EL_INVISIBLE_SAND_ACTIVE) { if (game.light_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } static void RedrawAllInvisibleElementsForLenses() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_EMC_DRIPPER && game.lenses_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.lenses_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || element == EL_INVISIBLE_SAND) { if (game.lenses_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || element == EL_INVISIBLE_SAND_ACTIVE) { if (game.lenses_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } static void RedrawAllInvisibleElementsForMagnifier() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_EMC_FAKE_GRASS && game.magnify_time_left > 0) { Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_FAKE_GRASS_ACTIVE && game.magnify_time_left == 0) { Feld[x][y] = EL_EMC_FAKE_GRASS; TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY(element) && game.magnify_time_left > 0) { Feld[x][y] = (IS_RND_GATE_GRAY(element) ? element - EL_GATE_1_GRAY + EL_GATE_1_GRAY_ACTIVE : IS_EM_GATE_GRAY(element) ? element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE : IS_EMC_GATE_GRAY(element) ? element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE : IS_DC_GATE_GRAY(element) ? EL_DC_GATE_WHITE_GRAY_ACTIVE : element); TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY_ACTIVE(element) && game.magnify_time_left == 0) { Feld[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ? element - EL_GATE_1_GRAY_ACTIVE + EL_GATE_1_GRAY : IS_EM_GATE_GRAY_ACTIVE(element) ? element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY : IS_EMC_GATE_GRAY_ACTIVE(element) ? element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY : IS_DC_GATE_GRAY_ACTIVE(element) ? EL_DC_GATE_WHITE_GRAY : element); TEST_DrawLevelField(x, y); } } } static void ToggleLightSwitch(int x, int y) { int element = Feld[x][y]; game.light_time_left = (element == EL_LIGHT_SWITCH ? level.time_light * FRAMES_PER_SECOND : 0); RedrawAllLightSwitchesAndInvisibleElements(); } static void ActivateTimegateSwitch(int x, int y) { int xx, yy; game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND; SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; if (element == EL_TIMEGATE_CLOSED || element == EL_TIMEGATE_CLOSING) { Feld[xx][yy] = EL_TIMEGATE_OPENING; PlayLevelSound(xx, yy, SND_CLASS_TIMEGATE_OPENING); } /* else if (element == EL_TIMEGATE_SWITCH_ACTIVE) { Feld[xx][yy] = EL_TIMEGATE_SWITCH; TEST_DrawLevelField(xx, yy); } */ } #if 1 Feld[x][y] = (Feld[x][y] == EL_TIMEGATE_SWITCH ? EL_TIMEGATE_SWITCH_ACTIVE : EL_DC_TIMEGATE_SWITCH_ACTIVE); #else Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE; #endif } void Impact(int x, int y) { boolean last_line = (y == lev_fieldy - 1); boolean object_hit = FALSE; boolean impact = (last_line || object_hit); int element = Feld[x][y]; int smashed = EL_STEELWALL; if (!last_line) /* check if element below was hit */ { if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING) return; object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) || MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); /* do not smash moving elements that left the smashed field in time */ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) object_hit = FALSE; #if USE_QUICKSAND_IMPACT_BUGFIX if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE) { RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_EMPTY; Feld[x][y + 2] = EL_ROCK; TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTYING && object_hit == FALSE) { RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 2] = EL_ROCK; TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } #endif if (object_hit) smashed = MovingOrBlocked2Element(x, y + 1); impact = (last_line || object_hit); } if (!last_line && smashed == EL_ACID) /* element falls into acid */ { SplashAcid(x, y + 1); return; } /* !!! not sufficient for all cases -- see EL_PEARL below !!! */ /* only reset graphic animation if graphic really changes after impact */ if (impact && el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element)) { ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } if (impact && CAN_EXPLODE_IMPACT(element)) { Bang(x, y); return; } else if (impact && element == EL_PEARL && smashed != EL_DC_MAGIC_WALL && smashed != EL_DC_MAGIC_WALL_ACTIVE) { ResetGfxAnimation(x, y); Feld[x][y] = EL_PEARL_BREAKING; PlayLevelSound(x, y, SND_PEARL_BREAKING); return; } else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT)) { PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); return; } if (impact && element == EL_AMOEBA_DROP) { if (object_hit && IS_PLAYER(x, y + 1)) KillPlayerUnlessEnemyProtected(x, y + 1); else if (object_hit && smashed == EL_PENGUIN) Bang(x, y + 1); else { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; ResetRandomAnimationValue(x, y); } return; } if (object_hit) /* check which object was hit */ { if ((CAN_PASS_MAGIC_WALL(element) && (smashed == EL_MAGIC_WALL || smashed == EL_BD_MAGIC_WALL)) || (CAN_PASS_DC_MAGIC_WALL(element) && smashed == EL_DC_MAGIC_WALL)) { int xx, yy; int activated_magic_wall = (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE : smashed == EL_BD_MAGIC_WALL ? EL_BD_MAGIC_WALL_ACTIVE : EL_DC_MAGIC_WALL_ACTIVE); /* activate magic wall / mill */ SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == smashed) Feld[xx][yy] = activated_magic_wall; } game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND; game.magic_wall_active = TRUE; PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ? SND_MAGIC_WALL_ACTIVATING : smashed == EL_BD_MAGIC_WALL ? SND_BD_MAGIC_WALL_ACTIVATING : SND_DC_MAGIC_WALL_ACTIVATING)); } if (IS_PLAYER(x, y + 1)) { if (CAN_SMASH_PLAYER(element)) { KillPlayerUnlessEnemyProtected(x, y + 1); return; } } else if (smashed == EL_PENGUIN) { if (CAN_SMASH_PLAYER(element)) { Bang(x, y + 1); return; } } else if (element == EL_BD_DIAMOND) { if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed)) { Bang(x, y + 1); return; } } else if (((element == EL_SP_INFOTRON || element == EL_SP_ZONK) && (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON || smashed == EL_SP_DISK_ORANGE)) || (element == EL_SP_INFOTRON && smashed == EL_SP_DISK_YELLOW)) { Bang(x, y + 1); return; } else if (CAN_SMASH_EVERYTHING(element)) { if (IS_CLASSIC_ENEMY(smashed) || CAN_EXPLODE_SMASHED(smashed)) { Bang(x, y + 1); return; } else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1)) { if (smashed == EL_LAMP || smashed == EL_LAMP_ACTIVE) { Bang(x, y + 1); return; } else if (smashed == EL_NUT) { Feld[x][y + 1] = EL_NUT_BREAKING; PlayLevelSound(x, y, SND_NUT_BREAKING); RaiseScoreElement(EL_NUT); return; } else if (smashed == EL_PEARL) { ResetGfxAnimation(x, y); Feld[x][y + 1] = EL_PEARL_BREAKING; PlayLevelSound(x, y, SND_PEARL_BREAKING); return; } else if (smashed == EL_DIAMOND) { Feld[x][y + 1] = EL_DIAMOND_BREAKING; PlayLevelSound(x, y, SND_DIAMOND_BREAKING); return; } else if (IS_BELT_SWITCH(smashed)) { ToggleBeltSwitch(x, y + 1); } else if (smashed == EL_SWITCHGATE_SWITCH_UP || smashed == EL_SWITCHGATE_SWITCH_DOWN || smashed == EL_DC_SWITCHGATE_SWITCH_UP || smashed == EL_DC_SWITCHGATE_SWITCH_DOWN) { ToggleSwitchgateSwitch(x, y + 1); } else if (smashed == EL_LIGHT_SWITCH || smashed == EL_LIGHT_SWITCH_ACTIVE) { ToggleLightSwitch(x, y + 1); } else { #if 0 TestIfElementSmashesCustomElement(x, y, MV_DOWN); #endif CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); CheckElementChangeBySide(x, y + 1, smashed, element, CE_SWITCHED, CH_SIDE_TOP); CheckTriggeredElementChangeBySide(x, y + 1, smashed, CE_SWITCH_OF_X, CH_SIDE_TOP); } } else { CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); } } } /* play sound of magic wall / mill */ if (!last_line && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)) { if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING); else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING); else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_DC_MAGIC_WALL_FILLING); return; } /* play sound of object that hits the ground */ if (last_line || object_hit) PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); } inline static void TurnRoundExt(int x, int y) { static struct { int dx, dy; } move_xy[] = { { 0, 0 }, { -1, 0 }, { +1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, +1 } }; static struct { int left, right, back; } turn[] = { { 0, 0, 0 }, { MV_DOWN, MV_UP, MV_RIGHT }, { MV_UP, MV_DOWN, MV_LEFT }, { 0, 0, 0 }, { MV_LEFT, MV_RIGHT, MV_DOWN }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { MV_RIGHT, MV_LEFT, MV_UP } }; int element = Feld[x][y]; int move_pattern = element_info[element].move_pattern; int old_move_dir = MovDir[x][y]; int left_dir = turn[old_move_dir].left; int right_dir = turn[old_move_dir].right; int back_dir = turn[old_move_dir].back; int left_dx = move_xy[left_dir].dx, left_dy = move_xy[left_dir].dy; int right_dx = move_xy[right_dir].dx, right_dy = move_xy[right_dir].dy; int move_dx = move_xy[old_move_dir].dx, move_dy = move_xy[old_move_dir].dy; int back_dx = move_xy[back_dir].dx, back_dy = move_xy[back_dir].dy; int left_x = x + left_dx, left_y = y + left_dy; int right_x = x + right_dx, right_y = y + right_dy; int move_x = x + move_dx, move_y = y + move_dy; int xx, yy; if (element == EL_BUG || element == EL_BD_BUTTERFLY) { TestIfBadThingTouchesOtherBadThing(x, y); if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = left_dir; if (element == EL_BUG && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */ MovDelay[x][y] = 1; } else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY) { TestIfBadThingTouchesOtherBadThing(x, y); if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = right_dir; if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */ MovDelay[x][y] = 1; } else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { TestIfBadThingTouchesOtherBadThing(x, y); if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0)) MovDir[x][y] = left_dir; else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } else if (element == EL_YAMYAM) { boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); else if (can_turn_left) MovDir[x][y] = (RND(2) ? left_dir : back_dir); else if (can_turn_right) MovDir[x][y] = (RND(2) ? right_dir : back_dir); else MovDir[x][y] = back_dir; MovDelay[x][y] = 16 + 16 * RND(3); } else if (element == EL_DARK_YAMYAM) { boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); else if (can_turn_left) MovDir[x][y] = (RND(2) ? left_dir : back_dir); else if (can_turn_right) MovDir[x][y] = (RND(2) ? right_dir : back_dir); else MovDir[x][y] = back_dir; MovDelay[x][y] = 16 + 16 * RND(3); } else if (element == EL_PACMAN) { boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); else if (can_turn_left) MovDir[x][y] = (RND(2) ? left_dir : back_dir); else if (can_turn_right) MovDir[x][y] = (RND(2) ? right_dir : back_dir); else MovDir[x][y] = back_dir; MovDelay[x][y] = 6 + RND(40); } else if (element == EL_PIG) { boolean can_turn_left = PIG_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y); boolean can_move_on = PIG_CAN_ENTER_FIELD(element, move_x, move_y); boolean should_turn_left, should_turn_right, should_move_on; int rnd_value = 24; int rnd = RND(rnd_value); should_turn_left = (can_turn_left && (!can_move_on || IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx, y + back_dy + left_dy))); should_turn_right = (can_turn_right && (!can_move_on || IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx, y + back_dy + right_dy))); should_move_on = (can_move_on && (!can_turn_left || !can_turn_right || IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx, y + move_dy + left_dy) || IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx, y + move_dy + right_dy))); if (should_turn_left || should_turn_right || should_move_on) { if (should_turn_left && should_turn_right && should_move_on) MovDir[x][y] = (rnd < rnd_value / 3 ? left_dir : rnd < 2 * rnd_value / 3 ? right_dir : old_move_dir); else if (should_turn_left && should_turn_right) MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir); else if (should_turn_left && should_move_on) MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : old_move_dir); else if (should_turn_right && should_move_on) MovDir[x][y] = (rnd < rnd_value / 2 ? right_dir : old_move_dir); else if (should_turn_left) MovDir[x][y] = left_dir; else if (should_turn_right) MovDir[x][y] = right_dir; else if (should_move_on) MovDir[x][y] = old_move_dir; } else if (can_move_on && rnd > rnd_value / 8) MovDir[x][y] = old_move_dir; else if (can_turn_left && can_turn_right) MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir); else if (can_turn_left && rnd > rnd_value / 8) MovDir[x][y] = left_dir; else if (can_turn_right && rnd > rnd_value/8) MovDir[x][y] = right_dir; else MovDir[x][y] = back_dir; xx = x + move_xy[MovDir[x][y]].dx; yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD(xx, yy) || (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))) MovDir[x][y] = old_move_dir; MovDelay[x][y] = 0; } else if (element == EL_DRAGON) { boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y); boolean can_move_on = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y); int rnd_value = 24; int rnd = RND(rnd_value); if (can_move_on && rnd > rnd_value / 8) MovDir[x][y] = old_move_dir; else if (can_turn_left && can_turn_right) MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir); else if (can_turn_left && rnd > rnd_value / 8) MovDir[x][y] = left_dir; else if (can_turn_right && rnd > rnd_value / 8) MovDir[x][y] = right_dir; else MovDir[x][y] = back_dir; xx = x + move_xy[MovDir[x][y]].dx; yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; MovDelay[x][y] = 0; } else if (element == EL_MOLE) { boolean can_move_on = (MOLE_CAN_ENTER_FIELD(element, move_x, move_y, IS_AMOEBOID(Feld[move_x][move_y]) || Feld[move_x][move_y] == EL_AMOEBA_SHRINKING)); if (!can_move_on) { boolean can_turn_left = (MOLE_CAN_ENTER_FIELD(element, left_x, left_y, IS_AMOEBOID(Feld[left_x][left_y]))); boolean can_turn_right = (MOLE_CAN_ENTER_FIELD(element, right_x, right_y, IS_AMOEBOID(Feld[right_x][right_y]))); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(2) ? left_dir : right_dir); else if (can_turn_left) MovDir[x][y] = left_dir; else MovDir[x][y] = right_dir; } if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } else if (element == EL_BALLOON) { MovDir[x][y] = game.wind_direction; MovDelay[x][y] = 0; } else if (element == EL_SPRING) { #if USE_NEW_SPRING_BUMPER if (MovDir[x][y] & MV_HORIZONTAL) { if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) && !SPRING_CAN_ENTER_FIELD(element, x, y + 1)) { Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE; ResetGfxAnimation(move_x, move_y); TEST_DrawLevelField(move_x, move_y); MovDir[x][y] = back_dir; } else if (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || SPRING_CAN_ENTER_FIELD(element, x, y + 1)) MovDir[x][y] = MV_NONE; } #else if (MovDir[x][y] & MV_HORIZONTAL && (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || SPRING_CAN_ENTER_FIELD(element, x, y + 1))) MovDir[x][y] = MV_NONE; #endif MovDelay[x][y] = 0; } else if (element == EL_ROBOT || element == EL_SATELLITE || element == EL_PENGUIN || element == EL_EMC_ANDROID) { int attr_x = -1, attr_y = -1; if (AllPlayersGone) { attr_x = ExitX; attr_y = ExitY; } else { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; if (!player->active) continue; if (attr_x == -1 || ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y)) { attr_x = jx; attr_y = jy; } } } if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 && (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE || game.engine_version < VERSION_IDENT(3,1,0,0))) { attr_x = ZX; attr_y = ZY; } if (element == EL_PENGUIN) { int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int ex = x + xy[i][0]; int ey = y + xy[i][1]; if (IN_LEV_FIELD(ex, ey) && (Feld[ex][ey] == EL_EXIT_OPEN || Feld[ex][ey] == EL_EM_EXIT_OPEN || Feld[ex][ey] == EL_STEEL_EXIT_OPEN || Feld[ex][ey] == EL_EM_STEEL_EXIT_OPEN)) { attr_x = ex; attr_y = ey; break; } } } MovDir[x][y] = MV_NONE; if (attr_x < x) MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT); else if (attr_x > x) MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT); if (attr_y < y) MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP); else if (attr_y > y) MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN); if (element == EL_ROBOT) { int newx, newy; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy)) MovDelay[x][y] = 8 + 8 * !RND(3); else MovDelay[x][y] = 16; } else if (element == EL_PENGUIN) { int newx, newy; MovDelay[x][y] = 1; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = old_move_dir; return; } } else if (element == EL_SATELLITE) { int newx, newy; MovDelay[x][y] = 1; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = old_move_dir; return; } } else if (element == EL_EMC_ANDROID) { static int check_pos[16] = { -1, /* 0 => (invalid) */ 7, /* 1 => MV_LEFT */ 3, /* 2 => MV_RIGHT */ -1, /* 3 => (invalid) */ 1, /* 4 => MV_UP */ 0, /* 5 => MV_LEFT | MV_UP */ 2, /* 6 => MV_RIGHT | MV_UP */ -1, /* 7 => (invalid) */ 5, /* 8 => MV_DOWN */ 6, /* 9 => MV_LEFT | MV_DOWN */ 4, /* 10 => MV_RIGHT | MV_DOWN */ -1, /* 11 => (invalid) */ -1, /* 12 => (invalid) */ -1, /* 13 => (invalid) */ -1, /* 14 => (invalid) */ -1, /* 15 => (invalid) */ }; static struct { int dx, dy; int dir; } check_xy[8] = { { -1, -1, MV_LEFT | MV_UP }, { 0, -1, MV_UP }, { +1, -1, MV_RIGHT | MV_UP }, { +1, 0, MV_RIGHT }, { +1, +1, MV_RIGHT | MV_DOWN }, { 0, +1, MV_DOWN }, { -1, +1, MV_LEFT | MV_DOWN }, { -1, 0, MV_LEFT }, }; int start_pos, check_order; boolean can_clone = FALSE; int i; /* check if there is any free field around current position */ for (i = 0; i < 8; i++) { int newx = x + check_xy[i].dx; int newy = y + check_xy[i].dy; if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { can_clone = TRUE; break; } } if (can_clone) /* randomly find an element to clone */ { can_clone = FALSE; start_pos = check_pos[RND(8)]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 8; i++) { int pos_raw = start_pos + i * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; if (ANDROID_CAN_CLONE_FIELD(newx, newy)) { element_info[element].move_leave_type = LEAVE_TYPE_LIMITED; element_info[element].move_leave_element = EL_TRIGGER_ELEMENT; Store[x][y] = Feld[newx][newy]; can_clone = TRUE; break; } } } if (can_clone) /* randomly find a direction to move */ { can_clone = FALSE; start_pos = check_pos[RND(8)]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 8; i++) { int pos_raw = start_pos + i * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; int new_move_dir = check_xy[pos].dir; if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { MovDir[x][y] = new_move_dir; MovDelay[x][y] = level.android_clone_time * 8 + 1; can_clone = TRUE; break; } } } if (can_clone) /* cloning and moving successful */ return; /* cannot clone -- try to move towards player */ start_pos = check_pos[MovDir[x][y] & 0x0f]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 3; i++) { /* first check start_pos, then previous/next or (next/previous) pos */ int pos_raw = start_pos + (i < 2 ? i : -1) * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; int new_move_dir = check_xy[pos].dir; if (IS_PLAYER(newx, newy)) break; if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) { MovDir[x][y] = new_move_dir; MovDelay[x][y] = level.android_move_time * 8 + 1; break; } } } } else if (move_pattern == MV_TURNING_LEFT || move_pattern == MV_TURNING_RIGHT || move_pattern == MV_TURNING_LEFT_RIGHT || move_pattern == MV_TURNING_RIGHT_LEFT || move_pattern == MV_TURNING_RANDOM || move_pattern == MV_ALL_DIRECTIONS) { boolean can_turn_left = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); if (element_info[element].move_stepsize == 0) /* "not moving" */ return; if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; else if (move_pattern == MV_TURNING_RIGHT) MovDir[x][y] = right_dir; else if (move_pattern == MV_TURNING_LEFT_RIGHT) MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir); else if (move_pattern == MV_TURNING_RIGHT_LEFT) MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir); else if (move_pattern == MV_TURNING_RANDOM) MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir : can_turn_right && !can_turn_left ? right_dir : RND(2) ? left_dir : right_dir); else if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); else if (can_turn_left) MovDir[x][y] = (RND(2) ? left_dir : back_dir); else if (can_turn_right) MovDir[x][y] = (RND(2) ? right_dir : back_dir); else MovDir[x][y] = back_dir; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_HORIZONTAL || move_pattern == MV_VERTICAL) { if (move_pattern & old_move_dir) MovDir[x][y] = back_dir; else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern & MV_ANY_DIRECTION) { MovDir[x][y] = move_pattern; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern & MV_WIND_DIRECTION) { MovDir[x][y] = game.wind_direction; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_ALONG_LEFT_SIDE) { if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_ALONG_RIGHT_SIDE) { if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = left_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_TOWARDS_PLAYER || move_pattern == MV_AWAY_FROM_PLAYER) { int attr_x = -1, attr_y = -1; int newx, newy; boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER); if (AllPlayersGone) { attr_x = ExitX; attr_y = ExitY; } else { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; if (!player->active) continue; if (attr_x == -1 || ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y)) { attr_x = jx; attr_y = jy; } } } MovDir[x][y] = MV_NONE; if (attr_x < x) MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT); else if (attr_x > x) MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT); if (attr_y < y) MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP); else if (attr_y > y) MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; if (element_info[element].move_stepsize == 0) /* "not moving" */ { first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y)); MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); return; } MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = old_move_dir; } } else if (move_pattern == MV_WHEN_PUSHED || move_pattern == MV_WHEN_DROPPED) { if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = MV_NONE; MovDelay[x][y] = 0; } else if (move_pattern & MV_MAZE_RUNNER_STYLE) { static int test_xy[7][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 }, { 0, -1 }, { -1, 0 }, { +1, 0 }, }; static int test_dir[7] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN, MV_UP, MV_LEFT, MV_RIGHT, }; boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER); int move_preference = -1000000; /* start with very low preference */ int new_move_dir = MV_NONE; int start_test = RND(4); int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int move_dir = test_dir[start_test + i]; int move_dir_preference; xx = x + test_xy[start_test + i][0]; yy = y + test_xy[start_test + i][1]; if (hunter_mode && IN_LEV_FIELD(xx, yy) && (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING)) { new_move_dir = move_dir; break; } if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy)) continue; move_dir_preference = -1 * RunnerVisit[xx][yy]; if (hunter_mode && PlayerVisit[xx][yy] > 0) move_dir_preference = PlayerVisit[xx][yy]; if (move_dir_preference > move_preference) { /* prefer field that has not been visited for the longest time */ move_preference = move_dir_preference; new_move_dir = move_dir; } else if (move_dir_preference == move_preference && move_dir == old_move_dir) { /* prefer last direction when all directions are preferred equally */ move_preference = move_dir_preference; new_move_dir = move_dir; } } MovDir[x][y] = new_move_dir; if (old_move_dir != new_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } } static void TurnRound(int x, int y) { int direction = MovDir[x][y]; TurnRoundExt(x, y); GfxDir[x][y] = MovDir[x][y]; if (direction != MovDir[x][y]) GfxFrame[x][y] = 0; if (MovDelay[x][y]) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction); ResetGfxFrame(x, y, FALSE); } static boolean JustBeingPushed(int x, int y) { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->active && player->is_pushing && player->MovPos) { int next_jx = player->jx + (player->jx - player->last_jx); int next_jy = player->jy + (player->jy - player->last_jy); if (x == next_jx && y == next_jy) return TRUE; } } return FALSE; } void StartMoving(int x, int y) { boolean started_moving = FALSE; /* some elements can fall _and_ move */ int element = Feld[x][y]; if (Stop[x][y]) return; if (MovDelay[x][y] == 0) GfxAction[x][y] = ACTION_DEFAULT; if (CAN_FALL(element) && y < lev_fieldy - 1) { if ((x > 0 && IS_PLAYER(x - 1, y)) || (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y))) if (JustBeingPushed(x, y)) return; if (element == EL_QUICKSAND_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_EMPTYING; #if USE_QUICKSAND_BD_ROCK_BUGFIX if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) Store[x][y] = EL_ROCK; #else Store[x][y] = EL_ROCK; #endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } } else if (element == EL_QUICKSAND_FAST_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FAST_EMPTYING; #if USE_QUICKSAND_BD_ROCK_BUGFIX if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) Store[x][y] = EL_ROCK; #else Store[x][y] = EL_ROCK; #endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } } else if ((element == EL_ROCK || element == EL_BD_ROCK) && Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FILLING; Store[x][y] = element; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if ((element == EL_ROCK || element == EL_BD_ROCK) && Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FAST_FILLING; Store[x][y] = element; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (element == EL_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED(Store[x][y]); } else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY/4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED(Store[x][y]); Store[x][y] = 0; } } else if (element == EL_BD_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED_BD(Store[x][y]); } else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY/4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED_BD(Store[x][y]); Store[x][y] = 0; } } else if (element == EL_DC_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_DC_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED_DC(Store[x][y]); } else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY/4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_DC_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_DC_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED_DC(Store[x][y]); Store[x][y] = 0; } } else if ((CAN_PASS_MAGIC_WALL(element) && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) || (CAN_PASS_DC_MAGIC_WALL(element) && (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE))) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING : Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ? EL_BD_MAGIC_WALL_FILLING : EL_DC_MAGIC_WALL_FILLING); Store[x][y] = element; } else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID) { SplashAcid(x, y + 1); InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Store[x][y] = EL_ACID; } else if ( #if USE_FIX_IMPACT_COLLISION (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckImpact[x][y] && !IS_FREE(x, y + 1)) || #else (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IS_FREE(x, y + 1)) || #endif (game.engine_version >= VERSION_IDENT(3,0,7,0) && CAN_FALL(element) && WasJustFalling[x][y] && (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || (game.engine_version < VERSION_IDENT(2,2,0,7) && CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] && (Feld[x][y + 1] == EL_BLOCKED))) { /* this is needed for a special case not covered by calling "Impact()" from "ContinueMoving()": if an element moves to a tile directly below another element which was just falling on that tile (which was empty in the previous frame), the falling element above would just stop instead of smashing the element below (in previous version, the above element was just checked for "moving" instead of "falling", resulting in incorrect smashes caused by horizontal movement of the above element; also, the case of the player being the element to smash was simply not covered here... :-/ ) */ CheckCollision[x][y] = 0; CheckImpact[x][y] = 0; Impact(x, y); } else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug) { if (MovDir[x][y] == MV_NONE) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; } } else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING) { if (WasJustFalling[x][y]) /* prevent animation from being restarted */ MovDir[x][y] = MV_DOWN; InitMovingField(x, y, MV_DOWN); started_moving = TRUE; } else if (element == EL_AMOEBA_DROP) { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; } else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) || (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) && !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] && element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE) { boolean can_fall_left = (x > 0 && IS_FREE(x - 1, y) && (IS_FREE(x - 1, y + 1) || Feld[x - 1][y + 1] == EL_ACID)); boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) && (IS_FREE(x + 1, y + 1) || Feld[x + 1][y + 1] == EL_ACID)); boolean can_fall_any = (can_fall_left || can_fall_right); boolean can_fall_both = (can_fall_left && can_fall_right); int slippery_type = element_info[Feld[x][y + 1]].slippery_type; #if USE_NEW_ALL_SLIPPERY if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM) { if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) can_fall_left = FALSE; else if (slippery_type == SLIPPERY_ONLY_LEFT) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ONLY_RIGHT) can_fall_left = FALSE; can_fall_any = (can_fall_left || can_fall_right); can_fall_both = FALSE; } #else if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) { if (slippery_type == SLIPPERY_ONLY_LEFT) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ONLY_RIGHT) can_fall_left = FALSE; else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) can_fall_left = FALSE; can_fall_any = (can_fall_left || can_fall_right); can_fall_both = (can_fall_left && can_fall_right); } #endif #if USE_NEW_ALL_SLIPPERY #else #if USE_NEW_SP_SLIPPERY /* !!! better use the same properties as for custom elements here !!! */ else if (game.engine_version >= VERSION_IDENT(3,1,1,0) && can_fall_both && IS_SP_ELEMENT(Feld[x][y + 1])) { can_fall_right = FALSE; /* slip down on left side */ can_fall_both = FALSE; } #endif #endif #if USE_NEW_ALL_SLIPPERY if (can_fall_both) { if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) can_fall_right = FALSE; /* slip down on left side */ else can_fall_left = !(can_fall_right = RND(2)); can_fall_both = FALSE; } #else if (can_fall_both) { if (game.emulation == EMU_BOULDERDASH || element == EL_BD_ROCK || element == EL_BD_DIAMOND) can_fall_right = FALSE; /* slip down on left side */ else can_fall_left = !(can_fall_right = RND(2)); can_fall_both = FALSE; } #endif if (can_fall_any) { /* if not determined otherwise, prefer left side for slipping down */ InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT); started_moving = TRUE; } } #if 0 else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element)) #else else if (IS_BELT_ACTIVE(Feld[x][y + 1])) #endif { boolean left_is_free = (x > 0 && IS_FREE(x - 1, y)); boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y)); int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]); int belt_dir = game.belt_dir[belt_nr]; if ((belt_dir == MV_LEFT && left_is_free) || (belt_dir == MV_RIGHT && right_is_free)) { int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1); InitMovingField(x, y, belt_dir); started_moving = TRUE; Pushed[x][y] = TRUE; Pushed[nextx][y] = TRUE; GfxAction[x][y] = ACTION_DEFAULT; } else { MovDir[x][y] = 0; /* if element was moving, stop it */ } } } /* not "else if" because of elements that can fall and move (EL_SPRING) */ #if 0 if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NONE) #else if (CAN_MOVE(element) && !started_moving) #endif { int move_pattern = element_info[element].move_pattern; int newx, newy; #if 0 #if DEBUG if (MovDir[x][y] == MV_NONE) { printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n", x, y, element, element_info[element].token_name); printf("StartMoving(): This should never happen!\n"); } #endif #endif Moving2Blocked(x, y, &newx, &newy); if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) return; if (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { WasJustMoving[x][y] = 0; CheckCollision[x][y] = 0; TestIfElementHitsCustomElement(x, y, MovDir[x][y]); if (Feld[x][y] != element) /* element has changed */ return; } if (!MovDelay[x][y]) /* start new movement phase */ { /* all objects that can change their move direction after each step (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */ if (element != EL_YAMYAM && element != EL_DARK_YAMYAM && element != EL_PACMAN && !(move_pattern & MV_ANY_DIRECTION) && move_pattern != MV_TURNING_LEFT && move_pattern != MV_TURNING_RIGHT && move_pattern != MV_TURNING_LEFT_RIGHT && move_pattern != MV_TURNING_RIGHT_LEFT && move_pattern != MV_TURNING_RANDOM) { TurnRound(x, y); if (MovDelay[x][y] && (element == EL_BUG || element == EL_SPACESHIP || element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON || element == EL_MOLE)) TEST_DrawLevelField(x, y); } } if (MovDelay[x][y]) /* wait some time before next movement */ { MovDelay[x][y]--; if (element == EL_ROBOT || element == EL_YAMYAM || element == EL_DARK_YAMYAM) { DrawLevelElementAnimationIfNeeded(x, y, element); PlayLevelSoundAction(x, y, ACTION_WAITING); } else if (element == EL_SP_ELECTRON) DrawLevelElementAnimationIfNeeded(x, y, element); else if (element == EL_DRAGON) { int i; int dir = MovDir[x][y]; int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0); int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); int graphic = (dir == MV_LEFT ? IMG_FLAMES_1_LEFT : dir == MV_RIGHT ? IMG_FLAMES_1_RIGHT : dir == MV_UP ? IMG_FLAMES_1_UP : dir == MV_DOWN ? IMG_FLAMES_1_DOWN : IMG_EMPTY); int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); GfxAction[x][y] = ACTION_ATTACKING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); PlayLevelSoundActionIfLoop(x, y, ACTION_ATTACKING); for (i = 1; i <= 3; i++) { int xx = x + i * dx; int yy = y + i * dy; int sx = SCREENX(xx); int sy = SCREENY(yy); int flame_graphic = graphic + (i - 1); if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy])) break; if (MovDelay[x][y]) { int flamed = MovingOrBlocked2Element(xx, yy); /* !!! */ #if 0 if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed)) Bang(xx, yy); else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy)) RemoveMovingField(xx, yy); else RemoveField(xx, yy); #else if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed)) Bang(xx, yy); else RemoveMovingField(xx, yy); #endif ChangeDelay[xx][yy] = 0; Feld[xx][yy] = EL_FLAMES; if (IN_SCR_FIELD(sx, sy)) { TEST_DrawLevelFieldCrumbled(xx, yy); DrawGraphic(sx, sy, flame_graphic, frame); } } else { if (Feld[xx][yy] == EL_FLAMES) Feld[xx][yy] = EL_EMPTY; TEST_DrawLevelField(xx, yy); } } } if (MovDelay[x][y]) /* element still has to wait some time */ { PlayLevelSoundAction(x, y, ACTION_WAITING); return; } } /* now make next step */ Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ if (DONT_COLLIDE_WITH(element) && IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) && !PLAYER_ENEMY_PROTECTED(newx, newy)) { TestIfBadThingRunsIntoPlayer(x, y, MovDir[x][y]); return; } else if (CAN_MOVE_INTO_ACID(element) && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID && !IS_MV_DIAGONAL(MovDir[x][y]) && (MovDir[x][y] == MV_DOWN || game.engine_version >= VERSION_IDENT(3,1,0,0))) { SplashAcid(newx, newy); Store[x][y] = EL_ACID; } else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy)) { if (Feld[newx][newy] == EL_EXIT_OPEN || Feld[newx][newy] == EL_EM_EXIT_OPEN || Feld[newx][newy] == EL_STEEL_EXIT_OPEN || Feld[newx][newy] == EL_EM_STEEL_EXIT_OPEN) { RemoveField(x, y); TEST_DrawLevelField(x, y); PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0); local_player->friends_still_needed--; if (!local_player->friends_still_needed && !local_player->GameOver && AllPlayersGone) PlayerWins(local_player); return; } else if (IS_FOOD_PENGUIN(Feld[newx][newy])) { if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING) TEST_DrawLevelField(newx, newy); else GfxDir[x][y] = MovDir[x][y] = MV_NONE; } else if (!IS_FREE(newx, newy)) { GfxAction[x][y] = ACTION_WAITING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); return; } } else if (element == EL_PIG && IN_LEV_FIELD(newx, newy)) { if (IS_FOOD_PIG(Feld[newx][newy])) { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_PIG_DIGGING); } else if (!IS_FREE(newx, newy)) { if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); return; } } else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy)) { if (Store[x][y] != EL_EMPTY) { boolean can_clone = FALSE; int xx, yy; /* check if element to clone is still there */ for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++) { if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y]) { can_clone = TRUE; break; } } /* cannot clone or target field not free anymore -- do not clone */ if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy)) Store[x][y] = EL_EMPTY; } if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) { if (IS_MV_DIAGONAL(MovDir[x][y])) { int diagonal_move_dir = MovDir[x][y]; int stored = Store[x][y]; int change_delay = 8; int graphic; /* android is moving diagonally */ CreateField(x, y, EL_DIAGONAL_SHRINKING); Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored); GfxElement[x][y] = EL_EMC_ANDROID; GfxAction[x][y] = ACTION_SHRINKING; GfxDir[x][y] = diagonal_move_dir; ChangeDelay[x][y] = change_delay; graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], GfxDir[x][y]); DrawLevelGraphicAnimation(x, y, graphic); PlayLevelSoundAction(x, y, ACTION_SHRINKING); if (Feld[newx][newy] == EL_ACID) { SplashAcid(newx, newy); return; } CreateField(newx, newy, EL_DIAGONAL_GROWING); Store[newx][newy] = EL_EMC_ANDROID; GfxElement[newx][newy] = EL_EMC_ANDROID; GfxAction[newx][newy] = ACTION_GROWING; GfxDir[newx][newy] = diagonal_move_dir; ChangeDelay[newx][newy] = change_delay; graphic = el_act_dir2img(GfxElement[newx][newy], GfxAction[newx][newy], GfxDir[newx][newy]); DrawLevelGraphicAnimation(newx, newy, graphic); PlayLevelSoundAction(newx, newy, ACTION_GROWING); return; } else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); PlayLevelSoundAction(x, y, ACTION_DIGGING); } } else if (!IS_FREE(newx, newy)) { #if 0 if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); #endif return; } } else if (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) { #if 1 if (!DigFieldByCE(newx, newy, element)) return; #else int new_element = Feld[newx][newy]; if (!IS_FREE(newx, newy)) { int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING : IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING : ACTION_BREAKING); /* no element can dig solid indestructible elements */ if (IS_INDESTRUCTIBLE(new_element) && !IS_DIGGABLE(new_element) && !IS_COLLECTIBLE(new_element)) return; if (AmoebaNr[newx][newy] && (new_element == EL_AMOEBA_FULL || new_element == EL_BD_AMOEBA || new_element == EL_AMOEBA_GROWING)) { AmoebaCnt[AmoebaNr[newx][newy]]--; AmoebaCnt2[AmoebaNr[newx][newy]]--; } if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { RemoveField(newx, newy); TEST_DrawLevelField(newx, newy); } /* if digged element was about to explode, prevent the explosion */ ExplodeField[newx][newy] = EX_TYPE_NONE; PlayLevelSoundAction(x, y, action); } Store[newx][newy] = EL_EMPTY; #if 1 /* this makes it possible to leave the removed element again */ if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) Store[newx][newy] = new_element; #else if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) { int move_leave_element = element_info[element].move_leave_element; /* this makes it possible to leave the removed element again */ Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? new_element : move_leave_element); } #endif #endif if (move_pattern & MV_MAZE_RUNNER_STYLE) { RunnerVisit[x][y] = FrameCounter; PlayerVisit[x][y] /= 8; /* expire player visit path */ } } else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy)) { if (!IS_FREE(newx, newy)) { if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); return; } else { boolean wanna_flame = !RND(10); int dx = newx - x, dy = newy - y; int newx1 = newx + 1 * dx, newy1 = newy + 1 * dy; int newx2 = newx + 2 * dx, newy2 = newy + 2 * dy; int element1 = (IN_LEV_FIELD(newx1, newy1) ? MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL); int element2 = (IN_LEV_FIELD(newx2, newy2) ? MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL); if ((wanna_flame || IS_CLASSIC_ENEMY(element1) || IS_CLASSIC_ENEMY(element2)) && element1 != EL_DRAGON && element2 != EL_DRAGON && element1 != EL_FLAMES && element2 != EL_FLAMES) { ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_ATTACKING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); PlayLevelSound(x, y, SND_DRAGON_ATTACKING); MovDelay[x][y] = 50; /* !!! */ #if 0 RemoveField(newx, newy); #endif Feld[newx][newy] = EL_FLAMES; if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY) { #if 0 RemoveField(newx1, newy1); #endif Feld[newx1][newy1] = EL_FLAMES; } if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY) { #if 0 RemoveField(newx2, newy2); #endif Feld[newx2][newy2] = EL_FLAMES; } return; } } } else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_DIAMOND) { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_YAMYAM_DIGGING); } else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) && IS_FOOD_DARK_YAMYAM(Feld[newx][newy])) { if (AmoebaNr[newx][newy]) { AmoebaCnt2[AmoebaNr[newx][newy]]--; if (Feld[newx][newy] == EL_AMOEBA_FULL || Feld[newx][newy] == EL_BD_AMOEBA) AmoebaCnt[AmoebaNr[newx][newy]]--; } #if 0 /* !!! test !!! */ if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy)) { RemoveMovingField(newx, newy); } #else if (IS_MOVING(newx, newy)) { RemoveMovingField(newx, newy); } #endif else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING); } else if ((element == EL_PACMAN || element == EL_MOLE) && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy])) { if (AmoebaNr[newx][newy]) { AmoebaCnt2[AmoebaNr[newx][newy]]--; if (Feld[newx][newy] == EL_AMOEBA_FULL || Feld[newx][newy] == EL_BD_AMOEBA) AmoebaCnt[AmoebaNr[newx][newy]]--; } if (element == EL_MOLE) { Feld[newx][newy] = EL_AMOEBA_SHRINKING; PlayLevelSound(x, y, SND_MOLE_DIGGING); ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_DIGGING; TEST_DrawLevelField(x, y); MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ return; /* wait for shrinking amoeba */ } else /* element == EL_PACMAN */ { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); PlayLevelSound(x, y, SND_PACMAN_DIGGING); } } else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) && (Feld[newx][newy] == EL_AMOEBA_SHRINKING || (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy]))) { /* wait for shrinking amoeba to completely disappear */ return; } else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy)) { /* object was running against a wall */ TurnRound(x, y); #if 0 /* !!! NEW "CE_BLOCKED" STUFF !!! -- DOES NOT WORK YET... !!! */ if (move_pattern & MV_ANY_DIRECTION && move_pattern == MovDir[x][y]) { int blocking_element = (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement); CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED, MovDir[x][y]); element = Feld[x][y]; /* element might have changed */ } #endif if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ DrawLevelElementAnimation(x, y, element); if (DONT_TOUCH(element)) TestIfBadThingTouchesPlayer(x, y); return; } InitMovingField(x, y, MovDir[x][y]); PlayLevelSoundAction(x, y, ACTION_MOVING); } if (MovDir[x][y]) ContinueMoving(x, y); } void ContinueMoving(int x, int y) { int element = Feld[x][y]; struct ElementInfo *ei = &element_info[element]; int direction = MovDir[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx, newy = y + dy; int stored = Store[x][y]; int stored_new = Store[newx][newy]; boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y)); boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y)); boolean last_line = (newy == lev_fieldy - 1); MovPos[x][y] += getElementMoveStepsize(x, y); if (pushed_by_player) /* special case: moving object pushed by player */ MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); if (ABS(MovPos[x][y]) < TILEX) { #if 0 int ee = Feld[x][y]; int gg = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); int ff = getGraphicAnimationFrame(gg, GfxFrame[x][y]); printf("::: %d.%d: moving %d ... [%d, %d, %d] [%d, %d, %d]\n", x, y, ABS(MovPos[x][y]), ee, gg, ff, GfxAction[x][y], GfxDir[x][y], GfxFrame[x][y]); #endif TEST_DrawLevelField(x, y); return; /* element is still moving */ } /* element reached destination field */ Feld[x][y] = EL_EMPTY; Feld[newx][newy] = element; MovPos[x][y] = 0; /* force "not moving" for "crumbled sand" */ if (Store[x][y] == EL_ACID) /* element is moving into acid pool */ { element = Feld[newx][newy] = EL_ACID; } else if (element == EL_MOLE) { Feld[x][y] = EL_SAND; TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_QUICKSAND_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_EMPTYING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_FAST_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_FAST_EMPTYING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; #if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); #endif } else if (element == EL_BD_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_BD_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; #if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); #endif } else if (element == EL_DC_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_DC_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_DC_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; #if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); #endif } else if (element == EL_AMOEBA_DROPPING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_SOKOBAN_OBJECT) { if (Back[x][y]) Feld[x][y] = Back[x][y]; if (Back[newx][newy]) Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL; Back[x][y] = Back[newx][newy] = 0; } Store[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; MovDelay[newx][newy] = 0; if (CAN_CHANGE_OR_HAS_ACTION(element)) { /* copy element change control values to new field */ ChangeDelay[newx][newy] = ChangeDelay[x][y]; ChangePage[newx][newy] = ChangePage[x][y]; ChangeCount[newx][newy] = ChangeCount[x][y]; ChangeEvent[newx][newy] = ChangeEvent[x][y]; } #if USE_NEW_CUSTOM_VALUE CustomValue[newx][newy] = CustomValue[x][y]; #endif ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; #if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; #endif /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ GfxDir[newx][newy] = GfxDir[x][y]; /* keep element direction */ Pushed[x][y] = Pushed[newx][newy] = FALSE; /* some elements can leave other elements behind after moving */ #if 1 if (ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) #else if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) #endif { int move_leave_element = ei->move_leave_element; #if 1 #if 1 /* this makes it possible to leave the removed element again */ if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored); #else /* this makes it possible to leave the removed element again */ if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = stored; #endif #else /* this makes it possible to leave the removed element again */ if (ei->move_leave_type == LEAVE_TYPE_LIMITED && ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = stored; #endif Feld[x][y] = move_leave_element; if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = direction; InitField(x, y, FALSE); if (GFX_CRUMBLED(Feld[x][y])) TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (ELEM_IS_PLAYER(move_leave_element)) RelocatePlayer(x, y, move_leave_element); } /* do this after checking for left-behind element */ ResetGfxAnimation(x, y); /* reset animation values for old field */ if (!CAN_MOVE(element) || (CAN_FALL(element) && direction == MV_DOWN && (element == EL_SPRING || element_info[element].move_pattern == MV_WHEN_PUSHED || element_info[element].move_pattern == MV_WHEN_DROPPED))) GfxDir[x][y] = MovDir[newx][newy] = 0; TEST_DrawLevelField(x, y); TEST_DrawLevelField(newx, newy); Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ /* prevent pushed element from moving on in pushed direction */ if (pushed_by_player && CAN_MOVE(element) && element_info[element].move_pattern & MV_ANY_DIRECTION && !(element_info[element].move_pattern & direction)) TurnRound(newx, newy); /* prevent elements on conveyor belt from moving on in last direction */ if (pushed_by_conveyor && CAN_FALL(element) && direction & MV_HORIZONTAL) MovDir[newx][newy] = 0; if (!pushed_by_player) { int nextx = newx + dx, nexty = newy + dy; boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty); WasJustMoving[newx][newy] = CHECK_DELAY_MOVING; if (CAN_FALL(element) && direction == MV_DOWN) WasJustFalling[newx][newy] = CHECK_DELAY_FALLING; if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again) CheckCollision[newx][newy] = CHECK_DELAY_COLLISION; #if USE_FIX_IMPACT_COLLISION if (CAN_FALL(element) && direction == MV_DOWN && check_collision_again) CheckImpact[newx][newy] = CHECK_DELAY_IMPACT; #endif } if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { TestIfBadThingTouchesPlayer(newx, newy); TestIfBadThingTouchesFriend(newx, newy); if (!IS_CUSTOM_ELEMENT(element)) TestIfBadThingTouchesOtherBadThing(newx, newy); } else if (element == EL_PENGUIN) TestIfFriendTouchesBadThing(newx, newy); if (DONT_GET_HIT_BY(element)) { TestIfGoodThingGetsHitByBadThing(newx, newy, direction); } /* give the player one last chance (one more frame) to move away */ if (CAN_FALL(element) && direction == MV_DOWN && (last_line || (!IS_FREE(x, newy + 1) && (!IS_PLAYER(x, newy + 1) || game.engine_version < VERSION_IDENT(3,1,1,0))))) Impact(x, newy); if (pushed_by_player && !game.use_change_when_pushing_bug) { int push_side = MV_DIR_OPPOSITE(direction); struct PlayerInfo *player = PLAYERINFO(x, y); CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER, player->index_bit, push_side); CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X, player->index_bit, push_side); } if (element == EL_EMC_ANDROID && pushed_by_player) /* make another move */ MovDelay[newx][newy] = 1; CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction); TestIfElementTouchesCustomElement(x, y); /* empty or new element */ #if 0 if (ChangePage[newx][newy] != -1) /* delayed change */ { int page = ChangePage[newx][newy]; struct ElementChangeInfo *change = &ei->change_page[page]; ChangePage[newx][newy] = -1; if (change->can_change) { if (ChangeElement(newx, newy, element, page)) { if (change->post_change_function) change->post_change_function(newx, newy); } } if (change->has_action) ExecuteCustomElementAction(newx, newy, element, page); } #endif TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY && IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element)) CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X, MV_DIR_OPPOSITE(direction)); } int AmoebeNachbarNr(int ax, int ay) { int i; int element = Feld[ax][ay]; int group_nr = 0; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int x = ax + xy[i][0]; int y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if (Feld[x][y] == element && AmoebaNr[x][y] > 0) group_nr = AmoebaNr[x][y]; } return group_nr; } void AmoebenVereinigen(int ax, int ay) { int i, x, y, xx, yy; int new_group_nr = AmoebaNr[ax][ay]; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (new_group_nr == 0) return; for (i = 0; i < NUM_DIRECTIONS; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if ((Feld[x][y] == EL_AMOEBA_FULL || Feld[x][y] == EL_BD_AMOEBA || Feld[x][y] == EL_AMOEBA_DEAD) && AmoebaNr[x][y] != new_group_nr) { int old_group_nr = AmoebaNr[x][y]; if (old_group_nr == 0) return; AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr]; AmoebaCnt[old_group_nr] = 0; AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; AmoebaCnt2[old_group_nr] = 0; SCAN_PLAYFIELD(xx, yy) { if (AmoebaNr[xx][yy] == old_group_nr) AmoebaNr[xx][yy] = new_group_nr; } } } } void AmoebeUmwandeln(int ax, int ay) { int i, x, y; if (Feld[ax][ay] == EL_AMOEBA_DEAD) { int group_nr = AmoebaNr[ax][ay]; #ifdef DEBUG if (group_nr == 0) { printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay); printf("AmoebeUmwandeln(): This should never happen!\n"); return; } #endif SCAN_PLAYFIELD(x, y) { if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr) { AmoebaNr[x][y] = 0; Feld[x][y] = EL_AMOEBA_TO_DIAMOND; } } PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ? SND_AMOEBA_TURNING_TO_GEM : SND_AMOEBA_TURNING_TO_ROCK)); Bang(ax, ay); } else { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND) { PlayLevelSound(x, y, (IS_GEM(level.amoeba_content) ? SND_AMOEBA_TURNING_TO_GEM : SND_AMOEBA_TURNING_TO_ROCK)); Bang(x, y); } } } } void AmoebeUmwandelnBD(int ax, int ay, int new_element) { int x, y; int group_nr = AmoebaNr[ax][ay]; boolean done = FALSE; #ifdef DEBUG if (group_nr == 0) { printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay); printf("AmoebeUmwandelnBD(): This should never happen!\n"); return; } #endif SCAN_PLAYFIELD(x, y) { if (AmoebaNr[x][y] == group_nr && (Feld[x][y] == EL_AMOEBA_DEAD || Feld[x][y] == EL_BD_AMOEBA || Feld[x][y] == EL_AMOEBA_GROWING)) { AmoebaNr[x][y] = 0; Feld[x][y] = new_element; InitField(x, y, FALSE); TEST_DrawLevelField(x, y); done = TRUE; } } if (done) PlayLevelSound(ax, ay, (new_element == EL_BD_ROCK ? SND_BD_AMOEBA_TURNING_TO_ROCK : SND_BD_AMOEBA_TURNING_TO_GEM)); } void AmoebeWaechst(int x, int y) { static unsigned long sound_delay = 0; static unsigned long sound_delay_value = 0; if (!MovDelay[x][y]) /* start new growing cycle */ { MovDelay[x][y] = 7; if (DelayReached(&sound_delay, sound_delay_value)) { PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING); sound_delay_value = 30; } } if (MovDelay[x][y]) /* wait some time before growing bigger */ { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING, 6 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame); } if (!MovDelay[x][y]) { Feld[x][y] = Store[x][y]; Store[x][y] = 0; TEST_DrawLevelField(x, y); } } } void AmoebaDisappearing(int x, int y) { static unsigned long sound_delay = 0; static unsigned long sound_delay_value = 0; if (!MovDelay[x][y]) /* start new shrinking cycle */ { MovDelay[x][y] = 7; if (DelayReached(&sound_delay, sound_delay_value)) sound_delay_value = 30; } if (MovDelay[x][y]) /* wait some time before shrinking */ { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING, 6 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame); } if (!MovDelay[x][y]) { Feld[x][y] = EL_EMPTY; TEST_DrawLevelField(x, y); /* don't let mole enter this field in this cycle; (give priority to objects falling to this field from above) */ Stop[x][y] = TRUE; } } } void AmoebeAbleger(int ax, int ay) { int i; int element = Feld[ax][ay]; int graphic = el2img(element); int newax = ax, neway = ay; boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER); static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!level.amoeba_speed && element != EL_EMC_DRIPPER) { Feld[ax][ay] = EL_AMOEBA_DEAD; TEST_DrawLevelField(ax, ay); return; } if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start making new amoeba field */ MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed)); if (MovDelay[ax][ay]) /* wait some time before making new amoeba */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (can_drop) /* EL_AMOEBA_WET or EL_EMC_DRIPPER */ { int start = RND(4); int x = ax + xy[start][0]; int y = ay + xy[start][1]; if (!IN_LEV_FIELD(x, y)) return; if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY || Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; } if (newax == ax && neway == ay) return; } else /* normal or "filled" (BD style) amoeba */ { int start = RND(4); boolean waiting_for_player = FALSE; for (i = 0; i < NUM_DIRECTIONS; i++) { int j = (start + i) % 4; int x = ax + xy[j][0]; int y = ay + xy[j][1]; if (!IN_LEV_FIELD(x, y)) continue; if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY || Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; break; } else if (IS_PLAYER(x, y)) waiting_for_player = TRUE; } if (newax == ax && neway == ay) /* amoeba cannot grow */ { if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA)) { Feld[ax][ay] = EL_AMOEBA_DEAD; TEST_DrawLevelField(ax, ay); AmoebaCnt[AmoebaNr[ax][ay]]--; if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */ { if (element == EL_AMOEBA_FULL) AmoebeUmwandeln(ax, ay); else if (element == EL_BD_AMOEBA) AmoebeUmwandelnBD(ax, ay, level.amoeba_content); } } return; } else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA) { /* amoeba gets larger by growing in some direction */ int new_group_nr = AmoebaNr[ax][ay]; #ifdef DEBUG if (new_group_nr == 0) { printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway); printf("AmoebeAbleger(): This should never happen!\n"); return; } #endif AmoebaNr[newax][neway] = new_group_nr; AmoebaCnt[new_group_nr]++; AmoebaCnt2[new_group_nr]++; /* if amoeba touches other amoeba(s) after growing, unify them */ AmoebenVereinigen(newax, neway); if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200) { AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK); return; } } } if (!can_drop || neway < ay || !IS_FREE(newax, neway) || (neway == lev_fieldy - 1 && newax != ax)) { Feld[newax][neway] = EL_AMOEBA_GROWING; /* creation of new amoeba */ Store[newax][neway] = element; } else if (neway == ay || element == EL_EMC_DRIPPER) { Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */ PlayLevelSoundAction(newax, neway, ACTION_GROWING); } else { InitMovingField(ax, ay, MV_DOWN); /* drop dripping from amoeba */ Feld[ax][ay] = EL_AMOEBA_DROPPING; Store[ax][ay] = EL_AMOEBA_DROP; ContinueMoving(ax, ay); return; } TEST_DrawLevelField(newax, neway); } void Life(int ax, int ay) { int x1, y1, x2, y2; int life_time = 40; int element = Feld[ax][ay]; int graphic = el2img(element); int *life_parameter = (element == EL_GAME_OF_LIFE ? level.game_of_life : level.biomaze); boolean changed = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (Stop[ax][ay]) return; if (!MovDelay[ax][ay]) /* start new "game of life" cycle */ MovDelay[ax][ay] = life_time; if (MovDelay[ax][ay]) /* wait some time before next cycle */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++) { int xx = ax+x1, yy = ay+y1; int nachbarn = 0; if (!IN_LEV_FIELD(xx, yy)) continue; for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++) { int x = xx+x2, y = yy+y2; if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy)) continue; if (((Feld[x][y] == element || (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) && !Stop[x][y]) || (IS_FREE(x, y) && Stop[x][y])) nachbarn++; } if (xx == ax && yy == ay) /* field in the middle */ { if (nachbarn < life_parameter[0] || nachbarn > life_parameter[1]) { Feld[xx][yy] = EL_EMPTY; if (!Stop[xx][yy]) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } } else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy])) { /* free border field */ if (nachbarn >= life_parameter[2] && nachbarn <= life_parameter[3]) { Feld[xx][yy] = element; MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); if (!Stop[xx][yy]) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } } } if (changed) PlayLevelSound(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING : SND_GAME_OF_LIFE_GROWING); } static void InitRobotWheel(int x, int y) { ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; } static void RunRobotWheel(int x, int y) { PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE); } static void StopRobotWheel(int x, int y) { if (ZX == x && ZY == y) { ZX = ZY = -1; game.robot_wheel_active = FALSE; } } static void InitTimegateWheel(int x, int y) { ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND; } static void RunTimegateWheel(int x, int y) { PlayLevelSound(x, y, SND_CLASS_TIMEGATE_SWITCH_ACTIVE); } static void InitMagicBallDelay(int x, int y) { #if 1 ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1; #else ChangeDelay[x][y] = level.ball_time * FRAMES_PER_SECOND + 1; #endif } static void ActivateMagicBall(int bx, int by) { int x, y; if (level.ball_random) { int pos_border = RND(8); /* select one of the eight border elements */ int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border); int xx = pos_content % 3; int yy = pos_content / 3; x = bx - 1 + xx; y = by - 1 + yy; if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); } else { for (y = by - 1; y <= by + 1; y++) for (x = bx - 1; x <= bx + 1; x++) { int xx = x - bx + 1; int yy = y - by + 1; if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); } } game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents; } void CheckExit(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING); } void CheckExitEM(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EM_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EM_EXIT_OPENING); } void CheckExitSteel(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_STEEL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_STEEL_EXIT_OPENING); } void CheckExitSteelEM(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EM_STEEL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EM_STEEL_EXIT_OPENING); } void CheckExitSP(int x, int y) { if (local_player->gems_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_SP_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING); } static void CloseAllOpenTimegates() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING) { Feld[x][y] = EL_TIMEGATE_CLOSING; PlayLevelSoundAction(x, y, ACTION_CLOSING); } } } void DrawTwinkleOnField(int x, int y) { if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y)) return; if (Feld[x][y] == EL_BD_DIAMOND) return; if (MovDelay[x][y] == 0) /* next animation frame */ MovDelay[x][y] = 11 * !GetSimpleRandom(500); if (MovDelay[x][y] != 0) /* wait some time before next frame */ { MovDelay[x][y]--; DrawLevelElementAnimation(x, y, Feld[x][y]); if (MovDelay[x][y] != 0) { int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE, 10 - MovDelay[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame); } } } void MauerWaechst(int x, int y) { int delay = 6; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 3 * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int graphic = el_dir2img(Feld[x][y], GfxDir[x][y]); int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); } if (!MovDelay[x][y]) { if (MovDir[x][y] == MV_LEFT) { if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y])) TEST_DrawLevelField(x - 1, y); } else if (MovDir[x][y] == MV_RIGHT) { if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y])) TEST_DrawLevelField(x + 1, y); } else if (MovDir[x][y] == MV_UP) { if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1])) TEST_DrawLevelField(x, y - 1); } else { if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1])) TEST_DrawLevelField(x, y + 1); } Feld[x][y] = Store[x][y]; Store[x][y] = 0; GfxDir[x][y] = MovDir[x][y] = MV_NONE; TEST_DrawLevelField(x, y); } } } void MauerAbleger(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); boolean oben_frei = FALSE, unten_frei = FALSE; boolean links_frei = FALSE, rechts_frei = FALSE; boolean oben_massiv = FALSE, unten_massiv = FALSE; boolean links_massiv = FALSE, rechts_massiv = FALSE; boolean new_wall = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start building new wall */ MovDelay[ax][ay] = 6; if (MovDelay[ax][ay]) /* wait some time before building new wall */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1)) oben_frei = TRUE; if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1)) unten_frei = TRUE; if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay)) links_frei = TRUE; if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay)) rechts_frei = TRUE; if (element == EL_EXPANDABLE_WALL_VERTICAL || element == EL_EXPANDABLE_WALL_ANY) { if (oben_frei) { Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING; Store[ax][ay-1] = element; GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1))) DrawGraphic(SCREENX(ax), SCREENY(ay - 1), IMG_EXPANDABLE_WALL_GROWING_UP, 0); new_wall = TRUE; } if (unten_frei) { Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING; Store[ax][ay+1] = element; GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1))) DrawGraphic(SCREENX(ax), SCREENY(ay + 1), IMG_EXPANDABLE_WALL_GROWING_DOWN, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_ANY || element == EL_EXPANDABLE_WALL || element == EL_BD_EXPANDABLE_WALL) { if (links_frei) { Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING; Store[ax-1][ay] = element; GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT; if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay))) DrawGraphic(SCREENX(ax - 1), SCREENY(ay), IMG_EXPANDABLE_WALL_GROWING_LEFT, 0); new_wall = TRUE; } if (rechts_frei) { Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING; Store[ax+1][ay] = element; GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT; if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay))) DrawGraphic(SCREENX(ax + 1), SCREENY(ay), IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei)) TEST_DrawLevelField(ax, ay); if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1])) oben_massiv = TRUE; if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1])) unten_massiv = TRUE; if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay])) links_massiv = TRUE; if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay])) rechts_massiv = TRUE; if (((oben_massiv && unten_massiv) || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL) && ((links_massiv && rechts_massiv) || element == EL_EXPANDABLE_WALL_VERTICAL)) Feld[ax][ay] = EL_WALL; if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } void MauerAblegerStahl(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); boolean oben_frei = FALSE, unten_frei = FALSE; boolean links_frei = FALSE, rechts_frei = FALSE; boolean oben_massiv = FALSE, unten_massiv = FALSE; boolean links_massiv = FALSE, rechts_massiv = FALSE; boolean new_wall = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start building new wall */ MovDelay[ax][ay] = 6; if (MovDelay[ax][ay]) /* wait some time before building new wall */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1)) oben_frei = TRUE; if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1)) unten_frei = TRUE; if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay)) links_frei = TRUE; if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay)) rechts_frei = TRUE; if (element == EL_EXPANDABLE_STEELWALL_VERTICAL || element == EL_EXPANDABLE_STEELWALL_ANY) { if (oben_frei) { Feld[ax][ay-1] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax][ay-1] = element; GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1))) DrawGraphic(SCREENX(ax), SCREENY(ay - 1), IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0); new_wall = TRUE; } if (unten_frei) { Feld[ax][ay+1] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax][ay+1] = element; GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1))) DrawGraphic(SCREENX(ax), SCREENY(ay + 1), IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || element == EL_EXPANDABLE_STEELWALL_ANY) { if (links_frei) { Feld[ax-1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax-1][ay] = element; GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT; if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay))) DrawGraphic(SCREENX(ax - 1), SCREENY(ay), IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0); new_wall = TRUE; } if (rechts_frei) { Feld[ax+1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax+1][ay] = element; GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT; if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay))) DrawGraphic(SCREENX(ax + 1), SCREENY(ay), IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0); new_wall = TRUE; } } if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1])) oben_massiv = TRUE; if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1])) unten_massiv = TRUE; if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay])) links_massiv = TRUE; if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay])) rechts_massiv = TRUE; if (((oben_massiv && unten_massiv) || element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) && ((links_massiv && rechts_massiv) || element == EL_EXPANDABLE_STEELWALL_VERTICAL)) Feld[ax][ay] = EL_STEELWALL; if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } void CheckForDragon(int x, int y) { int i, j; boolean dragon_found = FALSE; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 0; j < 4; j++) { int xx = x + j * xy[i][0], yy = y + j * xy[i][1]; if (IN_LEV_FIELD(xx, yy) && (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON)) { if (Feld[xx][yy] == EL_DRAGON) dragon_found = TRUE; } else break; } } if (!dragon_found) { for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 0; j < 3; j++) { int xx = x + j * xy[i][0], yy = y + j * xy[i][1]; if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES) { Feld[xx][yy] = EL_EMPTY; TEST_DrawLevelField(xx, yy); } else break; } } } } static void InitBuggyBase(int x, int y) { int element = Feld[x][y]; int activating_delay = FRAMES_PER_SECOND / 4; ChangeDelay[x][y] = (element == EL_SP_BUGGY_BASE ? 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay : element == EL_SP_BUGGY_BASE_ACTIVATING ? activating_delay : element == EL_SP_BUGGY_BASE_ACTIVE ? 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1); } static void WarnBuggyBase(int x, int y) { int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy)) { PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE); break; } } } static void InitTrap(int x, int y) { ChangeDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); } static void ActivateTrap(int x, int y) { PlayLevelSound(x, y, SND_TRAP_ACTIVATING); } static void ChangeActiveTrap(int x, int y) { int graphic = IMG_TRAP_ACTIVE; /* if new animation frame was drawn, correct crumbled sand border */ if (IS_NEW_FRAME(GfxFrame[x][y], graphic)) TEST_DrawLevelFieldCrumbled(x, y); } static int getSpecialActionElement(int element, int number, int base_element) { return (element != EL_EMPTY ? element : number != -1 ? base_element + number - 1 : EL_EMPTY); } static int getModifiedActionNumber(int value_old, int operator, int operand, int value_min, int value_max) { int value_new = (operator == CA_MODE_SET ? operand : operator == CA_MODE_ADD ? value_old + operand : operator == CA_MODE_SUBTRACT ? value_old - operand : operator == CA_MODE_MULTIPLY ? value_old * operand : operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) : operator == CA_MODE_MODULO ? value_old % MAX(1, operand) : value_old); return (value_new < value_min ? value_min : value_new > value_max ? value_max : value_new); } static void ExecuteCustomElementAction(int x, int y, int element, int page) { struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; int target_element = change->target_element; int action_type = change->action_type; int action_mode = change->action_mode; int action_arg = change->action_arg; int action_element = change->action_element; int i; if (!change->has_action) return; /* ---------- determine action paramater values -------------------------- */ int level_time_value = (level.time > 0 ? TimeLeft : TimePlayed); int action_arg_element_raw = (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player : action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_ACTION ? change->action_element : action_arg == CA_ARG_INVENTORY_RM_TRIGGER ? change->actual_trigger_element: action_arg == CA_ARG_INVENTORY_RM_TARGET ? change->target_element : action_arg == CA_ARG_INVENTORY_RM_ACTION ? change->action_element : EL_EMPTY); int action_arg_element = GetElementFromGroupElement(action_arg_element_raw); #if 0 if (action_arg_element_raw == EL_GROUP_START) printf("::: %d,%d: %d ('%s')\n", x, y, element, EL_NAME(element)); #endif int action_arg_direction = (action_arg >= CA_ARG_DIRECTION_LEFT && action_arg <= CA_ARG_DIRECTION_DOWN ? action_arg - CA_ARG_DIRECTION : action_arg == CA_ARG_DIRECTION_TRIGGER ? change->actual_trigger_side : action_arg == CA_ARG_DIRECTION_TRIGGER_BACK ? MV_DIR_OPPOSITE(change->actual_trigger_side) : MV_NONE); int action_arg_number_min = (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING : CA_ARG_MIN); int action_arg_number_max = (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER : action_type == CA_SET_LEVEL_GEMS ? 999 : action_type == CA_SET_LEVEL_TIME ? 9999 : action_type == CA_SET_LEVEL_SCORE ? 99999 : action_type == CA_SET_CE_VALUE ? 9999 : action_type == CA_SET_CE_SCORE ? 9999 : CA_ARG_MAX); int action_arg_number_reset = (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize[0] : action_type == CA_SET_LEVEL_GEMS ? level.gems_needed : action_type == CA_SET_LEVEL_TIME ? level.time : action_type == CA_SET_LEVEL_SCORE ? 0 : #if USE_NEW_CUSTOM_VALUE action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) : #else action_type == CA_SET_CE_VALUE ? ei->custom_value_initial : #endif action_type == CA_SET_CE_SCORE ? 0 : 0); int action_arg_number = (action_arg <= CA_ARG_MAX ? action_arg : action_arg >= CA_ARG_SPEED_NOT_MOVING && action_arg <= CA_ARG_SPEED_EVEN_FASTER ? (action_arg - CA_ARG_SPEED) : action_arg == CA_ARG_SPEED_RESET ? action_arg_number_reset : action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min : action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max : action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset : #if USE_NEW_CUSTOM_VALUE action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] : #else action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial : #endif action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) : action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed : action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element): action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value: action_arg == CA_ARG_ELEMENT_CV_ACTION ? GET_NEW_CE_VALUE(action_element): action_arg == CA_ARG_ELEMENT_CS_TARGET ? GET_CE_SCORE(target_element) : action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score: action_arg == CA_ARG_ELEMENT_CS_ACTION ? GET_CE_SCORE(action_element) : action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_NR_ACTION ? change->action_element : -1); int action_arg_number_old = (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed : action_type == CA_SET_LEVEL_TIME ? TimeLeft : action_type == CA_SET_LEVEL_SCORE ? local_player->score : action_type == CA_SET_CE_VALUE ? CustomValue[x][y] : action_type == CA_SET_CE_SCORE ? ei->collect_score : 0); int action_arg_number_new = getModifiedActionNumber(action_arg_number_old, action_mode, action_arg_number, action_arg_number_min, action_arg_number_max); #if 1 int trigger_player_bits = (change->actual_trigger_player_bits != CH_PLAYER_NONE ? change->actual_trigger_player_bits : change->trigger_player); #else int trigger_player_bits = (change->actual_trigger_player >= EL_PLAYER_1 && change->actual_trigger_player <= EL_PLAYER_4 ? (1 << (change->actual_trigger_player - EL_PLAYER_1)) : PLAYER_BITS_ANY); #endif int action_arg_player_bits = (action_arg >= CA_ARG_PLAYER_1 && action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER : action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits : action_arg == CA_ARG_PLAYER_ACTION ? 1 << GET_PLAYER_NR(action_element) : PLAYER_BITS_ANY); /* ---------- execute action -------------------------------------------- */ switch (action_type) { case CA_NO_ACTION: { return; } /* ---------- level actions ------------------------------------------- */ case CA_RESTART_LEVEL: { game.restart_level = TRUE; break; } case CA_SHOW_ENVELOPE: { int element = getSpecialActionElement(action_arg_element, action_arg_number, EL_ENVELOPE_1); if (IS_ENVELOPE(element)) local_player->show_envelope = element; break; } case CA_SET_LEVEL_TIME: { if (level.time > 0) /* only modify limited time value */ { TimeLeft = action_arg_number_new; #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } break; } case CA_SET_LEVEL_SCORE: { local_player->score = action_arg_number_new; #if 1 game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); #else DrawGameValue_Score(local_player->score); #endif break; } case CA_SET_LEVEL_GEMS: { local_player->gems_still_needed = action_arg_number_new; #if 1 game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); #else DrawGameValue_Emeralds(local_player->gems_still_needed); #endif break; } #if !USE_PLAYER_GRAVITY case CA_SET_LEVEL_GRAVITY: { game.gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : action_arg == CA_ARG_GRAVITY_ON ? TRUE : action_arg == CA_ARG_GRAVITY_TOGGLE ? !game.gravity : game.gravity); break; } #endif case CA_SET_LEVEL_WIND: { game.wind_direction = action_arg_direction; break; } case CA_SET_LEVEL_RANDOM_SEED: { #if 1 /* ensure that setting a new random seed while playing is predictable */ InitRND(action_arg_number_new ? action_arg_number_new : RND(1000000) + 1); #else InitRND(action_arg_number_new); #endif #if 0 printf("::: %d -> %d\n", action_arg_number_new, RND(10)); #endif #if 0 { int i; printf("::: "); for (i = 0; i < 9; i++) printf("%d, ", RND(2)); printf("\n"); } #endif break; } /* ---------- player actions ------------------------------------------ */ case CA_MOVE_PLAYER: { /* automatically move to the next field in specified direction */ for (i = 0; i < MAX_PLAYERS; i++) if (trigger_player_bits & (1 << i)) stored_player[i].programmed_action = action_arg_direction; break; } case CA_EXIT_PLAYER: { for (i = 0; i < MAX_PLAYERS; i++) if (action_arg_player_bits & (1 << i)) PlayerWins(&stored_player[i]); break; } case CA_KILL_PLAYER: { for (i = 0; i < MAX_PLAYERS; i++) if (action_arg_player_bits & (1 << i)) KillPlayer(&stored_player[i]); break; } case CA_SET_PLAYER_KEYS: { int key_state = (action_mode == CA_MODE_ADD ? TRUE : FALSE); int element = getSpecialActionElement(action_arg_element, action_arg_number, EL_KEY_1); if (IS_KEY(element)) { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { stored_player[i].key[KEY_NR(element)] = key_state; DrawGameDoorValues(); } } } break; } case CA_SET_PLAYER_SPEED: { #if 0 printf("::: trigger_player_bits == %d\n", trigger_player_bits); #endif for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { int move_stepsize = TILEX / stored_player[i].move_delay_value; if (action_arg == CA_ARG_SPEED_FASTER && stored_player[i].cannot_move) { action_arg_number = STEPSIZE_VERY_SLOW; } else if (action_arg == CA_ARG_SPEED_SLOWER || action_arg == CA_ARG_SPEED_FASTER) { action_arg_number = 2; action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE : CA_MODE_MULTIPLY); } else if (action_arg == CA_ARG_NUMBER_RESET) { action_arg_number = level.initial_player_stepsize[i]; } move_stepsize = getModifiedActionNumber(move_stepsize, action_mode, action_arg_number, action_arg_number_min, action_arg_number_max); SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE); } } break; } case CA_SET_PLAYER_SHIELD: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { if (action_arg == CA_ARG_SHIELD_OFF) { stored_player[i].shield_normal_time_left = 0; stored_player[i].shield_deadly_time_left = 0; } else if (action_arg == CA_ARG_SHIELD_NORMAL) { stored_player[i].shield_normal_time_left = 999999; } else if (action_arg == CA_ARG_SHIELD_DEADLY) { stored_player[i].shield_normal_time_left = 999999; stored_player[i].shield_deadly_time_left = 999999; } } } break; } #if USE_PLAYER_GRAVITY case CA_SET_PLAYER_GRAVITY: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { stored_player[i].gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : action_arg == CA_ARG_GRAVITY_ON ? TRUE : action_arg == CA_ARG_GRAVITY_TOGGLE ? !stored_player[i].gravity : stored_player[i].gravity); } } break; } #endif case CA_SET_PLAYER_ARTWORK: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { int artwork_element = action_arg_element; if (action_arg == CA_ARG_ELEMENT_RESET) artwork_element = (level.use_artwork_element[i] ? level.artwork_element[i] : stored_player[i].element_nr); #if USE_GFX_RESET_PLAYER_ARTWORK if (stored_player[i].artwork_element != artwork_element) stored_player[i].Frame = 0; #endif stored_player[i].artwork_element = artwork_element; SetPlayerWaiting(&stored_player[i], FALSE); /* set number of special actions for bored and sleeping animation */ stored_player[i].num_special_action_bored = get_num_special_action(artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); stored_player[i].num_special_action_sleeping = get_num_special_action(artwork_element, ACTION_SLEEPING_1, ACTION_SLEEPING_LAST); } } break; } case CA_SET_PLAYER_INVENTORY: { for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int j, k; if (trigger_player_bits & (1 << i)) { int inventory_element = action_arg_element; if (action_arg == CA_ARG_ELEMENT_TARGET || action_arg == CA_ARG_ELEMENT_TRIGGER || action_arg == CA_ARG_ELEMENT_ACTION) { int element = inventory_element; int collect_count = element_info[element].collect_count_initial; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } else if (action_arg == CA_ARG_INVENTORY_RM_TARGET || action_arg == CA_ARG_INVENTORY_RM_TRIGGER || action_arg == CA_ARG_INVENTORY_RM_ACTION) { if (player->inventory_infinite_element != EL_UNDEFINED && IS_EQUAL_OR_IN_GROUP(player->inventory_infinite_element, action_arg_element_raw)) player->inventory_infinite_element = EL_UNDEFINED; for (k = 0, j = 0; j < player->inventory_size; j++) { if (!IS_EQUAL_OR_IN_GROUP(player->inventory_element[j], action_arg_element_raw)) player->inventory_element[k++] = player->inventory_element[j]; } player->inventory_size = k; } else if (action_arg == CA_ARG_INVENTORY_RM_FIRST) { if (player->inventory_size > 0) { for (j = 0; j < player->inventory_size - 1; j++) player->inventory_element[j] = player->inventory_element[j + 1]; player->inventory_size--; } } else if (action_arg == CA_ARG_INVENTORY_RM_LAST) { if (player->inventory_size > 0) player->inventory_size--; } else if (action_arg == CA_ARG_INVENTORY_RM_ALL) { player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; } else if (action_arg == CA_ARG_INVENTORY_RESET) { player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; if (level.use_initial_inventory[i]) { for (j = 0; j < level.initial_inventory_size[i]; j++) { int element = level.initial_inventory_content[i][j]; int collect_count = element_info[element].collect_count_initial; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } } } } } break; } /* ---------- CE actions ---------------------------------------------- */ case CA_SET_CE_VALUE: { #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; CustomValue[x][y] = action_arg_number_new; if (CustomValue[x][y] != last_ce_value) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_CHANGES); CheckTriggeredElementChange(x, y, element, CE_VALUE_CHANGES_OF_X); if (CustomValue[x][y] == 0) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); } } #endif break; } case CA_SET_CE_SCORE: { #if USE_NEW_CUSTOM_VALUE int last_ce_score = ei->collect_score; ei->collect_score = action_arg_number_new; if (ei->collect_score != last_ce_score) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_CHANGES); CheckTriggeredElementChange(x, y, element, CE_SCORE_CHANGES_OF_X); if (ei->collect_score == 0) { int xx, yy; CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X); /* This is a very special case that seems to be a mixture between CheckElementChange() and CheckTriggeredElementChange(): while the first one only affects single elements that are triggered directly, the second one affects multiple elements in the playfield that are triggered indirectly by another element. This is a third case: Changing the CE score always affects multiple identical CEs, so every affected CE must be checked, not only the single CE for which the CE score was changed in the first place (as every instance of that CE shares the same CE score, and therefore also can change)! */ SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == element) CheckElementChange(xx, yy, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); } } } #endif break; } case CA_SET_CE_ARTWORK: { int artwork_element = action_arg_element; boolean reset_frame = FALSE; int xx, yy; if (action_arg == CA_ARG_ELEMENT_RESET) artwork_element = (ei->use_gfx_element ? ei->gfx_element_initial : element); if (ei->gfx_element != artwork_element) reset_frame = TRUE; ei->gfx_element = artwork_element; SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == element) { if (reset_frame) { ResetGfxAnimation(xx, yy); ResetRandomAnimationValue(xx, yy); } TEST_DrawLevelField(xx, yy); } } break; } /* ---------- engine actions ------------------------------------------ */ case CA_SET_ENGINE_SCAN_MODE: { InitPlayfieldScanMode(action_arg); break; } default: break; } } static void CreateFieldExt(int x, int y, int element, boolean is_change) { int old_element = Feld[x][y]; int new_element = GetElementFromGroupElement(element); int previous_move_direction = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; #endif boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y); boolean new_element_is_player = ELEM_IS_PLAYER(new_element); boolean add_player_onto_element = (new_element_is_player && #if USE_CODE_THAT_BREAKS_SNAKE_BITE /* this breaks SnakeBite when a snake is halfway through a door that closes */ /* NOW FIXED AT LEVEL INIT IN files.c */ new_element != EL_SOKOBAN_FIELD_PLAYER && #endif IS_WALKABLE(old_element)); #if 0 /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { Bang(x, y); return; } #endif if (!add_player_onto_element) { if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) RemoveMovingField(x, y); else RemoveField(x, y); Feld[x][y] = new_element; #if !USE_GFX_RESET_GFX_ANIMATION ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); #endif if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = previous_move_direction; #if USE_NEW_CUSTOM_VALUE if (element_info[new_element].use_last_ce_value) CustomValue[x][y] = last_ce_value; #endif InitField_WithBug1(x, y, FALSE); new_element = Feld[x][y]; /* element may have changed */ #if USE_GFX_RESET_GFX_ANIMATION ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); #endif TEST_DrawLevelField(x, y); if (GFX_CRUMBLED(new_element)) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } #if 1 /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ /* (must be checked after creating new element for walkable group elements) */ #if USE_FIX_KILLED_BY_NON_WALKABLE if (IS_PLAYER(x, y) && !player_explosion_protected && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { Bang(x, y); return; } #else if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { Bang(x, y); return; } #endif #endif /* "ChangeCount" not set yet to allow "entered by player" change one time */ if (new_element_is_player) RelocatePlayer(x, y, new_element); if (is_change) ChangeCount[x][y]++; /* count number of changes in the same frame */ TestIfBadThingTouchesPlayer(x, y); TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); } static void CreateField(int x, int y, int element) { CreateFieldExt(x, y, element, FALSE); } static void CreateElementFromChange(int x, int y, int element) { element = GET_VALID_RUNTIME_ELEMENT(element); #if USE_STOP_CHANGED_ELEMENTS if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { int old_element = Feld[x][y]; /* prevent changed element from moving in same engine frame unless both old and new element can either fall or move */ if ((!CAN_FALL(old_element) || !CAN_FALL(element)) && (!CAN_MOVE(old_element) || !CAN_MOVE(element))) Stop[x][y] = TRUE; } #endif CreateFieldExt(x, y, element, TRUE); } static boolean ChangeElement(int x, int y, int element, int page) { struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; int ce_value = CustomValue[x][y]; int ce_score = ei->collect_score; int target_element; int old_element = Feld[x][y]; /* always use default change event to prevent running into a loop */ if (ChangeEvent[x][y] == -1) ChangeEvent[x][y] = CE_DELAY; if (ChangeEvent[x][y] == CE_DELAY) { /* reset actual trigger element, trigger player and action element */ change->actual_trigger_element = EL_EMPTY; change->actual_trigger_player = EL_EMPTY; change->actual_trigger_player_bits = CH_PLAYER_NONE; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; } /* do not change elements more than a specified maximum number of changes */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame) return FALSE; ChangeCount[x][y]++; /* count number of changes in the same frame */ if (change->explode) { Bang(x, y); return TRUE; } if (change->use_target_content) { boolean complete_replace = TRUE; boolean can_replace[3][3]; int xx, yy; for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { boolean is_empty; boolean is_walkable; boolean is_diggable; boolean is_collectible; boolean is_removable; boolean is_destructible; int ex = x + xx - 1; int ey = y + yy - 1; int content_element = change->target_content.e[xx][yy]; int e; can_replace[xx][yy] = TRUE; if (ex == x && ey == y) /* do not check changing element itself */ continue; if (content_element == EL_EMPTY_SPACE) { can_replace[xx][yy] = FALSE; /* do not replace border with space */ continue; } if (!IN_LEV_FIELD(ex, ey)) { can_replace[xx][yy] = FALSE; complete_replace = FALSE; continue; } e = Feld[ex][ey]; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) e = MovingOrBlocked2Element(ex, ey); is_empty = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element))); is_walkable = (is_empty || IS_WALKABLE(e)); is_diggable = (is_empty || IS_DIGGABLE(e)); is_collectible = (is_empty || IS_COLLECTIBLE(e)); is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e)); is_removable = (is_diggable || is_collectible); can_replace[xx][yy] = (((change->replace_when == CP_WHEN_EMPTY && is_empty) || (change->replace_when == CP_WHEN_WALKABLE && is_walkable) || (change->replace_when == CP_WHEN_DIGGABLE && is_diggable) || (change->replace_when == CP_WHEN_COLLECTIBLE && is_collectible) || (change->replace_when == CP_WHEN_REMOVABLE && is_removable) || (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) && !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element))); if (!can_replace[xx][yy]) complete_replace = FALSE; } if (!change->only_if_complete || complete_replace) { boolean something_has_changed = FALSE; if (change->only_if_complete && change->use_random_replace && RND(100) < change->random_percentage) return FALSE; for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { int ex = x + xx - 1; int ey = y + yy - 1; int content_element; if (can_replace[xx][yy] && (!change->use_random_replace || RND(100) < change->random_percentage)) { if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) RemoveMovingField(ex, ey); ChangeEvent[ex][ey] = ChangeEvent[x][y]; content_element = change->target_content.e[xx][yy]; target_element = GET_TARGET_ELEMENT(element, content_element, change, ce_value, ce_score); CreateElementFromChange(ex, ey, target_element); something_has_changed = TRUE; /* for symmetry reasons, freeze newly created border elements */ if (ex != x || ey != y) Stop[ex][ey] = TRUE; /* no more moving in this frame */ } } if (something_has_changed) { PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); } } } else { target_element = GET_TARGET_ELEMENT(element, change->target_element, change, ce_value, ce_score); if (element == EL_DIAGONAL_GROWING || element == EL_DIAGONAL_SHRINKING) { target_element = Store[x][y]; Store[x][y] = EL_EMPTY; } CreateElementFromChange(x, y, target_element); PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); } /* this uses direct change before indirect change */ CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page); return TRUE; } #if USE_NEW_DELAYED_ACTION static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; boolean handle_action_before_change = FALSE; #ifdef DEBUG if (!CAN_CHANGE_OR_HAS_ACTION(element) && !CAN_CHANGE_OR_HAS_ACTION(Back[x][y])) { printf("\n\n"); printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", x, y, element, element_info[element].token_name); printf("HandleElementChange(): This should never happen!\n"); printf("\n\n"); } #endif /* this can happen with classic bombs on walkable, changing elements */ if (!CAN_CHANGE_OR_HAS_ACTION(element)) { #if 0 if (!CAN_CHANGE(Back[x][y])) /* prevent permanent repetition */ ChangeDelay[x][y] = 0; #endif return; } if (ChangeDelay[x][y] == 0) /* initialize element change */ { ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; if (change->can_change) { #if 1 /* !!! not clear why graphic animation should be reset at all here !!! */ /* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */ #if USE_GFX_RESET_WHEN_NOT_MOVING /* when a custom element is about to change (for example by change delay), do not reset graphic animation when the custom element is moving */ if (!IS_MOVING(x, y)) #endif { ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); } #endif if (change->pre_change_function) change->pre_change_function(x, y); } } ChangeDelay[x][y]--; if (ChangeDelay[x][y] != 0) /* continue element change */ { if (change->can_change) { int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (change->change_function) change->change_function(x, y); } } else /* finish element change */ { if (ChangePage[x][y] != -1) /* remember page from delayed change */ { page = ChangePage[x][y]; ChangePage[x][y] = -1; change = &ei->change_page[page]; } if (IS_MOVING(x, y)) /* never change a running system ;-) */ { ChangeDelay[x][y] = 1; /* try change after next move step */ ChangePage[x][y] = page; /* remember page to use for change */ return; } #if 1 /* special case: set new level random seed before changing element */ if (change->has_action && change->action_type == CA_SET_LEVEL_RANDOM_SEED) handle_action_before_change = TRUE; if (change->has_action && handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); #endif if (change->can_change) { if (ChangeElement(x, y, element, page)) { if (change->post_change_function) change->post_change_function(x, y); } } if (change->has_action && !handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); } } #else static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; #ifdef DEBUG if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y])) { printf("\n\n"); printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", x, y, element, element_info[element].token_name); printf("HandleElementChange(): This should never happen!\n"); printf("\n\n"); } #endif /* this can happen with classic bombs on walkable, changing elements */ if (!CAN_CHANGE(element)) { #if 0 if (!CAN_CHANGE(Back[x][y])) /* prevent permanent repetition */ ChangeDelay[x][y] = 0; #endif return; } if (ChangeDelay[x][y] == 0) /* initialize element change */ { ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); if (change->pre_change_function) change->pre_change_function(x, y); } ChangeDelay[x][y]--; if (ChangeDelay[x][y] != 0) /* continue element change */ { int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (change->change_function) change->change_function(x, y); } else /* finish element change */ { if (ChangePage[x][y] != -1) /* remember page from delayed change */ { page = ChangePage[x][y]; ChangePage[x][y] = -1; change = &ei->change_page[page]; } if (IS_MOVING(x, y)) /* never change a running system ;-) */ { ChangeDelay[x][y] = 1; /* try change after next move step */ ChangePage[x][y] = page; /* remember page to use for change */ return; } if (ChangeElement(x, y, element, page)) { if (change->post_change_function) change->post_change_function(x, y); } } } #endif static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, int trigger_element, int trigger_event, int trigger_player, int trigger_side, int trigger_page) { boolean change_done_any = FALSE; int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page); int i; if (!(trigger_events[trigger_element][trigger_event])) return FALSE; #if 0 printf("::: CheckTriggeredElementChangeExt %d ... [%d, %d, %d, '%s']\n", trigger_event, recursion_loop_depth, recursion_loop_detected, recursion_loop_element, EL_NAME(recursion_loop_element)); #endif RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; boolean change_done = FALSE; int p; if (!CAN_CHANGE_OR_HAS_ACTION(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; if (change->can_change_or_has_action && change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player && change->trigger_page & trigger_page_bits && IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) { change->actual_trigger_element = trigger_element; change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); #if 0 printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d\n", element, EL_NAME(element), p); #endif if ((change->can_change && !change_done) || change->has_action) { int x, y; SCAN_PLAYFIELD(x, y) { if (Feld[x][y] == element) { if (change->can_change && !change_done) { #if USE_FIX_NO_ACTION_AFTER_CHANGE /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; #endif #if 0 printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- CHANGE\n", element, EL_NAME(element), p); #endif ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; HandleElementChange(x, y, p); } #if USE_NEW_DELAYED_ACTION else if (change->has_action) { #if USE_FIX_NO_ACTION_AFTER_CHANGE /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; #endif #if 0 printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- ACTION\n", element, EL_NAME(element), p); #endif ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } #else if (change->has_action) { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } #endif } } if (change->can_change) { change_done = TRUE; change_done_any = TRUE; #if 0 printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- DONE\n", element, EL_NAME(element), p); #endif } } } } } RECURSION_LOOP_DETECTION_END(); return change_done_any; } static boolean CheckElementChangeExt(int x, int y, int element, int trigger_element, int trigger_event, int trigger_player, int trigger_side) { boolean change_done = FALSE; int p; if (!CAN_CHANGE_OR_HAS_ACTION(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) return FALSE; if (Feld[x][y] == EL_BLOCKED) { Blocked2Moving(x, y, &x, &y); element = Feld[x][y]; } #if 0 /* check if element has already changed */ if (Feld[x][y] != element) return FALSE; #else /* check if element has already changed or is about to change after moving */ if ((game.engine_version < VERSION_IDENT(3,2,0,7) && Feld[x][y] != element) || (game.engine_version >= VERSION_IDENT(3,2,0,7) && (ChangeCount[x][y] >= game.max_num_changes_per_frame || ChangePage[x][y] != -1))) return FALSE; #endif #if 0 printf("::: CheckElementChangeExt %d ... [%d, %d, %d, '%s']\n", trigger_event, recursion_loop_depth, recursion_loop_detected, recursion_loop_element, EL_NAME(recursion_loop_element)); #endif RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); #if 0 printf("::: X: trigger_player_bits == %d\n", trigger_player); #endif for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; /* check trigger element for all events where the element that is checked for changing interacts with a directly adjacent element -- this is different to element changes that affect other elements to change on the whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */ boolean check_trigger_element = (trigger_event == CE_TOUCHING_X || trigger_event == CE_HITTING_X || trigger_event == CE_HIT_BY_X || #if 1 /* this one was forgotten until 3.2.3 */ trigger_event == CE_DIGGING_X); #endif if (change->can_change_or_has_action && change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player && (!check_trigger_element || IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))) { change->actual_trigger_element = trigger_element; change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); /* special case: trigger element not at (x,y) position for some events */ if (check_trigger_element) { static struct { int dx, dy; } move_xy[] = { { 0, 0 }, { -1, 0 }, { +1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, +1 } }; int xx = x + move_xy[MV_DIR_OPPOSITE(trigger_side)].dx; int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy; change->actual_trigger_ce_value = CustomValue[xx][yy]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); } if (change->can_change && !change_done) { ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; HandleElementChange(x, y, p); change_done = TRUE; } #if USE_NEW_DELAYED_ACTION else if (change->has_action) { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } #else if (change->has_action) { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } #endif } } RECURSION_LOOP_DETECTION_END(); return change_done; } static void PlayPlayerSound(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int sound_element = player->artwork_element; int last_action = player->last_action_waiting; int action = player->action_waiting; if (player->is_waiting) { if (action != last_action) PlayLevelSoundElementAction(jx, jy, sound_element, action); else PlayLevelSoundElementActionIfLoop(jx, jy, sound_element, action); } else { if (action != last_action) StopSound(element_info[sound_element].sound[last_action]); if (last_action == ACTION_SLEEPING) PlayLevelSoundElementAction(jx, jy, sound_element, ACTION_AWAKENING); } } static void PlayAllPlayersSound() { int i; for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) PlayPlayerSound(&stored_player[i]); } static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) { boolean last_waiting = player->is_waiting; int move_dir = player->MovDir; player->dir_waiting = move_dir; player->last_action_waiting = player->action_waiting; if (is_waiting) { if (!last_waiting) /* not waiting -> waiting */ { player->is_waiting = TRUE; player->frame_counter_bored = FrameCounter + game.player_boring_delay_fixed + GetSimpleRandom(game.player_boring_delay_random); player->frame_counter_sleeping = FrameCounter + game.player_sleeping_delay_fixed + GetSimpleRandom(game.player_sleeping_delay_random); InitPlayerGfxAnimation(player, ACTION_WAITING, move_dir); } if (game.player_sleeping_delay_fixed + game.player_sleeping_delay_random > 0 && player->anim_delay_counter == 0 && player->post_delay_counter == 0 && FrameCounter >= player->frame_counter_sleeping) player->is_sleeping = TRUE; else if (game.player_boring_delay_fixed + game.player_boring_delay_random > 0 && FrameCounter >= player->frame_counter_bored) player->is_bored = TRUE; player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING : player->is_bored ? ACTION_BORING : ACTION_WAITING); if (player->is_sleeping && player->use_murphy) { /* special case for sleeping Murphy when leaning against non-free tile */ if (!IN_LEV_FIELD(player->jx - 1, player->jy) || (Feld[player->jx - 1][player->jy] != EL_EMPTY && !IS_MOVING(player->jx - 1, player->jy))) move_dir = MV_LEFT; else if (!IN_LEV_FIELD(player->jx + 1, player->jy) || (Feld[player->jx + 1][player->jy] != EL_EMPTY && !IS_MOVING(player->jx + 1, player->jy))) move_dir = MV_RIGHT; else player->is_sleeping = FALSE; player->dir_waiting = move_dir; } if (player->is_sleeping) { if (player->num_special_action_sleeping > 0) { if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) { int last_special_action = player->special_action_sleeping; int num_special_action = player->num_special_action_sleeping; int special_action = (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 : last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING : last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ? last_special_action + 1 : ACTION_SLEEPING); int special_graphic = el_act_dir2img(player->artwork_element, special_action, move_dir); player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_sleeping = special_action; } if (player->anim_delay_counter > 0) { player->action_waiting = player->special_action_sleeping; player->anim_delay_counter--; } else if (player->post_delay_counter > 0) { player->post_delay_counter--; } } } else if (player->is_bored) { if (player->num_special_action_bored > 0) { if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) { int special_action = ACTION_BORING_1 + GetSimpleRandom(player->num_special_action_bored); int special_graphic = el_act_dir2img(player->artwork_element, special_action, move_dir); player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_bored = special_action; } if (player->anim_delay_counter > 0) { player->action_waiting = player->special_action_bored; player->anim_delay_counter--; } else if (player->post_delay_counter > 0) { player->post_delay_counter--; } } } } else if (last_waiting) /* waiting -> not waiting */ { player->is_waiting = FALSE; player->is_bored = FALSE; player->is_sleeping = FALSE; player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; player->anim_delay_counter = 0; player->post_delay_counter = 0; player->dir_waiting = player->MovDir; player->action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; player->special_action_sleeping = ACTION_DEFAULT; } } static byte PlayerActions(struct PlayerInfo *player, byte player_action) { boolean moved = FALSE, snapped = FALSE, dropped = FALSE; int left = player_action & JOY_LEFT; int right = player_action & JOY_RIGHT; int up = player_action & JOY_UP; int down = player_action & JOY_DOWN; int button1 = player_action & JOY_BUTTON_1; int button2 = player_action & JOY_BUTTON_2; int dx = (left ? -1 : right ? 1 : 0); int dy = (up ? -1 : down ? 1 : 0); if (!player->active || tape.pausing) return 0; if (player_action) { if (button1) snapped = SnapField(player, dx, dy); else { if (button2) dropped = DropElement(player); moved = MovePlayer(player, dx, dy); } if (tape.single_step && tape.recording && !tape.pausing) { #if 1 /* as it is called "single step mode", just return to pause mode when the player stopped moving after one tile (or never starts moving at all) */ if (!player->is_moving) #else /* this is buggy: there are quite some cases where the single step mode does not return to pause mode (like pushing things that don't move or simply by trying to run against a wall) */ if (button1 || (dropped && !moved)) #endif { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); SnapField(player, 0, 0); /* stop snapping */ } } SetPlayerWaiting(player, FALSE); return player_action; } else { /* no actions for this player (no input at player's configured device) */ DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); CheckGravityMovementWhenNotMoving(player); if (player->MovPos == 0) SetPlayerWaiting(player, TRUE); if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; return 0; } } static void CheckLevelTime() { int i; /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ { PlayerWins(local_player); AllPlayersGone = TRUE; level.native_em_level->lev->home = -1; } if (level.native_em_level->ply[0]->alive == 0 && level.native_em_level->ply[1]->alive == 0 && level.native_em_level->ply[2]->alive == 0 && level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { if (game_sp.LevelSolved && !game_sp.GameOver) /* game won */ { PlayerWins(local_player); game_sp.GameOver = TRUE; AllPlayersGone = TRUE; } if (game_sp.GameOver) /* game lost */ AllPlayersGone = TRUE; } if (TimeFrames >= FRAMES_PER_SECOND) { TimeFrames = 0; TapeTime++; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (SHIELD_ON(player)) { player->shield_normal_time_left--; if (player->shield_deadly_time_left > 0) player->shield_deadly_time_left--; } } if (!local_player->LevelSolved && !level.use_step_counter) { TimePlayed++; if (TimeLeft > 0) { TimeLeft--; if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif if (!TimeLeft && setup.time_limit) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) level.native_em_level->lev->killed_out_of_time = TRUE; else for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } } #if 1 else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } #else else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); #endif level.native_em_level->lev->time = (level.time == 0 ? TimePlayed : TimeLeft); } if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); } #if 1 UpdateAndDisplayGameControlValues(); #else UpdateGameDoorValues(); DrawGameDoorValues(); #endif } void AdvanceFrameAndPlayerCounters(int player_nr) { int i; /* advance frame counters (global frame counter and time frame counter) */ FrameCounter++; TimeFrames++; /* advance player counters (counters for move delay, move animation etc.) */ for (i = 0; i < MAX_PLAYERS; i++) { boolean advance_player_counters = (player_nr == -1 || player_nr == i); int move_delay_value = stored_player[i].move_delay_value; int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value; if (!advance_player_counters) /* not all players may be affected */ continue; #if USE_NEW_PLAYER_ANIM if (move_frames == 0) /* less than one move per game frame */ { int stepsize = TILEX / move_delay_value; int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED; int count = (stored_player[i].is_moving ? ABS(stored_player[i].MovPos) / stepsize : FrameCounter); if (count % delay == 0) move_frames = 1; } #endif stored_player[i].Frame += move_frames; if (stored_player[i].MovPos != 0) stored_player[i].StepFrame += move_frames; if (stored_player[i].move_delay > 0) stored_player[i].move_delay--; /* due to bugs in previous versions, counter must count up, not down */ if (stored_player[i].push_delay != -1) stored_player[i].push_delay++; if (stored_player[i].drop_delay > 0) stored_player[i].drop_delay--; if (stored_player[i].is_dropping_pressed) stored_player[i].drop_pressed_delay++; } } void StartGameActions(boolean init_network_game, boolean record_tape, long random_seed) { unsigned long new_random_seed = InitRND(random_seed); if (record_tape) TapeStartRecording(new_random_seed); #if defined(NETWORK_AVALIABLE) if (init_network_game) { SendToServer_StartPlaying(); return; } #endif InitGame(); } void GameActions() { static unsigned long game_frame_delay = 0; unsigned long game_frame_delay_value; byte *recorded_player_action; byte summarized_player_action = 0; byte tape_action[MAX_PLAYERS]; int i; /* detect endless loops, caused by custom element programming */ if (recursion_loop_detected && recursion_loop_depth == 0) { char *message = getStringCat3("Internal Error ! Element ", EL_NAME(recursion_loop_element), " caused endless loop ! Quit the game ?"); Error(ERR_WARN, "element '%s' caused endless loop in game engine", EL_NAME(recursion_loop_element)); RequestQuitGameExt(FALSE, level_editor_test_game, message); recursion_loop_detected = FALSE; /* if game should be continued */ free(message); return; } if (game.restart_level) StartGameActions(options.network, setup.autorecord, level.random_seed); /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ { PlayerWins(local_player); AllPlayersGone = TRUE; level.native_em_level->lev->home = -1; } if (level.native_em_level->ply[0]->alive == 0 && level.native_em_level->ply[1]->alive == 0 && level.native_em_level->ply[2]->alive == 0 && level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { if (game_sp.LevelSolved && !game_sp.GameOver) /* game won */ { PlayerWins(local_player); game_sp.GameOver = TRUE; AllPlayersGone = TRUE; } if (game_sp.GameOver) /* game lost */ AllPlayersGone = TRUE; } if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) TapeStop(); if (game_status != GAME_MODE_PLAYING) /* status might have changed */ return; game_frame_delay_value = (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay); if (tape.playing && tape.warp_forward && !tape.pausing) game_frame_delay_value = 0; /* ---------- main game synchronization point ---------- */ WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); if (network_playing && !network_player_action_received) { /* try to get network player actions in time */ #if defined(NETWORK_AVALIABLE) /* last chance to get network player actions without main loop delay */ HandleNetworking(); #endif /* game was quit by network peer */ if (game_status != GAME_MODE_PLAYING) return; if (!network_player_action_received) return; /* failed to get network player actions in time */ /* do not yet reset "network_player_action_received" (for tape.pausing) */ } if (tape.pausing) return; /* at this point we know that we really continue executing the game */ network_player_action_received = FALSE; /* when playing tape, read previously recorded player input from tape data */ recorded_player_action = (tape.playing ? TapePlayAction() : NULL); #if 1 /* TapePlayAction() may return NULL when toggling to "pause before death" */ if (tape.pausing) return; #endif if (tape.set_centered_player) { game.centered_player_nr_next = tape.centered_player_nr_next; game.set_centered_player = TRUE; } for (i = 0; i < MAX_PLAYERS; i++) { summarized_player_action |= stored_player[i].action; if (!network_playing) stored_player[i].effective_action = stored_player[i].action; } #if defined(NETWORK_AVALIABLE) if (network_playing) SendToServer_MovePlayer(summarized_player_action); #endif if (!options.network && !setup.team_mode) local_player->effective_action = summarized_player_action; if (setup.team_mode && setup.input_on_focus && game.centered_player_nr != -1) { for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = (i == game.centered_player_nr ? summarized_player_action : 0); } if (recorded_player_action != NULL) for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = recorded_player_action[i]; for (i = 0; i < MAX_PLAYERS; i++) { tape_action[i] = stored_player[i].effective_action; /* (this can only happen in the R'n'D game engine) */ if (tape.recording && tape_action[i] && !tape.player_participates[i]) tape.player_participates[i] = TRUE; /* player just appeared from CE */ } /* only record actions from input devices, but not programmed actions */ if (tape.recording) TapeRecordAction(tape_action); #if USE_NEW_PLAYER_ASSIGNMENTS { byte mapped_action[MAX_PLAYERS]; for (i = 0; i < MAX_PLAYERS; i++) mapped_action[i] = stored_player[map_player_action[i]].effective_action; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = mapped_action[i]; } #endif if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { GameActions_EM_Main(); } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { GameActions_SP_Main(); } else { GameActions_RND(); } } void GameActions_EM_Main() { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; GameActions_EM(effective_action, warp_mode); CheckLevelTime(); AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ } void GameActions_SP_Main() { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; GameActions_SP(effective_action, warp_mode); CheckLevelTime(); AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ } void GameActions_RND() { int magic_wall_x = 0, magic_wall_y = 0; int i, x, y, element, graphic; InitPlayfieldScanModeVars(); #if USE_ONE_MORE_CHANGE_PER_FRAME if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; } } #endif if (game.set_centered_player) { boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND(); /* switching to "all players" only possible if all players fit to screen */ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } /* do not switch focus to non-existing (or non-active) player */ if (game.centered_player_nr_next >= 0 && !stored_player[game.centered_player_nr_next].active) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } } if (game.set_centered_player && ScreenMovPos == 0) /* screen currently aligned at tile position */ { int sx, sy; if (game.centered_player_nr_next == -1) { setScreenCenteredToAllPlayers(&sx, &sy); } else { sx = stored_player[game.centered_player_nr_next].jx; sy = stored_player[game.centered_player_nr_next].jy; } game.centered_player_nr = game.centered_player_nr_next; game.set_centered_player = FALSE; DrawRelocateScreen(0, 0, sx, sy, MV_NONE, TRUE, setup.quick_switch); DrawGameDoorValues(); } for (i = 0; i < MAX_PLAYERS; i++) { int actual_player_action = stored_player[i].effective_action; #if 1 /* !!! THIS BREAKS THE FOLLOWING TAPES: !!! - rnd_equinox_tetrachloride 048 - rnd_equinox_tetrachloride_ii 096 - rnd_emanuel_schmieg 002 - doctor_sloan_ww 001, 020 */ if (stored_player[i].MovPos == 0) CheckGravityMovement(&stored_player[i]); #endif /* overwrite programmed action with tape action */ if (stored_player[i].programmed_action) actual_player_action = stored_player[i].programmed_action; PlayerActions(&stored_player[i], actual_player_action); ScrollPlayer(&stored_player[i], SCROLL_GO_ON); } ScrollScreen(NULL, SCROLL_GO_ON); /* for backwards compatibility, the following code emulates a fixed bug that occured when pushing elements (causing elements that just made their last pushing step to already (if possible) make their first falling step in the same game frame, which is bad); this code is also needed to use the famous "spring push bug" which is used in older levels and might be wanted to be used also in newer levels, but in this case the buggy pushing code is only affecting the "spring" element and no other elements */ if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug) { for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int x = player->jx; int y = player->jy; if (player->active && player->is_pushing && player->is_moving && IS_MOVING(x, y) && (game.engine_version < VERSION_IDENT(2,2,0,7) || Feld[x][y] == EL_SPRING)) { ContinueMoving(x, y); /* continue moving after pushing (this is actually a bug) */ if (!IS_MOVING(x, y)) Stop[x][y] = FALSE; } } } #if 0 debug_print_timestamp(0, "start main loop profiling"); #endif SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; /* this must be handled before main playfield loop */ if (Feld[x][y] == EL_PLAYER_IS_LEAVING) { MovDelay[x][y]--; if (MovDelay[x][y] <= 0) RemoveField(x, y); } #if USE_NEW_SNAP_DELAY if (Feld[x][y] == EL_ELEMENT_SNAPPING) { MovDelay[x][y]--; if (MovDelay[x][y] <= 0) { RemoveField(x, y); TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); /* for empty space */ } } #endif #if DEBUG if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1) { printf("GameActions(): x = %d, y = %d: ChangePage != -1\n", x, y); printf("GameActions(): This should never happen!\n"); ChangePage[x][y] = -1; } #endif Stop[x][y] = FALSE; if (WasJustMoving[x][y] > 0) WasJustMoving[x][y]--; if (WasJustFalling[x][y] > 0) WasJustFalling[x][y]--; if (CheckCollision[x][y] > 0) CheckCollision[x][y]--; if (CheckImpact[x][y] > 0) CheckImpact[x][y]--; GfxFrame[x][y]++; /* reset finished pushing action (not done in ContinueMoving() to allow continuous pushing animation for elements with zero push delay) */ if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } #if DEBUG if (IS_BLOCKED(x, y)) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); if (!IS_MOVING(oldx, oldy)) { printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n"); printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y); printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy); printf("GameActions(): This should never happen!\n"); } } #endif } #if 0 debug_print_timestamp(0, "- time for pre-main loop:"); #endif #if 0 // -------------------- !!! TEST ONLY !!! -------------------- SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); #if 1 { #if 1 int element2 = element; int graphic2 = graphic; #else int element2 = Feld[x][y]; int graphic2 = el_act_dir2img(element2, GfxAction[x][y], GfxDir[x][y]); #endif int last_gfx_frame = GfxFrame[x][y]; if (graphic_info[graphic2].anim_global_sync) GfxFrame[x][y] = FrameCounter; else if (ANIM_MODE(graphic2) == ANIM_CE_VALUE) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic2) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element2].collect_score; else if (ANIM_MODE(graphic2) == ANIM_CE_DELAY) GfxFrame[x][y] = ChangeDelay[x][y]; if (redraw && GfxFrame[x][y] != last_gfx_frame) DrawLevelGraphicAnimation(x, y, graphic2); } #else ResetGfxFrame(x, y, TRUE); #endif #if 1 if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) ResetRandomAnimationValue(x, y); #endif #if 1 SetRandomAnimationValue(x, y); #endif #if 1 PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); #endif } #endif // -------------------- !!! TEST ONLY !!! -------------------- #if 0 debug_print_timestamp(0, "- time for TEST loop: -->"); #endif SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); ResetGfxFrame(x, y, TRUE); if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) ResetRandomAnimationValue(x, y); SetRandomAnimationValue(x, y); PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); if (IS_INACTIVE(element)) { if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); continue; } /* this may take place after moving, so 'element' may have changed */ if (IS_CHANGING(x, y) && (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y])) { int page = element_info[element].event_page_nr[CE_DELAY]; #if 1 HandleElementChange(x, y, page); #else if (CAN_CHANGE(element)) HandleElementChange(x, y, page); if (HAS_ACTION(element)) ExecuteCustomElementAction(x, y, element, page); #endif element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); } #if 0 // --------------------------------------------------------------------- if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic) && !IS_MOVING(x, y) && !Stop[x][y]) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) TEST_DrawTwinkleOnField(x, y); } else if (IS_MOVING(x, y)) ContinueMoving(x, y); else { switch (element) { case EL_ACID: case EL_EXIT_OPEN: case EL_EM_EXIT_OPEN: case EL_SP_EXIT_OPEN: case EL_STEEL_EXIT_OPEN: case EL_EM_STEEL_EXIT_OPEN: case EL_SP_TERMINAL: case EL_SP_TERMINAL_ACTIVE: case EL_EXTRA_TIME: case EL_SHIELD_NORMAL: case EL_SHIELD_DEADLY: if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); break; case EL_DYNAMITE_ACTIVE: case EL_EM_DYNAMITE_ACTIVE: case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: case EL_DYNABOMB_PLAYER_4_ACTIVE: case EL_SP_DISK_RED_ACTIVE: CheckDynamite(x, y); break; case EL_AMOEBA_GROWING: AmoebeWaechst(x, y); break; case EL_AMOEBA_SHRINKING: AmoebaDisappearing(x, y); break; #if !USE_NEW_AMOEBA_CODE case EL_AMOEBA_WET: case EL_AMOEBA_DRY: case EL_AMOEBA_FULL: case EL_BD_AMOEBA: case EL_EMC_DRIPPER: AmoebeAbleger(x, y); break; #endif case EL_GAME_OF_LIFE: case EL_BIOMAZE: Life(x, y); break; case EL_EXIT_CLOSED: CheckExit(x, y); break; case EL_EM_EXIT_CLOSED: CheckExitEM(x, y); break; case EL_STEEL_EXIT_CLOSED: CheckExitSteel(x, y); break; case EL_EM_STEEL_EXIT_CLOSED: CheckExitSteelEM(x, y); break; case EL_SP_EXIT_CLOSED: CheckExitSP(x, y); break; case EL_EXPANDABLE_WALL_GROWING: case EL_EXPANDABLE_STEELWALL_GROWING: MauerWaechst(x, y); break; case EL_EXPANDABLE_WALL: case EL_EXPANDABLE_WALL_HORIZONTAL: case EL_EXPANDABLE_WALL_VERTICAL: case EL_EXPANDABLE_WALL_ANY: case EL_BD_EXPANDABLE_WALL: MauerAbleger(x, y); break; case EL_EXPANDABLE_STEELWALL_HORIZONTAL: case EL_EXPANDABLE_STEELWALL_VERTICAL: case EL_EXPANDABLE_STEELWALL_ANY: MauerAblegerStahl(x, y); break; case EL_FLAMES: CheckForDragon(x, y); break; case EL_EXPLOSION: break; case EL_ELEMENT_SNAPPING: case EL_DIAGONAL_SHRINKING: case EL_DIAGONAL_GROWING: { graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); DrawLevelGraphicAnimationIfNeeded(x, y, graphic); break; } default: if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); break; } } #else // --------------------------------------------------------------------- if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic) && !IS_MOVING(x, y) && !Stop[x][y]) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) TEST_DrawTwinkleOnField(x, y); } else if ((element == EL_ACID || element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || element == EL_SP_EXIT_OPEN || element == EL_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN || element == EL_SP_TERMINAL || element == EL_SP_TERMINAL_ACTIVE || element == EL_EXTRA_TIME || element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) && IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); else if (IS_MOVING(x, y)) ContinueMoving(x, y); else if (IS_ACTIVE_BOMB(element)) CheckDynamite(x, y); else if (element == EL_AMOEBA_GROWING) AmoebeWaechst(x, y); else if (element == EL_AMOEBA_SHRINKING) AmoebaDisappearing(x, y); #if !USE_NEW_AMOEBA_CODE else if (IS_AMOEBALIVE(element)) AmoebeAbleger(x, y); #endif else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE) Life(x, y); else if (element == EL_EXIT_CLOSED) CheckExit(x, y); else if (element == EL_EM_EXIT_CLOSED) CheckExitEM(x, y); else if (element == EL_STEEL_EXIT_CLOSED) CheckExitSteel(x, y); else if (element == EL_EM_STEEL_EXIT_CLOSED) CheckExitSteelEM(x, y); else if (element == EL_SP_EXIT_CLOSED) CheckExitSP(x, y); else if (element == EL_EXPANDABLE_WALL_GROWING || element == EL_EXPANDABLE_STEELWALL_GROWING) MauerWaechst(x, y); else if (element == EL_EXPANDABLE_WALL || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_VERTICAL || element == EL_EXPANDABLE_WALL_ANY || element == EL_BD_EXPANDABLE_WALL) MauerAbleger(x, y); else if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || element == EL_EXPANDABLE_STEELWALL_VERTICAL || element == EL_EXPANDABLE_STEELWALL_ANY) MauerAblegerStahl(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); else if (element == EL_EXPLOSION) ; /* drawing of correct explosion animation is handled separately */ else if (element == EL_ELEMENT_SNAPPING || element == EL_DIAGONAL_SHRINKING || element == EL_DIAGONAL_GROWING) { graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); DrawLevelGraphicAnimationIfNeeded(x, y, graphic); } else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); #endif // --------------------------------------------------------------------- if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); if (game.magic_wall_active) { int jx = local_player->jx, jy = local_player->jy; /* play the element sound at the position nearest to the player */ if ((element == EL_MAGIC_WALL_FULL || element == EL_MAGIC_WALL_ACTIVE || element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_FULL || element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_EMPTYING || element == EL_DC_MAGIC_WALL_FULL || element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_EMPTYING) && ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy)) { magic_wall_x = x; magic_wall_y = y; } } } #if 0 debug_print_timestamp(0, "- time for MAIN loop: -->"); #endif #if USE_NEW_AMOEBA_CODE /* new experimental amoeba growth stuff */ if (!(FrameCounter % 8)) { static unsigned long random = 1684108901; for (i = 0; i < level.amoeba_speed * 28 / 8; i++) { x = RND(lev_fieldx); y = RND(lev_fieldy); element = Feld[x][y]; if (!IS_PLAYER(x,y) && (element == EL_EMPTY || CAN_GROW_INTO(element) || element == EL_QUICKSAND_EMPTY || element == EL_QUICKSAND_FAST_EMPTY || element == EL_ACID_SPLASH_LEFT || element == EL_ACID_SPLASH_RIGHT)) { if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) Feld[x][y] = EL_AMOEBA_DROP; } random = random * 129 + 1; } } #endif #if 0 if (game.explosions_delayed) #endif { game.explosions_delayed = FALSE; SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; if (ExplodeField[x][y]) Explode(x, y, EX_PHASE_START, ExplodeField[x][y]); else if (element == EL_EXPLOSION) Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL); ExplodeField[x][y] = EX_TYPE_NONE; } game.explosions_delayed = TRUE; } if (game.magic_wall_active) { if (!(game.magic_wall_time_left % 4)) { int element = Feld[magic_wall_x][magic_wall_y]; if (element == EL_BD_MAGIC_WALL_FULL || element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_EMPTYING) PlayLevelSound(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE); else if (element == EL_DC_MAGIC_WALL_FULL || element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_EMPTYING) PlayLevelSound(magic_wall_x, magic_wall_y, SND_DC_MAGIC_WALL_ACTIVE); else PlayLevelSound(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE); } if (game.magic_wall_time_left > 0) { game.magic_wall_time_left--; if (!game.magic_wall_time_left) { SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; if (element == EL_MAGIC_WALL_ACTIVE || element == EL_MAGIC_WALL_FULL) { Feld[x][y] = EL_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } else if (element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_FULL) { Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } else if (element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_FULL) { Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } } game.magic_wall_active = FALSE; } } } if (game.light_time_left > 0) { game.light_time_left--; if (game.light_time_left == 0) RedrawAllLightSwitchesAndInvisibleElements(); } if (game.timegate_time_left > 0) { game.timegate_time_left--; if (game.timegate_time_left == 0) CloseAllOpenTimegates(); } if (game.lenses_time_left > 0) { game.lenses_time_left--; if (game.lenses_time_left == 0) RedrawAllInvisibleElementsForLenses(); } if (game.magnify_time_left > 0) { game.magnify_time_left--; if (game.magnify_time_left == 0) RedrawAllInvisibleElementsForMagnifier(); } for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (SHIELD_ON(player)) { if (player->shield_deadly_time_left) PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); else if (player->shield_normal_time_left) PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); } } #if USE_DELAYED_GFX_REDRAW SCAN_PLAYFIELD(x, y) { #if 1 if (GfxRedraw[x][y] != GFX_REDRAW_NONE) #else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)) && GfxRedraw[x][y] != GFX_REDRAW_NONE) #endif { /* !!! PROBLEM: THIS REDRAWS THE PLAYFIELD _AFTER_ THE SCAN, BUT TILES !!! MAY HAVE CHANGED AFTER BEING DRAWN DURING PLAYFIELD SCAN !!! */ if (GfxRedraw[x][y] & GFX_REDRAW_TILE) DrawLevelField(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED) DrawLevelFieldCrumbled(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS) DrawLevelFieldCrumbledNeighbours(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_TWINKLED) DrawTwinkleOnField(x, y); } GfxRedraw[x][y] = GFX_REDRAW_NONE; } #endif CheckLevelTime(); DrawAllPlayers(); PlayAllPlayersSound(); if (options.debug) /* calculate frames per second */ { static unsigned long fps_counter = 0; static int fps_frames = 0; unsigned long fps_delay_ms = Counter() - fps_counter; fps_frames++; if (fps_delay_ms >= 500) /* calculate fps every 0.5 seconds */ { global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; fps_frames = 0; fps_counter = Counter(); } redraw_mask |= REDRAW_FPS; } AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ if (local_player->show_envelope != 0 && local_player->MovPos == 0) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); local_player->show_envelope = 0; } #if 0 debug_print_timestamp(0, "stop main loop profiling "); printf("----------------------------------------------------------\n"); #endif /* use random number generator in every frame to make it less predictable */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) { int min_x = x, min_y = y, max_x = x, max_y = y; int i; for (i = 0; i < MAX_PLAYERS; i++) { int jx = stored_player[i].jx, jy = stored_player[i].jy; if (!stored_player[i].active || &stored_player[i] == player) continue; min_x = MIN(min_x, jx); min_y = MIN(min_y, jy); max_x = MAX(max_x, jx); max_y = MAX(max_y, jy); } return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY); } static boolean AllPlayersInVisibleScreen() { int i; for (i = 0; i < MAX_PLAYERS; i++) { int jx = stored_player[i].jx, jy = stored_player[i].jy; if (!stored_player[i].active) continue; if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) return FALSE; } return TRUE; } void ScrollLevel(int dx, int dy) { #if 0 /* (directly solved in BlitBitmap() now) */ static Bitmap *bitmap_db_field2 = NULL; int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); int x, y; #else int x, y; #endif #if 0 /* !!! THIS IS APPARENTLY WRONG FOR PLAYER RELOCATION !!! */ /* only horizontal XOR vertical scroll direction allowed */ if ((dx == 0 && dy == 0) || (dx != 0 && dy != 0)) return; #endif #if 0 /* (directly solved in BlitBitmap() now) */ if (bitmap_db_field2 == NULL) bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); /* needed when blitting directly to same bitmap -- should not be needed with recent SDL libraries, but apparently does not work in 1.2.11 directly */ BlitBitmap(drawto_field, bitmap_db_field2, FX + TILEX * (dx == -1) - softscroll_offset, FY + TILEY * (dy == -1) - softscroll_offset, SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset); BlitBitmap(bitmap_db_field2, drawto_field, FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset, SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset); #else #if 0 /* !!! DOES NOT WORK FOR DIAGONAL PLAYER RELOCATION !!! */ int xsize = (BX2 - BX1 + 1); int ysize = (BY2 - BY1 + 1); int start = (dx != 0 ? (dx == -1 ? BX1 : BX2) : (dy == -1 ? BY1 : BY2)); int end = (dx != 0 ? (dx == -1 ? BX2 : BX1) : (dy == -1 ? BY2 : BY1)); int step = (start < end ? +1 : -1); for (i = start; i != end; i += step) { BlitBitmap(drawto_field, drawto_field, FX + TILEX * (dx != 0 ? i + step : 0), FY + TILEY * (dy != 0 ? i + step : 0), TILEX * (dx != 0 ? 1 : xsize), TILEY * (dy != 0 ? 1 : ysize), FX + TILEX * (dx != 0 ? i : 0), FY + TILEY * (dy != 0 ? i : 0)); } #else int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); BlitBitmap(drawto_field, drawto_field, FX + TILEX * (dx == -1) - softscroll_offset, FY + TILEY * (dy == -1) - softscroll_offset, SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset); #endif #endif if (dx != 0) { x = (dx == 1 ? BX1 : BX2); for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); } if (dy != 0) { y = (dy == 1 ? BY1 : BY2); for (x = BX1; x <= BX2; x++) DrawScreenField(x, y); } redraw_mask |= REDRAW_FIELD; } static boolean canFallDown(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; return (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1) || (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) && IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) && !IS_WALKABLE_INSIDE(Feld[jx][jy])); } static boolean canPassField(int x, int y, int move_dir) { int opposite_dir = MV_DIR_OPPOSITE(move_dir); int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int nextx = x + dx; int nexty = y + dy; int element = Feld[x][y]; return (IS_PASSABLE_FROM(element, opposite_dir) && !CAN_MOVE(element) && IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) && IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) && (level.can_pass_to_walkable || IS_FREE(nextx, nexty))); } static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) { int opposite_dir = MV_DIR_OPPOSITE(move_dir); int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && IS_GRAVITY_REACHABLE(Feld[newx][newy]) && (IS_DIGGABLE(Feld[newx][newy]) || IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || canPassField(newx, newy, move_dir))); } static void CheckGravityMovement(struct PlayerInfo *player) { #if USE_PLAYER_GRAVITY if (player->gravity && !player->programmed_action) #else if (game.gravity && !player->programmed_action) #endif { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; boolean player_is_snapping = (player->effective_action & JOY_BUTTON_1); int jx = player->jx, jy = player->jy; boolean player_is_moving_to_valid_field = (!player_is_snapping && (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) || canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical))); boolean player_can_fall_down = canFallDown(player); if (player_can_fall_down && !player_is_moving_to_valid_field) player->programmed_action = MV_DOWN; } } static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) { return CheckGravityMovement(player); #if USE_PLAYER_GRAVITY if (player->gravity && !player->programmed_action) #else if (game.gravity && !player->programmed_action) #endif { int jx = player->jx, jy = player->jy; boolean field_under_player_is_free = (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1)); boolean player_is_standing_on_valid_field = (IS_WALKABLE_INSIDE(Feld[jx][jy]) || (IS_WALKABLE(Feld[jx][jy]) && !(element_info[Feld[jx][jy]].access_direction & MV_DOWN))); if (field_under_player_is_free && !player_is_standing_on_valid_field) player->programmed_action = MV_DOWN; } } /* MovePlayerOneStep() ----------------------------------------------------------------------------- dx, dy: direction (non-diagonal) to try to move the player to real_dx, real_dy: direction as read from input device (can be diagonal) */ boolean MovePlayerOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { int jx = player->jx, jy = player->jy; int new_jx = jx + dx, new_jy = jy + dy; #if !USE_FIXED_DONT_RUN_INTO int element; #endif int can_move; boolean player_can_move = !player->cannot_move; if (!player->active || (!dx && !dy)) return MP_NO_ACTION; player->MovDir = (dx < 0 ? MV_LEFT : dx > 0 ? MV_RIGHT : dy < 0 ? MV_UP : dy > 0 ? MV_DOWN : MV_NONE); if (!IN_LEV_FIELD(new_jx, new_jy)) return MP_NO_ACTION; if (!player_can_move) { if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } } #if 1 if (!options.network && game.centered_player_nr == -1 && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; #else if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; #endif #if !USE_FIXED_DONT_RUN_INTO element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); /* (moved to DigField()) */ if (player_can_move && DONT_RUN_INTO(element)) { if (element == EL_ACID && dx == 0 && dy == 1) { SplashAcid(new_jx, new_jy); Feld[jx][jy] = EL_PLAYER_1; InitMovingField(jx, jy, MV_DOWN); Store[jx][jy] = EL_ACID; ContinueMoving(jx, jy); BuryPlayer(player); } else TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); return MP_MOVING; } #endif can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG); if (can_move != MP_MOVING) return can_move; /* check if DigField() has caused relocation of the player */ if (player->jx != jx || player->jy != jy) return MP_NO_ACTION; /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */ StorePlayer[jx][jy] = 0; player->last_jx = jx; player->last_jy = jy; player->jx = new_jx; player->jy = new_jy; StorePlayer[new_jx][new_jy] = player->element_nr; if (player->move_delay_value_next != -1) { player->move_delay_value = player->move_delay_value_next; player->move_delay_value_next = -1; } player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); player->step_counter++; PlayerVisit[jx][jy] = FrameCounter; #if USE_UFAST_PLAYER_EXIT_BUGFIX player->is_moving = TRUE; #endif #if 1 /* should better be called in MovePlayer(), but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); #endif return MP_MOVING; } boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) { int jx = player->jx, jy = player->jy; int old_jx = jx, old_jy = jy; int moved = MP_NO_ACTION; if (!player->active) return FALSE; if (!dx && !dy) { if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } return FALSE; } if (player->move_delay > 0) return FALSE; player->move_delay = -1; /* set to "uninitialized" value */ /* store if player is automatically moved to next field */ player->is_auto_moving = (player->programmed_action != MV_NONE); /* remove the last programmed player action */ player->programmed_action = 0; if (player->MovPos) { /* should only happen if pre-1.2 tape recordings are played */ /* this is only for backward compatibility */ int original_move_delay_value = player->move_delay_value; #if DEBUG printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n", tape.counter); #endif /* scroll remaining steps with finest movement resolution */ player->move_delay_value = MOVE_DELAY_NORMAL_SPEED; while (player->MovPos) { ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); AdvanceFrameAndPlayerCounters(player->index_nr); DrawAllPlayers(); BackToFront(); } player->move_delay_value = original_move_delay_value; } player->is_active = FALSE; if (player->last_move_dir & MV_HORIZONTAL) { if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy))) moved |= MovePlayerOneStep(player, dx, 0, dx, dy); } else { if (!(moved |= MovePlayerOneStep(player, dx, 0, dx, dy))) moved |= MovePlayerOneStep(player, 0, dy, dx, dy); } #if USE_FIXED_BORDER_RUNNING_GFX if (!moved && !player->is_active) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } #endif jx = player->jx; jy = player->jy; #if 1 if (moved & MP_MOVING && !ScreenMovPos && (player->index_nr == game.centered_player_nr || game.centered_player_nr == -1)) #else if (moved & MP_MOVING && !ScreenMovPos && (player == local_player || !options.network)) #endif { int old_scroll_x = scroll_x, old_scroll_y = scroll_y; int offset = game.scroll_delay_value; if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) { /* actual player has left the screen -- scroll in that direction */ if (jx != old_jx) /* player has moved horizontally */ scroll_x += (jx - old_jx); else /* player has moved vertically */ scroll_y += (jy - old_jy); } else { if (jx != old_jx) /* player has moved horizontally */ { if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) || (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset)) scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset); /* don't scroll over playfield boundaries */ if (scroll_x < SBX_Left || scroll_x > SBX_Right) scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); /* don't scroll more than one field at a time */ scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x); /* don't scroll against the player's moving direction */ if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) || (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x)) scroll_x = old_scroll_x; } else /* player has moved vertically */ { if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) || (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset)) scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset); /* don't scroll over playfield boundaries */ if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); /* don't scroll more than one field at a time */ scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y); /* don't scroll against the player's moving direction */ if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) || (player->MovDir == MV_DOWN && scroll_y < old_scroll_y)) scroll_y = old_scroll_y; } } if (scroll_x != old_scroll_x || scroll_y != old_scroll_y) { #if 1 if (!options.network && game.centered_player_nr == -1 && !AllPlayersInVisibleScreen()) { scroll_x = old_scroll_x; scroll_y = old_scroll_y; } else #else if (!options.network && !AllPlayersInVisibleScreen()) { scroll_x = old_scroll_x; scroll_y = old_scroll_y; } else #endif { ScrollScreen(player, SCROLL_INIT); ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y); } } } player->StepFrame = 0; if (moved & MP_MOVING) { if (old_jx != jx && old_jy == jy) player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT); else if (old_jx == jx && old_jy != jy) player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP); TEST_DrawLevelField(jx, jy); /* for "crumbled sand" */ player->last_move_dir = player->MovDir; player->is_moving = TRUE; player->is_snapping = FALSE; player->is_switching = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; #if 0 /* should better be called here than above, but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); #endif } else { CheckGravityMovementWhenNotMoving(player); player->is_moving = FALSE; /* at this point, the player is allowed to move, but cannot move right now (e.g. because of something blocking the way) -- ensure that the player is also allowed to move in the next frame (in old versions before 3.1.1, the player was forced to wait again for eight frames before next try) */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) player->move_delay = 0; /* allow direct movement in the next frame */ } if (player->move_delay == -1) /* not yet initialized by DigField() */ player->move_delay = player->move_delay_value; if (game.engine_version < VERSION_IDENT(3,0,7,0)) { TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); } if (!player->active) RemovePlayer(player); return moved; } void ScrollPlayer(struct PlayerInfo *player, int mode) { int jx = player->jx, jy = player->jy; int last_jx = player->last_jx, last_jy = player->last_jy; int move_stepsize = TILEX / player->move_delay_value; #if USE_NEW_PLAYER_SPEED if (!player->active) return; if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ return; #else if (!player->active || player->MovPos == 0) return; #endif if (mode == SCROLL_INIT) { player->actual_frame_counter = FrameCounter; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); if ((player->block_last_field || player->block_delay_adjustment > 0) && Feld[last_jx][last_jy] == EL_EMPTY) { int last_field_block_delay = 0; /* start with no blocking at all */ int block_delay_adjustment = player->block_delay_adjustment; /* if player blocks last field, add delay for exactly one move */ if (player->block_last_field) { last_field_block_delay += player->move_delay_value; /* when blocking enabled, prevent moving up despite gravity */ #if USE_PLAYER_GRAVITY if (player->gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; #else if (game.gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; #endif } /* add block delay adjustment (also possible when not blocking) */ last_field_block_delay += block_delay_adjustment; Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } #if USE_NEW_PLAYER_SPEED if (player->MovPos != 0) /* player has not yet reached destination */ return; #else return; #endif } else if (!FrameReached(&player->actual_frame_counter, 1)) return; #if USE_NEW_PLAYER_SPEED if (player->MovPos != 0) { player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); /* before DrawPlayer() to draw correct player graphic for this case */ if (player->MovPos == 0) CheckGravityMovement(player); } #else player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); /* before DrawPlayer() to draw correct player graphic for this case */ if (player->MovPos == 0) CheckGravityMovement(player); #endif if (player->MovPos == 0) /* player reached destination field */ { if (player->move_delay_reset_counter > 0) { player->move_delay_reset_counter--; if (player->move_delay_reset_counter == 0) { /* continue with normal speed after quickly moving through gate */ HALVE_PLAYER_SPEED(player); /* be able to make the next move without delay */ player->move_delay = 0; } } player->last_jx = jx; player->last_jy = jy; if (Feld[jx][jy] == EL_EXIT_OPEN || Feld[jx][jy] == EL_EM_EXIT_OPEN || #if 1 Feld[jx][jy] == EL_EM_EXIT_OPENING || #endif Feld[jx][jy] == EL_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN || #if 1 Feld[jx][jy] == EL_EM_STEEL_EXIT_OPENING || #endif Feld[jx][jy] == EL_SP_EXIT_OPEN || Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ { DrawPlayer(player); /* needed here only to cleanup last field */ RemovePlayer(player); if (local_player->friends_still_needed == 0 || IS_SP_ELEMENT(Feld[jx][jy])) PlayerWins(player); } /* this breaks one level: "machine", level 000 */ { int move_direction = player->MovDir; int enter_side = MV_DIR_OPPOSITE(move_direction); int leave_side = move_direction; int old_jx = last_jx; int old_jy = last_jy; int old_element = Feld[old_jx][old_jy]; int new_element = Feld[jx][jy]; if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); if (IS_CUSTOM_ELEMENT(new_element)) CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, new_element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); #if USE_FIX_CE_ACTION_WITH_PLAYER CheckTriggeredElementChangeBySide(jx, jy, player->initial_element, CE_MOVE_OF_X, move_direction); #else CheckTriggeredElementChangeBySide(jx, jy, player->element_nr, CE_MOVE_OF_X, move_direction); #endif } if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); /* needed because pushed element has not yet reached its destination, so it would trigger a change event at its previous field location */ if (!player->is_pushing) TestIfElementTouchesCustomElement(jx, jy); /* for empty space */ if (!player->active) RemovePlayer(player); } if (!local_player->LevelSolved && level.use_step_counter) { int i; TimePlayed++; if (TimeLeft > 0) { TimeLeft--; if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } #if 1 else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } #else else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); #endif } if (tape.single_step && tape.recording && !tape.pausing && !player->programmed_action) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); } } void ScrollScreen(struct PlayerInfo *player, int mode) { static unsigned long screen_frame_counter = 0; if (mode == SCROLL_INIT) { /* set scrolling step size according to actual player's moving speed */ ScrollStepSize = TILEX / player->move_delay_value; screen_frame_counter = FrameCounter; ScreenMovDir = player->MovDir; ScreenMovPos = player->MovPos; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); return; } else if (!FrameReached(&screen_frame_counter, 1)) return; if (ScreenMovPos) { ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); redraw_mask |= REDRAW_FIELD; } else ScreenMovDir = MV_NONE; } void TestIfPlayerTouchesCustomElement(int x, int y) { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int trigger_sides[4][2] = { /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; int center_element = Feld[x][y]; /* should always be non-moving! */ int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int center_side = trigger_sides[i][0]; int border_side = trigger_sides[i][1]; int border_element; if (!IN_LEV_FIELD(xx, yy)) continue; if (IS_PLAYER(x, y)) /* player found at center element */ { struct PlayerInfo *player = PLAYERINFO(x, y); if (game.engine_version < VERSION_IDENT(3,0,7,0)) border_element = Feld[xx][yy]; /* may be moving! */ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ border_element = MovingOrBlocked2Element(xx, yy); else continue; /* center and border element do not touch */ CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); CheckTriggeredElementChangeByPlayer(xx, yy, border_element, CE_PLAYER_TOUCHES_X, player->index_bit, border_side); #if USE_FIX_CE_ACTION_WITH_PLAYER { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(x, y)->initial_element; CheckElementChangeBySide(xx, yy, border_element, player_element, CE_TOUCHING_X, border_side); } #endif } else if (IS_PLAYER(xx, yy)) /* player found at border element */ { struct PlayerInfo *player = PLAYERINFO(xx, yy); if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) continue; /* center and border element do not touch */ } CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, player->index_bit, center_side); CheckTriggeredElementChangeByPlayer(x, y, center_element, CE_PLAYER_TOUCHES_X, player->index_bit, center_side); #if USE_FIX_CE_ACTION_WITH_PLAYER { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(xx, yy)->initial_element; CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, center_side); } #endif break; } } } #if USE_ELEMENT_TOUCHING_BUGFIX void TestIfElementTouchesCustomElement(int x, int y) { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int trigger_sides[4][2] = { /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; boolean change_center_element = FALSE; int center_element = Feld[x][y]; /* should always be non-moving! */ int border_element_old[NUM_DIRECTIONS]; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int border_element; border_element_old[i] = -1; if (!IN_LEV_FIELD(xx, yy)) continue; if (game.engine_version < VERSION_IDENT(3,0,7,0)) border_element = Feld[xx][yy]; /* may be moving! */ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ border_element = MovingOrBlocked2Element(xx, yy); else continue; /* center and border element do not touch */ border_element_old[i] = border_element; } for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int center_side = trigger_sides[i][0]; int border_element = border_element_old[i]; if (border_element == -1) continue; /* check for change of border element */ CheckElementChangeBySide(xx, yy, border_element, center_element, CE_TOUCHING_X, center_side); /* (center element cannot be player, so we dont have to check this here) */ } for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int border_side = trigger_sides[i][1]; int border_element = border_element_old[i]; if (border_element == -1) continue; /* check for change of center element (but change it only once) */ if (!change_center_element) change_center_element = CheckElementChangeBySide(x, y, center_element, border_element, CE_TOUCHING_X, border_side); #if USE_FIX_CE_ACTION_WITH_PLAYER if (IS_PLAYER(xx, yy)) { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(xx, yy)->initial_element; CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, border_side); } #endif } } #else void TestIfElementTouchesCustomElement_OLD(int x, int y) { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int trigger_sides[4][2] = { /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; boolean change_center_element = FALSE; int center_element = Feld[x][y]; /* should always be non-moving! */ int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int center_side = trigger_sides[i][0]; int border_side = trigger_sides[i][1]; int border_element; if (!IN_LEV_FIELD(xx, yy)) continue; if (game.engine_version < VERSION_IDENT(3,0,7,0)) border_element = Feld[xx][yy]; /* may be moving! */ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ border_element = MovingOrBlocked2Element(xx, yy); else continue; /* center and border element do not touch */ /* check for change of center element (but change it only once) */ if (!change_center_element) change_center_element = CheckElementChangeBySide(x, y, center_element, border_element, CE_TOUCHING_X, border_side); /* check for change of border element */ CheckElementChangeBySide(xx, yy, border_element, center_element, CE_TOUCHING_X, center_side); } } #endif void TestIfElementHitsCustomElement(int x, int y, int direction) { int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int hitx = x + dx, hity = y + dy; int hitting_element = Feld[x][y]; int touched_element; if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) return; touched_element = (IN_LEV_FIELD(hitx, hity) ? MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL); if (IN_LEV_FIELD(hitx, hity)) { int opposite_direction = MV_DIR_OPPOSITE(direction); int hitting_side = direction; int touched_side = opposite_direction; boolean object_hit = (!IS_MOVING(hitx, hity) || MovDir[hitx][hity] != direction || ABS(MovPos[hitx][hity]) <= TILEY / 2); object_hit = TRUE; if (object_hit) { CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_X, touched_side); CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_X, hitting_side); CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_SOMETHING, opposite_direction); #if USE_FIX_CE_ACTION_WITH_PLAYER if (IS_PLAYER(hitx, hity)) { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(hitx, hity)->initial_element; CheckElementChangeBySide(x, y, hitting_element, player_element, CE_HITTING_X, touched_side); } #endif } } /* "hitting something" is also true when hitting the playfield border */ CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_SOMETHING, direction); } #if 0 void TestIfElementSmashesCustomElement(int x, int y, int direction) { int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int hitx = x + dx, hity = y + dy; int hitting_element = Feld[x][y]; int touched_element; #if 0 boolean object_hit = (IN_LEV_FIELD(hitx, hity) && !IS_FREE(hitx, hity) && (!IS_MOVING(hitx, hity) || MovDir[hitx][hity] != direction || ABS(MovPos[hitx][hity]) <= TILEY / 2)); #endif if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) return; #if 0 if (IN_LEV_FIELD(hitx, hity) && !object_hit) return; #endif touched_element = (IN_LEV_FIELD(hitx, hity) ? MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL); CheckElementChangeBySide(x, y, hitting_element, touched_element, EP_CAN_SMASH_EVERYTHING, direction); if (IN_LEV_FIELD(hitx, hity)) { int opposite_direction = MV_DIR_OPPOSITE(direction); int hitting_side = direction; int touched_side = opposite_direction; #if 0 int touched_element = MovingOrBlocked2Element(hitx, hity); #endif #if 1 boolean object_hit = (!IS_MOVING(hitx, hity) || MovDir[hitx][hity] != direction || ABS(MovPos[hitx][hity]) <= TILEY / 2); object_hit = TRUE; #endif if (object_hit) { int i; CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_SMASHED_BY_SOMETHING, opposite_direction); CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_OTHER_IS_SMASHING, touched_side); CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_OTHER_GETS_SMASHED, hitting_side); } } } #endif void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { int i, kill_x = -1, kill_y = -1; int bad_element = -1; static int test_xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int test_dir[4] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN }; for (i = 0; i < NUM_DIRECTIONS; i++) { int test_x, test_y, test_move_dir, test_element; test_x = good_x + test_xy[i][0]; test_y = good_y + test_xy[i][1]; if (!IN_LEV_FIELD(test_x, test_y)) continue; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y); /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing; 2nd case: DONT_TOUCH style bad thing does not move away from good thing */ if ((DONT_RUN_INTO(test_element) && good_move_dir == test_dir[i]) || (DONT_TOUCH(test_element) && test_move_dir != test_dir[i])) { kill_x = test_x; kill_y = test_y; bad_element = test_element; break; } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(good_x, good_y)) { struct PlayerInfo *player = PLAYERINFO(good_x, good_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(kill_x, kill_y); else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y)) KillPlayer(player); } else Bang(good_x, good_y); } } void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) { int i, kill_x = -1, kill_y = -1; int bad_element = Feld[bad_x][bad_y]; static int test_xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; static int test_dir[4] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN }; if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */ return; for (i = 0; i < NUM_DIRECTIONS; i++) { int test_x, test_y, test_move_dir, test_element; test_x = bad_x + test_xy[i][0]; test_y = bad_y + test_xy[i][1]; if (!IN_LEV_FIELD(test_x, test_y)) continue; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = Feld[test_x][test_y]; /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing; 2nd case: DONT_TOUCH style bad thing does not move away from good thing */ if ((DONT_RUN_INTO(bad_element) && bad_move_dir == test_dir[i]) || (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i])) { /* good thing is player or penguin that does not move away */ if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); if (bad_element == EL_ROBOT && player->is_moving) continue; /* robot does not kill player if he is moving */ if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) continue; /* center and border element do not touch */ } kill_x = test_x; kill_y = test_y; break; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; break; } } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(kill_x, kill_y)) { struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(bad_x, bad_y); else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) KillPlayer(player); } else Bang(kill_x, kill_y); } } void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir) { int bad_element = Feld[bad_x][bad_y]; int dx = (bad_move_dir == MV_LEFT ? -1 : bad_move_dir == MV_RIGHT ? +1 : 0); int dy = (bad_move_dir == MV_UP ? -1 : bad_move_dir == MV_DOWN ? +1 : 0); int test_x = bad_x + dx, test_y = bad_y + dy; int test_move_dir, test_element; int kill_x = -1, kill_y = -1; if (!IN_LEV_FIELD(test_x, test_y)) return; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = Feld[test_x][test_y]; if (test_move_dir != bad_move_dir) { /* good thing can be player or penguin that does not move away */ if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); /* (note: in comparison to DONT_RUN_TO and DONT_TOUCH, also handle the player as being hit when he is moving towards the bad thing, because the "get hit by" condition would be lost after the player stops) */ if (player->MovPos != 0 && player->MovDir == bad_move_dir) return; /* player moves away from bad thing */ kill_x = test_x; kill_y = test_y; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(kill_x, kill_y)) { struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(bad_x, bad_y); else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) KillPlayer(player); } else Bang(kill_x, kill_y); } } void TestIfPlayerTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NONE); } void TestIfPlayerRunsIntoBadThing(int x, int y, int move_dir) { TestIfGoodThingHitsBadThing(x, y, move_dir); } void TestIfBadThingTouchesPlayer(int x, int y) { TestIfBadThingHitsGoodThing(x, y, MV_NONE); } void TestIfBadThingRunsIntoPlayer(int x, int y, int move_dir) { TestIfBadThingHitsGoodThing(x, y, move_dir); } void TestIfFriendTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NONE); } void TestIfBadThingTouchesFriend(int x, int y) { TestIfBadThingHitsGoodThing(x, y, MV_NONE); } void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y) { int i, kill_x = bad_x, kill_y = bad_y; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int x, y, element; x = bad_x + xy[i][0]; y = bad_y + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; element = Feld[x][y]; if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE || element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP) { kill_x = x; kill_y = y; break; } } if (kill_x != bad_x || kill_y != bad_y) Bang(bad_x, bad_y); } void KillPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; if (!player->active) return; #if 0 printf("::: 0: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif /* the following code was introduced to prevent an infinite loop when calling -> Bang() -> CheckTriggeredElementChangeExt() -> ExecuteCustomElementAction() -> KillPlayer() -> (infinitely repeating the above sequence of function calls) which occurs when killing the player while having a CE with the setting "kill player X when explosion of "; the solution using a new field "player->killed" was chosen for backwards compatibility, although clever use of the fields "player->active" etc. would probably also work */ #if 1 if (player->killed) return; #endif player->killed = TRUE; /* remove accessible field at the player's position */ Feld[jx][jy] = EL_EMPTY; /* deactivate shield (else Bang()/Explode() would not work right) */ player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; #if 0 printf("::: 1: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif Bang(jx, jy); #if 0 printf("::: 2: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif #if USE_PLAYER_REANIMATION #if 1 if (player->reanimated) /* killed player may have been reanimated */ player->killed = player->reanimated = FALSE; else BuryPlayer(player); #else if (player->killed) /* player may have been reanimated */ BuryPlayer(player); #endif #else BuryPlayer(player); #endif } static void KillPlayerUnlessEnemyProtected(int x, int y) { if (!PLAYER_ENEMY_PROTECTED(x, y)) KillPlayer(PLAYERINFO(x, y)); } static void KillPlayerUnlessExplosionProtected(int x, int y) { if (!PLAYER_EXPLOSION_PROTECTED(x, y)) KillPlayer(PLAYERINFO(x, y)); } void BuryPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; if (!player->active) return; PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING); PlayLevelSound(jx, jy, SND_GAME_LOSING); player->GameOver = TRUE; RemovePlayer(player); } void RemovePlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int i, found = FALSE; player->present = FALSE; player->active = FALSE; if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; if (player->is_moving) TEST_DrawLevelField(player->last_jx, player->last_jy); for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) found = TRUE; if (!found) AllPlayersGone = TRUE; ExitX = ZX = jx; ExitY = ZY = jy; } #if USE_NEW_SNAP_DELAY static void setFieldForSnapping(int x, int y, int element, int direction) { struct ElementInfo *ei = &element_info[element]; int direction_bit = MV_DIR_TO_BIT(direction); int graphic_snapping = ei->direction_graphic[ACTION_SNAPPING][direction_bit]; int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING : IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING); Feld[x][y] = EL_ELEMENT_SNAPPING; MovDelay[x][y] = MOVE_DELAY_NORMAL_SPEED + 1 - 1; ResetGfxAnimation(x, y); GfxElement[x][y] = element; GfxAction[x][y] = action; GfxDir[x][y] = direction; GfxFrame[x][y] = -1; } #endif /* ============================================================================= checkDiagonalPushing() ----------------------------------------------------------------------------- check if diagonal input device direction results in pushing of object (by checking if the alternative direction is walkable, diggable, ...) ============================================================================= */ static boolean checkDiagonalPushing(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy) { int jx, jy, dx, dy, xx, yy; if (real_dx == 0 || real_dy == 0) /* no diagonal direction => push */ return TRUE; /* diagonal direction: check alternative direction */ jx = player->jx; jy = player->jy; dx = x - jx; dy = y - jy; xx = jx + (dx == 0 ? real_dx : 0); yy = jy + (dy == 0 ? real_dy : 0); return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy])); } /* ============================================================================= DigField() ----------------------------------------------------------------------------- x, y: field next to player (non-diagonal) to try to dig to real_dx, real_dy: direction as read from input device (can be diagonal) ============================================================================= */ static int DigField(struct PlayerInfo *player, int oldx, int oldy, int x, int y, int real_dx, int real_dy, int mode) { boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG); boolean player_was_pushing = player->is_pushing; boolean player_can_move = (!player->cannot_move && mode != DF_SNAP); boolean player_can_move_or_snap = (!player->cannot_move || mode == DF_SNAP); int jx = oldx, jy = oldy; int dx = x - jx, dy = y - jy; int nextx = x + dx, nexty = y + dy; int move_direction = (dx == -1 ? MV_LEFT : dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NONE); int opposite_direction = MV_DIR_OPPOSITE(move_direction); int dig_side = MV_DIR_OPPOSITE(move_direction); int old_element = Feld[jx][jy]; #if USE_FIXED_DONT_RUN_INTO int element = MovingOrBlocked2ElementIfNotLeaving(x, y); #else int element; #endif int collect_count; if (is_player) /* function can also be called by EL_PENGUIN */ { if (player->MovPos == 0) { player->is_digging = FALSE; player->is_collecting = FALSE; } if (player->MovPos == 0) /* last pushing move finished */ player->is_pushing = FALSE; if (mode == DF_NO_PUSH) /* player just stopped pushing */ { player->is_switching = FALSE; player->push_delay = -1; return MP_NO_ACTION; } } #if !USE_FIXED_DONT_RUN_INTO if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MP_NO_ACTION; #endif if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; /* in case of element dropped at player position, check background */ else if (Back[jx][jy] != EL_EMPTY && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ #if USE_FIXED_DONT_RUN_INTO if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) { SplashAcid(x, y); Feld[jx][jy] = player->artwork_element; InitMovingField(jx, jy, MV_DOWN); Store[jx][jy] = EL_ACID; ContinueMoving(jx, jy); BuryPlayer(player); return MP_DONT_RUN_INTO; } #endif #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) { TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); return MP_DONT_RUN_INTO; } #endif #if USE_FIXED_DONT_RUN_INTO if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MP_NO_ACTION; #endif #if !USE_FIXED_DONT_RUN_INTO element = Feld[x][y]; #endif collect_count = element_info[element].collect_count_initial; if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */ return MP_NO_ACTION; if (game.engine_version < VERSION_IDENT(2,2,0,0)) player_can_move = player_can_move_or_snap; if (mode == DF_SNAP && !IS_SNAPPABLE(element) && game.engine_version >= VERSION_IDENT(2,2,0,0)) { CheckElementChangeByPlayer(x, y, element, CE_SNAPPED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); if (element == EL_DC_LANDMINE) Bang(x, y); if (Feld[x][y] != element) /* field changed by snapping */ return MP_ACTION; return MP_NO_ACTION; } #if USE_PLAYER_GRAVITY if (player->gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MP_NO_ACTION; /* player cannot walk here due to gravity */ #else if (game.gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MP_NO_ACTION; /* player cannot walk here due to gravity */ #endif if (player_can_move && IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) { int sound_element = SND_ELEMENT(element); int sound_action = ACTION_WALKING; if (IS_RND_GATE(element)) { if (!player->key[RND_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_RND_GATE_GRAY(element)) { if (!player->key[RND_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_RND_GATE_GRAY_ACTIVE(element)) { if (!player->key[RND_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || #if 1 element == EL_EM_EXIT_OPENING || #endif element == EL_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN || #if 1 element == EL_EM_STEEL_EXIT_OPENING || #endif element == EL_SP_EXIT_OPEN || element == EL_SP_EXIT_OPENING) { sound_action = ACTION_PASSING; /* player is passing exit */ } else if (element == EL_EMPTY) { sound_action = ACTION_MOVING; /* nothing to walk on */ } /* play sound from background or player, whatever is available */ if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED) PlayLevelSoundElementAction(x, y, sound_element, sound_action); else PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action); } else if (player_can_move && IS_PASSABLE(element) && canPassField(x, y, move_direction)) { if (!ACCESS_FROM(element, opposite_direction)) return MP_NO_ACTION; /* field not accessible from this direction */ if (CAN_MOVE(element)) /* only fixed elements can be passed! */ return MP_NO_ACTION; if (IS_EM_GATE(element)) { if (!player->key[EM_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_EM_GATE_GRAY(element)) { if (!player->key[EM_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_EM_GATE_GRAY_ACTIVE(element)) { if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE(element)) { if (!player->key[EMC_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE_GRAY(element)) { if (!player->key[EMC_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE_GRAY_ACTIVE(element)) { if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (element == EL_DC_GATE_WHITE || element == EL_DC_GATE_WHITE_GRAY || element == EL_DC_GATE_WHITE_GRAY_ACTIVE) { if (player->num_white_keys == 0) return MP_NO_ACTION; player->num_white_keys--; } else if (IS_SP_PORT(element)) { if (element == EL_SP_GRAVITY_PORT_LEFT || element == EL_SP_GRAVITY_PORT_RIGHT || element == EL_SP_GRAVITY_PORT_UP || element == EL_SP_GRAVITY_PORT_DOWN) #if USE_PLAYER_GRAVITY player->gravity = !player->gravity; #else game.gravity = !game.gravity; #endif else if (element == EL_SP_GRAVITY_ON_PORT_LEFT || element == EL_SP_GRAVITY_ON_PORT_RIGHT || element == EL_SP_GRAVITY_ON_PORT_UP || element == EL_SP_GRAVITY_ON_PORT_DOWN) #if USE_PLAYER_GRAVITY player->gravity = TRUE; #else game.gravity = TRUE; #endif else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT || element == EL_SP_GRAVITY_OFF_PORT_RIGHT || element == EL_SP_GRAVITY_OFF_PORT_UP || element == EL_SP_GRAVITY_OFF_PORT_DOWN) #if USE_PLAYER_GRAVITY player->gravity = FALSE; #else game.gravity = FALSE; #endif } /* automatically move to the next field with double speed */ player->programmed_action = move_direction; if (player->move_delay_reset_counter == 0) { player->move_delay_reset_counter = 2; /* two double speed steps */ DOUBLE_PLAYER_SPEED(player); } PlayLevelSoundAction(x, y, ACTION_PASSING); } else if (player_can_move_or_snap && IS_DIGGABLE(element)) { RemoveField(x, y); if (mode != DF_SNAP) { GfxElement[x][y] = GFX_ELEMENT(element); player->is_digging = TRUE; } PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X, player->index_bit, dig_side); if (mode == DF_SNAP) { #if USE_NEW_SNAP_DELAY if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ #else TestIfElementTouchesCustomElement(x, y); /* for empty space */ #endif CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); } } else if (player_can_move_or_snap && IS_COLLECTIBLE(element)) { RemoveField(x, y); if (is_player && mode != DF_SNAP) { GfxElement[x][y] = element; player->is_collecting = TRUE; } if (element == EL_SPEED_PILL) { player->move_delay_value = MOVE_DELAY_HIGH_SPEED; } else if (element == EL_EXTRA_TIME && level.time > 0) { TimeLeft += level.extra_time; #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif } else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) { player->shield_normal_time_left += level.shield_normal_time; if (element == EL_SHIELD_DEADLY) player->shield_deadly_time_left += level.shield_deadly_time; } else if (element == EL_DYNAMITE || element == EL_EM_DYNAMITE || element == EL_SP_DISK_RED) { if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; DrawGameDoorValues(); } else if (element == EL_DYNABOMB_INCREASE_NUMBER) { player->dynabomb_count++; player->dynabombs_left++; } else if (element == EL_DYNABOMB_INCREASE_SIZE) { player->dynabomb_size++; } else if (element == EL_DYNABOMB_INCREASE_POWER) { player->dynabomb_xl = TRUE; } else if (IS_KEY(element)) { player->key[KEY_NR(element)] = TRUE; DrawGameDoorValues(); } else if (element == EL_DC_KEY_WHITE) { player->num_white_keys++; /* display white keys? */ /* DrawGameDoorValues(); */ } else if (IS_ENVELOPE(element)) { player->show_envelope = element; } else if (element == EL_EMC_LENSES) { game.lenses_time_left = level.lenses_time * FRAMES_PER_SECOND; RedrawAllInvisibleElementsForLenses(); } else if (element == EL_EMC_MAGNIFIER) { game.magnify_time_left = level.magnify_time * FRAMES_PER_SECOND; RedrawAllInvisibleElementsForMagnifier(); } else if (IS_DROPPABLE(element) || IS_THROWABLE(element)) /* can be collected and dropped */ { int i; if (collect_count == 0) player->inventory_infinite_element = element; else for (i = 0; i < collect_count; i++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; DrawGameDoorValues(); } else if (collect_count > 0) { local_player->gems_still_needed -= collect_count; if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; #if 1 game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); #else DrawGameValue_Emeralds(local_player->gems_still_needed); #endif } RaiseScoreElement(element); PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); if (is_player) CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_COLLECTS_X, player->index_bit, dig_side); if (mode == DF_SNAP) { #if USE_NEW_SNAP_DELAY if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ #else TestIfElementTouchesCustomElement(x, y); /* for empty space */ #endif CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); } } else if (player_can_move_or_snap && IS_PUSHABLE(element)) { if (mode == DF_SNAP && element != EL_BD_ROCK) return MP_NO_ACTION; if (CAN_FALL(element) && dy) return MP_NO_ACTION; if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && !(element == EL_SPRING && level.use_spring_bug)) return MP_NO_ACTION; if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 && ((move_direction & MV_VERTICAL && ((element_info[element].move_pattern & MV_LEFT && IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) || (element_info[element].move_pattern & MV_RIGHT && IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) || (move_direction & MV_HORIZONTAL && ((element_info[element].move_pattern & MV_UP && IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) || (element_info[element].move_pattern & MV_DOWN && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1)))))) return MP_NO_ACTION; /* do not push elements already moving away faster than player */ if (CAN_MOVE(element) && MovDir[x][y] == move_direction && ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) return MP_NO_ACTION; if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { if (player->push_delay_value == -1 || !player_was_pushing) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } else if (game.engine_version >= VERSION_IDENT(3,0,7,1)) { if (player->push_delay_value == -1) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } else if (game.engine_version >= VERSION_IDENT(2,2,0,7)) { if (!player->is_pushing) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } player->is_pushing = TRUE; player->is_active = TRUE; if (!(IN_LEV_FIELD(nextx, nexty) && (IS_FREE(nextx, nexty) || (IS_SB_ELEMENT(element) && Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) || (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty))))) return MP_NO_ACTION; if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MP_NO_ACTION; if (player->push_delay == -1) /* new pushing; restart delay */ player->push_delay = 0; if (player->push_delay < player->push_delay_value && !(tape.playing && tape.file_version < FILE_VERSION_2_0) && element != EL_SPRING && element != EL_BALLOON) { /* make sure that there is no move delay before next try to push */ if (game.engine_version >= VERSION_IDENT(3,0,7,1)) player->move_delay = 0; return MP_NO_ACTION; } if (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty)) { if (!DigFieldByCE(nextx, nexty, element)) return MP_NO_ACTION; } if (IS_SB_ELEMENT(element)) { if (element == EL_SOKOBAN_FIELD_FULL) { Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; local_player->sokobanfields_still_needed++; } if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) { Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; local_player->sokobanfields_still_needed--; } Feld[x][y] = EL_SOKOBAN_OBJECT; if (Back[x][y] == Back[nextx][nexty]) PlayLevelSoundAction(x, y, ACTION_PUSHING); else if (Back[x][y] != 0) PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, ACTION_EMPTYING); else PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); #if 1 if (local_player->sokobanfields_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) #else if (local_player->sokobanfields_still_needed == 0 && game.emulation == EMU_SOKOBAN) #endif { PlayerWins(player); PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } } else PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); InitMovingField(x, y, move_direction); GfxAction[x][y] = ACTION_PUSHING; if (mode == DF_SNAP) ContinueMoving(x, y); else MovPos[x][y] = (dx != 0 ? dx : dy); Pushed[x][y] = TRUE; Pushed[nextx][nexty] = TRUE; if (game.engine_version < VERSION_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); else player->push_delay_value = -1; /* get new value later */ /* check for element change _after_ element has been pushed */ if (game.use_change_when_pushing_bug) { CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); } } else if (IS_SWITCHABLE(element)) { if (PLAYER_SWITCHING(player, x, y)) { CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_ACTION; } player->is_switching = TRUE; player->switch_x = x; player->switch_y = y; PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); if (element == EL_ROBOT_WHEEL) { Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; ZX = x; ZY = y; game.robot_wheel_active = TRUE; TEST_DrawLevelField(x, y); } else if (element == EL_SP_TERMINAL) { int xx, yy; SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) Bang(xx, yy); else if (Feld[xx][yy] == EL_SP_TERMINAL) Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE; } } else if (IS_BELT_SWITCH(element)) { ToggleBeltSwitch(x, y); } else if (element == EL_SWITCHGATE_SWITCH_UP || element == EL_SWITCHGATE_SWITCH_DOWN || element == EL_DC_SWITCHGATE_SWITCH_UP || element == EL_DC_SWITCHGATE_SWITCH_DOWN) { ToggleSwitchgateSwitch(x, y); } else if (element == EL_LIGHT_SWITCH || element == EL_LIGHT_SWITCH_ACTIVE) { ToggleLightSwitch(x, y); } else if (element == EL_TIMEGATE_SWITCH || element == EL_DC_TIMEGATE_SWITCH) { ActivateTimegateSwitch(x, y); } else if (element == EL_BALLOON_SWITCH_LEFT || element == EL_BALLOON_SWITCH_RIGHT || element == EL_BALLOON_SWITCH_UP || element == EL_BALLOON_SWITCH_DOWN || element == EL_BALLOON_SWITCH_NONE || element == EL_BALLOON_SWITCH_ANY) { game.wind_direction = (element == EL_BALLOON_SWITCH_LEFT ? MV_LEFT : element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT : element == EL_BALLOON_SWITCH_UP ? MV_UP : element == EL_BALLOON_SWITCH_DOWN ? MV_DOWN : element == EL_BALLOON_SWITCH_NONE ? MV_NONE : move_direction); } else if (element == EL_LAMP) { Feld[x][y] = EL_LAMP_ACTIVE; local_player->lights_still_needed--; ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } else if (element == EL_TIME_ORB_FULL) { Feld[x][y] = EL_TIME_ORB_EMPTY; if (level.time > 0 || level.use_time_orb_bug) { TimeLeft += level.time_orb_time; #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif } ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } else if (element == EL_EMC_MAGIC_BALL_SWITCH || element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) { int xx, yy; game.ball_state = !game.ball_state; SCAN_PLAYFIELD(xx, yy) { int e = Feld[xx][yy]; if (game.ball_state) { if (e == EL_EMC_MAGIC_BALL) CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE); else if (e == EL_EMC_MAGIC_BALL_SWITCH) CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE); } else { if (e == EL_EMC_MAGIC_BALL_ACTIVE) CreateField(xx, yy, EL_EMC_MAGIC_BALL); else if (e == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH); } } } CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_ACTION; } else { if (!PLAYER_SWITCHING(player, x, y)) { player->is_switching = TRUE; player->switch_x = x; player->switch_y = y; CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X, player->index_bit, dig_side); CheckElementChangeByPlayer(x, y, element, CE_SWITCHED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X, player->index_bit, dig_side); } CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_NO_ACTION; } player->push_delay = -1; if (is_player) /* function can also be called by EL_PENGUIN */ { if (Feld[x][y] != element) /* really digged/collected something */ { player->is_collecting = !player->is_digging; player->is_active = TRUE; } } return MP_MOVING; } static boolean DigFieldByCE(int x, int y, int digging_element) { int element = Feld[x][y]; if (!IS_FREE(x, y)) { int action = (IS_DIGGABLE(element) ? ACTION_DIGGING : IS_COLLECTIBLE(element) ? ACTION_COLLECTING : ACTION_BREAKING); /* no element can dig solid indestructible elements */ if (IS_INDESTRUCTIBLE(element) && !IS_DIGGABLE(element) && !IS_COLLECTIBLE(element)) return FALSE; if (AmoebaNr[x][y] && (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA || element == EL_AMOEBA_GROWING)) { AmoebaCnt[AmoebaNr[x][y]]--; AmoebaCnt2[AmoebaNr[x][y]]--; } if (IS_MOVING(x, y)) RemoveMovingField(x, y); else { RemoveField(x, y); TEST_DrawLevelField(x, y); } /* if digged element was about to explode, prevent the explosion */ ExplodeField[x][y] = EX_TYPE_NONE; PlayLevelSoundAction(x, y, action); } Store[x][y] = EL_EMPTY; #if 1 /* this makes it possible to leave the removed element again */ if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) Store[x][y] = element; #else if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) { int move_leave_element = element_info[digging_element].move_leave_element; /* this makes it possible to leave the removed element again */ Store[x][y] = (move_leave_element == EL_TRIGGER_ELEMENT ? element : move_leave_element); } #endif return TRUE; } static boolean SnapField(struct PlayerInfo *player, int dx, int dy) { int jx = player->jx, jy = player->jy; int x = jx + dx, y = jy + dy; int snap_direction = (dx == -1 ? MV_LEFT : dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NONE); boolean can_continue_snapping = (level.continuous_snapping && WasJustFalling[x][y] < CHECK_DELAY_FALLING); if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0)) return FALSE; if (!player->active || !IN_LEV_FIELD(x, y)) return FALSE; if (dx && dy) return FALSE; if (!dx && !dy) { if (player->MovPos == 0) player->is_pushing = FALSE; player->is_snapping = FALSE; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } return FALSE; } #if USE_NEW_CONTINUOUS_SNAPPING /* prevent snapping with already pressed snap key when not allowed */ if (player->is_snapping && !can_continue_snapping) return FALSE; #else if (player->is_snapping) return FALSE; #endif player->MovDir = snap_direction; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION) return FALSE; player->is_snapping = TRUE; player->is_active = TRUE; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } if (player->MovPos != 0) /* prevent graphic bugs in versions < 2.2.0 */ TEST_DrawLevelField(player->last_jx, player->last_jy); TEST_DrawLevelField(x, y); return TRUE; } static boolean DropElement(struct PlayerInfo *player) { int old_element, new_element; int dropx = player->jx, dropy = player->jy; int drop_direction = player->MovDir; int drop_side = drop_direction; #if 1 int drop_element = get_next_dropped_element(player); #else int drop_element = (player->inventory_size > 0 ? player->inventory_element[player->inventory_size - 1] : player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left > 0 ? EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); #endif player->is_dropping_pressed = TRUE; /* do not drop an element on top of another element; when holding drop key pressed without moving, dropped element must move away before the next element can be dropped (this is especially important if the next element is dynamite, which can be placed on background for historical reasons) */ if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY) return MP_ACTION; if (IS_THROWABLE(drop_element)) { dropx += GET_DX_FROM_DIR(drop_direction); dropy += GET_DY_FROM_DIR(drop_direction); if (!IN_LEV_FIELD(dropx, dropy)) return FALSE; } old_element = Feld[dropx][dropy]; /* old element at dropping position */ new_element = drop_element; /* default: no change when dropping */ /* check if player is active, not moving and ready to drop */ if (!player->active || player->MovPos || player->drop_delay > 0) return FALSE; /* check if player has anything that can be dropped */ if (new_element == EL_UNDEFINED) return FALSE; /* check if drop key was pressed long enough for EM style dynamite */ if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40) return FALSE; /* check if anything can be dropped at the current position */ if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION) return FALSE; /* collected custom elements can only be dropped on empty fields */ if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY) return FALSE; if (old_element != EL_EMPTY) Back[dropx][dropy] = old_element; /* store old element on this field */ ResetGfxAnimation(dropx, dropy); ResetRandomAnimationValue(dropx, dropy); if (player->inventory_size > 0 || player->inventory_infinite_element != EL_UNDEFINED) { if (player->inventory_size > 0) { player->inventory_size--; DrawGameDoorValues(); if (new_element == EL_DYNAMITE) new_element = EL_DYNAMITE_ACTIVE; else if (new_element == EL_EM_DYNAMITE) new_element = EL_EM_DYNAMITE_ACTIVE; else if (new_element == EL_SP_DISK_RED) new_element = EL_SP_DISK_RED_ACTIVE; } Feld[dropx][dropy] = new_element; if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy))) DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy), el2img(Feld[dropx][dropy]), 0); PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); /* needed if previous element just changed to "empty" in the last frame */ ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, CE_PLAYER_DROPS_X, player->index_bit, drop_side); TestIfElementTouchesCustomElement(dropx, dropy); } else /* player is dropping a dyna bomb */ { player->dynabombs_left--; Feld[dropx][dropy] = new_element; if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy))) DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy), el2img(Feld[dropx][dropy]), 0); PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); } if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */ InitField_WithBug1(dropx, dropy, FALSE); new_element = Feld[dropx][dropy]; /* element might have changed */ if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) { int move_direction, nextx, nexty; if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) MovDir[dropx][dropy] = drop_direction; move_direction = MovDir[dropx][dropy]; nextx = dropx + GET_DX_FROM_DIR(move_direction); nexty = dropy + GET_DY_FROM_DIR(move_direction); ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ #if USE_FIX_IMPACT_COLLISION /* do not cause impact style collision by dropping elements that can fall */ CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; #else CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; #endif } player->drop_delay = GET_NEW_DROP_DELAY(drop_element); player->is_dropping = TRUE; player->drop_pressed_delay = 0; player->is_dropping_pressed = FALSE; player->drop_x = dropx; player->drop_y = dropy; return TRUE; } /* ------------------------------------------------------------------------- */ /* game sound playing functions */ /* ------------------------------------------------------------------------- */ static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; void InitPlayLevelSound() { int num_sounds = getSoundListSize(); checked_free(loop_sound_frame); checked_free(loop_sound_volume); loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); loop_sound_volume = checked_calloc(num_sounds * sizeof(int)); } static void PlayLevelSound(int x, int y, int nr) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo_position; int max_distance = 8; int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND); if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) || (!setup.sound_loops && IS_LOOP_SOUND(nr))) return; if (!IN_LEV_FIELD(x, y) || sx < -max_distance || sx >= SCR_FIELDX + max_distance || sy < -max_distance || sy >= SCR_FIELDY + max_distance) return; volume = SOUND_MAX_VOLUME; if (!IN_SCR_FIELD(sx, sy)) { int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2; int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2; volume -= volume * (dx > dy ? dx : dy) / max_distance; } stereo_position = (SOUND_MAX_LEFT + (sx + max_distance) * SOUND_MAX_LEFT2RIGHT / (SCR_FIELDX + 2 * max_distance)); if (IS_LOOP_SOUND(nr)) { /* This assures that quieter loop sounds do not overwrite louder ones, while restarting sound volume comparison with each new game frame. */ if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter) return; loop_sound_volume[nr] = volume; loop_sound_frame[nr] = FrameCounter; } PlaySoundExt(nr, volume, stereo_position, type); } static void PlayLevelSoundNearest(int x, int y, int sound_action) { PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) : x > LEVELX(BX2) ? LEVELX(BX2) : x, y < LEVELY(BY1) ? LEVELY(BY1) : y > LEVELY(BY2) ? LEVELY(BY2) : y, sound_action); } static void PlayLevelSoundAction(int x, int y, int action) { PlayLevelSoundElementAction(x, y, Feld[x][y], action); } static void PlayLevelSoundElementAction(int x, int y, int element, int action) { int sound_effect = element_info[SND_ELEMENT(element)].sound[action]; if (sound_effect != SND_UNDEFINED) PlayLevelSound(x, y, sound_effect); } static void PlayLevelSoundElementActionIfLoop(int x, int y, int element, int action) { int sound_effect = element_info[SND_ELEMENT(element)].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) PlayLevelSound(x, y, sound_effect); } static void PlayLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) PlayLevelSound(x, y, sound_effect); } static void StopLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) StopSound(sound_effect); } static void PlayLevelMusic() { if (levelset.music[level_nr] != MUS_UNDEFINED) PlayMusic(levelset.music[level_nr]); /* from config file */ else PlayMusic(MAP_NOCONF_MUSIC(level_nr)); /* from music dir */ } void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) { int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int x = xx - 1 - offset; int y = yy - 1 - offset; switch (sample) { case SAMPLE_blank: PlayLevelSoundElementAction(x, y, element, ACTION_WALKING); break; case SAMPLE_roll: PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); break; case SAMPLE_stone: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_nut: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_crack: PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING); break; case SAMPLE_bug: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_tank: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_android_clone: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_android_move: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_spring: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_slurp: PlayLevelSoundElementAction(x, y, element, ACTION_EATING); break; case SAMPLE_eater: PlayLevelSoundElementAction(x, y, element, ACTION_WAITING); break; case SAMPLE_eater_eat: PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); break; case SAMPLE_alien: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_collect: PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); break; case SAMPLE_diamond: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_squash: /* !!! CHECK THIS !!! */ #if 1 PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING); #else PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK); #endif break; case SAMPLE_wonderfall: PlayLevelSoundElementAction(x, y, element, ACTION_FILLING); break; case SAMPLE_drip: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_push: PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); break; case SAMPLE_dirt: PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); break; case SAMPLE_acid: PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING); break; case SAMPLE_ball: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_grow: PlayLevelSoundElementAction(x, y, element, ACTION_GROWING); break; case SAMPLE_wonder: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_door: PlayLevelSoundElementAction(x, y, element, ACTION_PASSING); break; case SAMPLE_exit_open: PlayLevelSoundElementAction(x, y, element, ACTION_OPENING); break; case SAMPLE_exit_leave: PlayLevelSoundElementAction(x, y, element, ACTION_PASSING); break; case SAMPLE_dynamite: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_tick: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_press: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); break; case SAMPLE_wheel: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_boom: PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING); break; case SAMPLE_die: PlayLevelSoundElementAction(x, y, element, ACTION_DYING); break; case SAMPLE_time: PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); break; default: PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT); break; } } void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) { int element = map_element_SP_to_RND(element_sp); int action = map_action_SP_to_RND(action_sp); int offset = (setup.sp_show_border_elements ? 0 : 1); int x = xx - offset; int y = yy - offset; #if 0 printf("::: %d -> %d\n", element_sp, action_sp); #endif PlayLevelSoundElementAction(x, y, element, action); } #if 0 void ChangeTime(int value) { int *time = (level.time == 0 ? &TimePlayed : &TimeLeft); *time += value; /* EMC game engine uses value from time counter of RND game engine */ level.native_em_level->lev->time = *time; DrawGameValue_Time(*time); } void RaiseScore(int value) { /* EMC game engine and RND game engine have separate score counters */ int *score = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? &level.native_em_level->lev->score : &local_player->score); *score += value; DrawGameValue_Score(*score); } #endif void RaiseScore(int value) { local_player->score += value; #if 1 game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); #else DrawGameValue_Score(local_player->score); #endif } void RaiseScoreElement(int element) { switch (element) { case EL_EMERALD: case EL_BD_DIAMOND: case EL_EMERALD_YELLOW: case EL_EMERALD_RED: case EL_EMERALD_PURPLE: case EL_SP_INFOTRON: RaiseScore(level.score[SC_EMERALD]); break; case EL_DIAMOND: RaiseScore(level.score[SC_DIAMOND]); break; case EL_CRYSTAL: RaiseScore(level.score[SC_CRYSTAL]); break; case EL_PEARL: RaiseScore(level.score[SC_PEARL]); break; case EL_BUG: case EL_BD_BUTTERFLY: case EL_SP_ELECTRON: RaiseScore(level.score[SC_BUG]); break; case EL_SPACESHIP: case EL_BD_FIREFLY: case EL_SP_SNIKSNAK: RaiseScore(level.score[SC_SPACESHIP]); break; case EL_YAMYAM: case EL_DARK_YAMYAM: RaiseScore(level.score[SC_YAMYAM]); break; case EL_ROBOT: RaiseScore(level.score[SC_ROBOT]); break; case EL_PACMAN: RaiseScore(level.score[SC_PACMAN]); break; case EL_NUT: RaiseScore(level.score[SC_NUT]); break; case EL_DYNAMITE: case EL_EM_DYNAMITE: case EL_SP_DISK_RED: case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: case EL_DYNABOMB_INCREASE_POWER: RaiseScore(level.score[SC_DYNAMITE]); break; case EL_SHIELD_NORMAL: case EL_SHIELD_DEADLY: RaiseScore(level.score[SC_SHIELD]); break; case EL_EXTRA_TIME: RaiseScore(level.extra_time_score); break; case EL_KEY_1: case EL_KEY_2: case EL_KEY_3: case EL_KEY_4: case EL_EM_KEY_1: case EL_EM_KEY_2: case EL_EM_KEY_3: case EL_EM_KEY_4: case EL_EMC_KEY_5: case EL_EMC_KEY_6: case EL_EMC_KEY_7: case EL_EMC_KEY_8: case EL_DC_KEY_WHITE: RaiseScore(level.score[SC_KEY]); break; default: RaiseScore(element_info[element].collect_score); break; } } void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) { if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED)) { #if defined(NETWORK_AVALIABLE) if (options.network) SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); else #endif { if (quick_quit) { #if 1 #if 1 FadeSkipNextFadeIn(); #else fading = fading_none; #endif #else OpenDoor(DOOR_CLOSE_1); #endif game_status = GAME_MODE_MAIN; #if 1 DrawAndFadeInMainMenu(REDRAW_FIELD); #else DrawMainMenu(); #endif } else { #if 0 FadeOut(REDRAW_FIELD); #endif game_status = GAME_MODE_MAIN; DrawAndFadeInMainMenu(REDRAW_FIELD); } } } else /* continue playing the game */ { if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); } } void RequestQuitGame(boolean ask_if_really_quit) { boolean quick_quit = (!ask_if_really_quit || level_editor_test_game); boolean skip_request = AllPlayersGone || quick_quit; RequestQuitGameExt(skip_request, quick_quit, "Do you really want to quit the game ?"); } /* ------------------------------------------------------------------------- */ /* random generator functions */ /* ------------------------------------------------------------------------- */ unsigned int InitEngineRandom_RND(long seed) { game.num_random_calls = 0; #if 0 unsigned int rnd_seed = InitEngineRandom(seed); printf("::: START RND: %d\n", rnd_seed); return rnd_seed; #else return InitEngineRandom(seed); #endif } unsigned int RND(int max) { if (max > 0) { game.num_random_calls++; return GetEngineRandom(max); } return 0; } /* ------------------------------------------------------------------------- */ /* game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ struct EngineSnapshotInfo { /* runtime values for custom element collect score */ int collect_score[NUM_CUSTOM_ELEMENTS]; /* runtime values for group element choice position */ int choice_pos[NUM_GROUP_ELEMENTS]; /* runtime values for belt position animations */ int belt_graphic[4][NUM_BELT_PARTS]; int belt_anim_mode[4][NUM_BELT_PARTS]; }; static struct EngineSnapshotInfo engine_snapshot_rnd; static char *snapshot_level_identifier = NULL; static int snapshot_level_nr = -1; static void SaveEngineSnapshotValues_RND() { static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; int i, j; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; engine_snapshot_rnd.collect_score[i] = element_info[element].collect_score; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; engine_snapshot_rnd.choice_pos[i] = element_info[element].group->choice_pos; } for (i = 0; i < 4; i++) { for (j = 0; j < NUM_BELT_PARTS; j++) { int element = belt_base_active_element[i] + j; int graphic = el2img(element); int anim_mode = graphic_info[graphic].anim_mode; engine_snapshot_rnd.belt_graphic[i][j] = graphic; engine_snapshot_rnd.belt_anim_mode[i][j] = anim_mode; } } } static void LoadEngineSnapshotValues_RND() { unsigned long num_random_calls = game.num_random_calls; int i, j; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; element_info[element].collect_score = engine_snapshot_rnd.collect_score[i]; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; element_info[element].group->choice_pos = engine_snapshot_rnd.choice_pos[i]; } for (i = 0; i < 4; i++) { for (j = 0; j < NUM_BELT_PARTS; j++) { int graphic = engine_snapshot_rnd.belt_graphic[i][j]; int anim_mode = engine_snapshot_rnd.belt_anim_mode[i][j]; graphic_info[graphic].anim_mode = anim_mode; } } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { InitRND(tape.random_seed); for (i = 0; i < num_random_calls; i++) RND(1); } if (game.num_random_calls != num_random_calls) { Error(ERR_INFO, "number of random calls out of sync"); Error(ERR_INFO, "number of random calls should be %d", num_random_calls); Error(ERR_INFO, "number of random calls is %d", game.num_random_calls); Error(ERR_EXIT, "this should not happen -- please debug"); } } void SaveEngineSnapshot() { /* do not save snapshots from editor */ if (level_editor_test_game) return; /* free previous snapshot buffers, if needed */ FreeEngineSnapshotBuffers(); /* copy some special values to a structure better suited for the snapshot */ SaveEngineSnapshotValues_RND(); SaveEngineSnapshotValues_EM(); SaveEngineSnapshotValues_SP(); /* save values stored in special snapshot structure */ SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); /* save further RND engine values */ SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(stored_player)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(game)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(tape)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TapeTime)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Feld)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDir)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDelay)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangePage)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CustomValue)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store2)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Back)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElement)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxAction)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxDir)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_x)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_y)); /* save level identification information */ setString(&snapshot_level_identifier, leveldir_current->identifier); snapshot_level_nr = level_nr; #if 0 ListNode *node = engine_snapshot_list_rnd; int num_bytes = 0; while (node != NULL) { num_bytes += ((struct EngineSnapshotNodeInfo *)node->content)->size; node = node->next; } printf("::: size of engine snapshot: %d bytes\n", num_bytes); #endif } void LoadEngineSnapshot() { /* restore generically stored snapshot buffers */ LoadEngineSnapshotBuffers(); /* restore special values from snapshot structure */ LoadEngineSnapshotValues_RND(); LoadEngineSnapshotValues_EM(); LoadEngineSnapshotValues_SP(); } boolean CheckEngineSnapshot() { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } /* ---------- new game button stuff ---------------------------------------- */ /* graphic position values for game buttons */ #define GAME_BUTTON_XSIZE 30 #define GAME_BUTTON_YSIZE 30 #define GAME_BUTTON_XPOS 5 #define GAME_BUTTON_YPOS 215 #define SOUND_BUTTON_XPOS 5 #define SOUND_BUTTON_YPOS (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE) #define GAME_BUTTON_STOP_XPOS (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) #define GAME_BUTTON_PAUSE_XPOS (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) #define GAME_BUTTON_PLAY_XPOS (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) static struct { int *x, *y; int gd_x, gd_y; int gadget_id; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = { #if 1 { &game.button.stop.x, &game.button.stop.y, GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_STOP, "stop game" }, { &game.button.pause.x, &game.button.pause.y, GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_PAUSE, "pause game" }, { &game.button.play.x, &game.button.play.y, GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_PLAY, "play game" }, { &game.button.sound_music.x, &game.button.sound_music.y, SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_MUSIC, "background music on/off" }, { &game.button.sound_loops.x, &game.button.sound_loops.y, SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_LOOPS, "sound loops on/off" }, { &game.button.sound_simple.x,&game.button.sound_simple.y, SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } #else { GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_STOP, "stop game" }, { GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_PAUSE, "pause game" }, { GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_PLAY, "play game" }, { SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_MUSIC, "background music on/off" }, { SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_LOOPS, "sound loops on/off" }, { SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS, SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } #endif }; void CreateGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; int button_type; boolean checked; unsigned long event_mask; int x, y; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y1, gd_y2; int id = i; x = DX + *gamebutton_info[i].x; y = DY + *gamebutton_info[i].y; gd_xoffset = gamebutton_info[i].gd_x; gd_yoffset = gamebutton_info[i].gd_y; gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset; if (id == GAME_CTRL_ID_STOP || id == GAME_CTRL_ID_PAUSE || id == GAME_CTRL_ID_PLAY) { button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; event_mask = GD_EVENT_RELEASED; gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; } else { button_type = GD_TYPE_CHECK_BUTTON; checked = ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) || (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) || (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE); event_mask = GD_EVENT_PRESSED; gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset; gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, gamebutton_info[i].infotext, #if 1 GDI_X, x, GDI_Y, y, #else GDI_X, DX + gd_xoffset, GDI_Y, DY + gd_yoffset, #endif GDI_WIDTH, GAME_BUTTON_XSIZE, GDI_HEIGHT, GAME_BUTTON_YSIZE, GDI_TYPE, button_type, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1, GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2, GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleGameButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); game_gadget[id] = gi; } } void FreeGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) FreeGadget(game_gadget[i]); } static void MapGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) MapGadget(game_gadget[i]); } void UnmapGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) UnmapGadget(game_gadget[i]); } void RedrawGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) RedrawGadget(game_gadget[i]); } static void HandleGameButtonsExt(int id) { if (game_status != GAME_MODE_PLAYING) return; switch (id) { case GAME_CTRL_ID_STOP: if (tape.playing) TapeStop(); else RequestQuitGame(TRUE); break; case GAME_CTRL_ID_PAUSE: if (options.network) { #if defined(NETWORK_AVALIABLE) if (tape.pausing) SendToServer_ContinuePlaying(); else SendToServer_PausePlaying(); #endif } else TapeTogglePause(TAPE_TOGGLE_MANUAL); break; case GAME_CTRL_ID_PLAY: if (tape.pausing) { #if defined(NETWORK_AVALIABLE) if (options.network) SendToServer_ContinuePlaying(); else #endif { tape.pausing = FALSE; DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0); } } break; case SOUND_CTRL_ID_MUSIC: if (setup.sound_music) { setup.sound_music = FALSE; FadeMusic(); } else if (audio.music_available) { setup.sound = setup.sound_music = TRUE; SetAudioMode(setup.sound); PlayLevelMusic(); } break; case SOUND_CTRL_ID_LOOPS: if (setup.sound_loops) setup.sound_loops = FALSE; else if (audio.loops_available) { setup.sound = setup.sound_loops = TRUE; SetAudioMode(setup.sound); } break; case SOUND_CTRL_ID_SIMPLE: if (setup.sound_simple) setup.sound_simple = FALSE; else if (audio.sound_available) { setup.sound = setup.sound_simple = TRUE; SetAudioMode(setup.sound); } break; default: break; } } static void HandleGameButtons(struct GadgetInfo *gi) { HandleGameButtonsExt(gi->custom_id); } void HandleSoundButtonKeys(Key key) { #if 1 if (key == setup.shortcut.sound_simple) ClickOnGadget(game_gadget[SOUND_CTRL_ID_SIMPLE], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_loops) ClickOnGadget(game_gadget[SOUND_CTRL_ID_LOOPS], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_music) ClickOnGadget(game_gadget[SOUND_CTRL_ID_MUSIC], MB_LEFTBUTTON); #else if (key == setup.shortcut.sound_simple) HandleGameButtonsExt(SOUND_CTRL_ID_SIMPLE); else if (key == setup.shortcut.sound_loops) HandleGameButtonsExt(SOUND_CTRL_ID_LOOPS); else if (key == setup.shortcut.sound_music) HandleGameButtonsExt(SOUND_CTRL_ID_MUSIC); #endif } rocksndiamonds-3.3.0.1+dfsg1/src/tools.c0000644000175000017500000065477011375525356016760 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tools.c * ***********************************************************/ #include "libgame/libgame.h" #include "tools.h" #include "init.h" #include "game.h" #include "events.h" #include "cartoons.h" #include "network.h" #include "tape.h" #include "screens.h" /* select level set with EMC X11 graphics before activating EM GFX debugging */ #define DEBUG_EM_GFX 0 /* tool button identifiers */ #define TOOL_CTRL_ID_YES 0 #define TOOL_CTRL_ID_NO 1 #define TOOL_CTRL_ID_CONFIRM 2 #define TOOL_CTRL_ID_PLAYER_1 3 #define TOOL_CTRL_ID_PLAYER_2 4 #define TOOL_CTRL_ID_PLAYER_3 5 #define TOOL_CTRL_ID_PLAYER_4 6 #define NUM_TOOL_BUTTONS 7 /* forward declaration for internal use */ static void UnmapToolButtons(); static void HandleToolButtons(struct GadgetInfo *); static int el_act_dir2crm(int, int, int); static int el_act2crm(int, int); static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS]; static int request_gadget_id = -1; static char *print_if_not_empty(int element) { static char *s = NULL; char *token_name = element_info[element].token_name; if (s != NULL) free(s); s = checked_malloc(strlen(token_name) + 10 + 1); if (element != EL_EMPTY) sprintf(s, "%d\t['%s']", element, token_name); else sprintf(s, "%d", element); return s; } void DumpTile(int x, int y) { int sx = SCREENX(x); int sy = SCREENY(y); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { x--; y--; } printf_line("-", 79); printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y); printf_line("-", 79); if (!IN_LEV_FIELD(x, y)) { printf("(not in level field)\n"); printf("\n"); return; } printf(" Feld: %d\t['%s']\n", Feld[x][y], element_info[Feld[x][y]].token_name); printf(" Back: %s\n", print_if_not_empty(Back[x][y])); printf(" Store: %s\n", print_if_not_empty(Store[x][y])); printf(" Store2: %s\n", print_if_not_empty(Store2[x][y])); printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y])); printf(" MovPos: %d\n", MovPos[x][y]); printf(" MovDir: %d\n", MovDir[x][y]); printf(" MovDelay: %d\n", MovDelay[x][y]); printf(" ChangeDelay: %d\n", ChangeDelay[x][y]); printf(" CustomValue: %d\n", CustomValue[x][y]); printf(" GfxElement: %d\n", GfxElement[x][y]); printf(" GfxAction: %d\n", GfxAction[x][y]); printf(" GfxFrame: %d\n", GfxFrame[x][y]); printf("\n"); } void SetDrawtoField(int mode) { if (mode == DRAW_BUFFERED && setup.soft_scrolling) { FX = TILEX; FY = TILEY; BX1 = -1; BY1 = -1; BX2 = SCR_FIELDX; BY2 = SCR_FIELDY; redraw_x1 = 1; redraw_y1 = 1; drawto_field = fieldbuffer; } else /* 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 RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height) { if (game_status == GAME_MODE_PLAYING && level.game_engine_type == GAME_ENGINE_TYPE_EM) { /* currently there is no partial redraw -- always redraw whole playfield */ RedrawPlayfield_EM(TRUE); /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_EM(backbuffer); } else if (game_status == GAME_MODE_PLAYING && level.game_engine_type == GAME_ENGINE_TYPE_SP) { /* currently there is no partial redraw -- always redraw whole playfield */ RedrawPlayfield_SP(TRUE); /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_SP(backbuffer); } else if (game_status == GAME_MODE_PLAYING && !game.envelope_active) { if (force_redraw) { x = gfx.sx - TILEX; y = gfx.sy - TILEY; width = gfx.sxsize + 2 * TILEX; height = gfx.sysize + 2 * TILEY; } if (force_redraw) { int xx, yy; int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY; int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY; for (xx = BX1; xx <= BX2; xx++) for (yy = BY1; yy <= BY2; yy++) if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2) DrawScreenField(xx, yy); DrawAllPlayers(); } if (setup.soft_scrolling) { int fx = FX, fy = FY; fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0); fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0); BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY); } } if (force_redraw) { x = gfx.sx; y = gfx.sy; width = gfx.sxsize; height = gfx.sysize; } BlitBitmap(drawto, window, x, y, width, height, x, y); } void DrawMaskedBorder_Rect(int x, int y, int width, int height) { Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap; SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0); BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y); } void DrawMaskedBorder_FIELD() { if (global.border_status >= GAME_MODE_TITLE && global.border_status <= GAME_MODE_PLAYING && border.draw_masked[global.border_status]) DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); } void DrawMaskedBorder_DOOR_1() { if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && (global.border_status != GAME_MODE_EDITOR || border.draw_masked[GFX_SPECIAL_ARG_EDITOR])) DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE); } void DrawMaskedBorder_DOOR_2() { if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && global.border_status != GAME_MODE_EDITOR) DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE); } void DrawMaskedBorder_DOOR_3() { /* currently not available */ } void DrawMaskedBorder_ALL() { DrawMaskedBorder_FIELD(); DrawMaskedBorder_DOOR_1(); DrawMaskedBorder_DOOR_2(); DrawMaskedBorder_DOOR_3(); } void DrawMaskedBorder(int redraw_mask) { /* never draw masked screen borders on borderless screens */ if (effectiveGameStatus() == GAME_MODE_LOADING || effectiveGameStatus() == GAME_MODE_TITLE) return; if (redraw_mask & REDRAW_ALL) DrawMaskedBorder_ALL(); else { if (redraw_mask & REDRAW_FIELD) DrawMaskedBorder_FIELD(); if (redraw_mask & REDRAW_DOOR_1) DrawMaskedBorder_DOOR_1(); if (redraw_mask & REDRAW_DOOR_2) DrawMaskedBorder_DOOR_2(); if (redraw_mask & REDRAW_DOOR_3) DrawMaskedBorder_DOOR_3(); } } void BackToFront() { int x, y; DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field); #if 0 printf("::: TILES TO REFRESH: %d\n", redraw_tiles); for (x = 0; x < SCR_FIELDX; x++) for (y = 0 ; y < SCR_FIELDY; y++) if (redraw[redraw_x1 + x][redraw_y1 + y]) printf("::: - %d, %d [%s]\n", LEVELX(x), LEVELY(y), EL_NAME(Feld[LEVELX(x)][LEVELY(y)])); #endif 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 == REDRAW_NONE) return; if (redraw_mask & REDRAW_TILES && game_status == GAME_MODE_PLAYING && border.draw_masked[GAME_MODE_PLAYING]) redraw_mask |= REDRAW_FIELD; if (global.fps_slowdown && game_status == GAME_MODE_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(); /* prevent drawing masked border to backbuffer when using playfield buffer */ if (game_status != GAME_MODE_PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER || buffer == backbuffer) DrawMaskedBorder(redraw_mask); else DrawMaskedBorder(redraw_mask & REDRAW_DOORS); if (redraw_mask & REDRAW_ALL) { BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); redraw_mask = REDRAW_NONE; } if (redraw_mask & REDRAW_FIELD) { #if 0 printf("::: REDRAW_FIELD\n"); #endif if (game_status != GAME_MODE_PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER) { BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } else { int fx = FX, fy = FY; if (setup.soft_scrolling) { fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0); fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0); } if (setup.soft_scrolling || ABS(ScreenMovPos) + ScrollStepSize == TILEX || ABS(ScreenMovPos) == ScrollStepSize || redraw_tiles > REDRAWTILES_THRESHOLD) { if (border.draw_masked[GAME_MODE_PLAYING]) { if (buffer != backbuffer) { /* copy playfield buffer to backbuffer to add masked border */ BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY); DrawMaskedBorder(REDRAW_FIELD); } BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } else { BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY); } #if 0 #ifdef DEBUG printf("redrawing all (ScreenGfxPos == %d) because %s\n", ScreenGfxPos, (setup.soft_scrolling ? "setup.soft_scrolling" : ABS(ScreenGfxPos) + ScrollStepSize == TILEX ? "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" : ABS(ScreenGfxPos) == ScrollStepSize ? "ABS(ScreenGfxPos) == ScrollStepSize" : "redraw_tiles > REDRAWTILES_THRESHOLD")); #endif #endif } } redraw_mask &= ~REDRAW_MAIN; } if (redraw_mask & REDRAW_DOORS) { if (redraw_mask & REDRAW_DOOR_1) BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY); if (redraw_mask & REDRAW_DOOR_2) BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY); if (redraw_mask & REDRAW_DOOR_3) BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY); redraw_mask &= ~REDRAW_DOORS; } if (redraw_mask & REDRAW_MICROLEVEL) { BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY, SX, SY + 10 * TILEY); redraw_mask &= ~REDRAW_MICROLEVEL; } if (redraw_mask & REDRAW_TILES) { #if 0 printf("::: REDRAW_TILES\n"); #endif for (x = 0; x < SCR_FIELDX; x++) for (y = 0 ; y < SCR_FIELDY; y++) if (redraw[redraw_x1 + x][redraw_y1 + y]) BlitBitmap(buffer, window, FX + x * TILEX, FY + y * TILEY, TILEX, TILEY, SX + x * TILEX, SY + y * TILEY); } if (redraw_mask & REDRAW_FPS) /* display frames per second */ { char text[100]; char info1[100]; sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor); if (!global.fps_slowdown) info1[0] = '\0'; sprintf(text, "%04.1f fps%s", global.frames_per_second, info1); #if 1 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE); #else DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE); #endif } FlushDisplay(); for (x = 0; x < MAX_BUF_XSIZE; x++) for (y = 0; y < MAX_BUF_YSIZE; y++) redraw[x][y] = 0; redraw_tiles = 0; redraw_mask = REDRAW_NONE; } static void FadeCrossSaveBackbuffer() { BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); } static void FadeExt(int fade_mask, int fade_mode, int fade_type) { static int fade_type_skip = FADE_TYPE_NONE; void (*draw_border_function)(void) = NULL; Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL); int x, y, width, height; int fade_delay, post_delay; if (fade_type == FADE_TYPE_FADE_OUT) { if (fade_type_skip != FADE_TYPE_NONE) { #if 0 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip); #endif /* skip all fade operations until specified fade operation */ if (fade_type & fade_type_skip) fade_type_skip = FADE_TYPE_NONE; return; } if (fading.fade_mode & FADE_TYPE_TRANSFORM) { FadeCrossSaveBackbuffer(); return; } } redraw_mask |= fade_mask; if (fade_type == FADE_TYPE_SKIP) { #if 0 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip); #endif fade_type_skip = fade_mode; return; } #if 0 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type, fade_type_skip); #endif #if 1 fade_delay = fading.fade_delay; post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0); #endif if (fade_type_skip != FADE_TYPE_NONE) { #if 0 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip); #endif /* skip all fade operations until specified fade operation */ if (fade_type & fade_type_skip) fade_type_skip = FADE_TYPE_NONE; #if 1 fade_delay = 0; #else return; #endif } #if 1 if (global.autoplay_leveldir) { // fading.fade_mode = FADE_MODE_NONE; return; } #endif #if 0 if (fading.fade_mode == FADE_MODE_NONE) { BackToFront(); return; } #endif /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */ #if 0 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type); #endif #if 0 if (fade_mask == REDRAW_NONE) fade_mask = REDRAW_FIELD; #endif // if (fade_mask & REDRAW_FIELD) if (fade_mask == REDRAW_FIELD) { x = REAL_SX; y = REAL_SY; width = FULL_SXSIZE; height = FULL_SYSIZE; #if 0 fade_delay = fading.fade_delay; post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0); #endif if (border.draw_masked_when_fading) draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */ else DrawMaskedBorder_FIELD(); /* draw once */ } else /* REDRAW_ALL */ { x = 0; y = 0; width = WIN_XSIZE; height = WIN_YSIZE; #if 0 fade_delay = fading.fade_delay; post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0); #endif } #if 1 if (!setup.fade_screens || fade_delay == 0 || fading.fade_mode == FADE_MODE_NONE) #else if (!setup.fade_screens || fade_delay == 0) #endif { if (fade_mode == FADE_MODE_FADE_OUT) return; #if 0 if (fade_mode == FADE_MODE_FADE_OUT && fading.fade_mode != FADE_MODE_NONE) ClearRectangle(backbuffer, x, y, width, height); #endif #if 1 BlitBitmap(backbuffer, window, x, y, width, height, x, y); redraw_mask = REDRAW_NONE; #else BackToFront(); #endif return; } FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); redraw_mask &= ~fade_mask; } void FadeIn(int fade_mask) { if (fading.fade_mode & FADE_TYPE_TRANSFORM) FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN); else FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN); } void FadeOut(int fade_mask) { if (fading.fade_mode & FADE_TYPE_TRANSFORM) FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT); else FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT); global.border_status = game_status; } static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set) { static struct TitleFadingInfo fading_leave_stored; if (set) fading_leave_stored = fading_leave; else fading = fading_leave_stored; } void FadeSetEnterMenu() { fading = menu.enter_menu; #if 0 printf("::: storing enter_menu\n"); #endif FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetLeaveMenu() { fading = menu.leave_menu; #if 0 printf("::: storing leave_menu\n"); #endif FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetEnterScreen() { fading = menu.enter_screen[game_status]; #if 0 printf("::: storing leave_screen[%d]\n", game_status); #endif FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */ } void FadeSetNextScreen() { fading = menu.next_screen; #if 0 printf("::: storing next_screen\n"); #endif // (do not overwrite fade mode set by FadeSetEnterScreen) // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetLeaveScreen() { #if 0 printf("::: recalling last stored value\n"); #endif FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */ } void FadeSetFromType(int type) { if (type & TYPE_ENTER_SCREEN) FadeSetEnterScreen(); else if (type & TYPE_ENTER) FadeSetEnterMenu(); else if (type & TYPE_LEAVE) FadeSetLeaveMenu(); } void FadeSetDisabled() { static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 }; fading = fading_none; } void FadeSkipNextFadeIn() { FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP); } void FadeSkipNextFadeOut() { FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP); } void SetWindowBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetWindowBackgroundBitmap(graphic_info[graphic].bitmap); } void SetMainBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetMainBackgroundBitmap(graphic_info[graphic].bitmap); } void SetDoorBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetDoorBackgroundBitmap(graphic_info[graphic].bitmap); } void SetWindowBackgroundImage(int graphic) { SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL : graphic_info[graphic].bitmap ? graphic_info[graphic].bitmap : graphic_info[IMG_BACKGROUND].bitmap); } void SetMainBackgroundImage(int graphic) { SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL : graphic_info[graphic].bitmap ? graphic_info[graphic].bitmap : graphic_info[IMG_BACKGROUND].bitmap); } void SetDoorBackgroundImage(int graphic) { SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL : graphic_info[graphic].bitmap ? graphic_info[graphic].bitmap : graphic_info[IMG_BACKGROUND].bitmap); } void SetPanelBackground() { BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0); SetDoorBackgroundBitmap(bitmap_db_panel); } void DrawBackground(int x, int y, int width, int height) { /* !!! "drawto" might still point to playfield buffer here (see below) !!! */ /* (when entering hall of fame after playing) */ #if 0 ClearRectangleOnBackground(drawto, x, y, width, height); #else ClearRectangleOnBackground(backbuffer, x, y, width, height); #endif redraw_mask |= REDRAW_FIELD; } void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr) { struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); if (font->bitmap == NULL) return; DrawBackground(x, y, width, height); } void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic) { struct GraphicInfo *g = &graphic_info[graphic]; if (g->bitmap == NULL) return; DrawBackground(x, y, width, height); } void ClearField() { /* !!! "drawto" might still point to playfield buffer here (see above) !!! */ /* (when entering hall of fame after playing) */ DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); /* !!! maybe this should be done before clearing the background !!! */ if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING) { ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE); SetDrawtoField(DRAW_BUFFERED); } else SetDrawtoField(DRAW_BACKBUFFER); } void MarkTileDirty(int x, int y) { int xx = redraw_x1 + x; int yy = redraw_y1 + y; if (!redraw[xx][yy]) redraw_tiles++; redraw[xx][yy] = TRUE; redraw_mask |= REDRAW_TILES; } void SetBorderElement() { int x, y; BorderElement = EL_EMPTY; for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++) { for (x = 0; x < lev_fieldx; x++) { if (!IS_INDESTRUCTIBLE(Feld[x][y])) BorderElement = EL_STEELWALL; if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1) x = lev_fieldx - 2; } } } void FloodFillLevel(int from_x, int from_y, int fill_element, short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY], int max_fieldx, int max_fieldy) { 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 (field[from_x][from_y] == fill_element) return; safety++; if (safety > max_fieldx * max_fieldy) Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug."); old_element = field[from_x][from_y]; field[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_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element) FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy); } safety--; } void SetRandomAnimationValue(int x, int y) { gfx.anim_random_frame = GfxRandom[x][y]; } inline int getGraphicAnimationFrame(int graphic, int sync_frame) { /* animation synchronized with global frame counter, not move position */ if (graphic_info[graphic].anim_global_sync || sync_frame < 0) sync_frame = FrameCounter; return getAnimationFrame(graphic_info[graphic].anim_frames, graphic_info[graphic].anim_delay, graphic_info[graphic].anim_mode, graphic_info[graphic].anim_start_frame, sync_frame); } void getSizedGraphicSource(int graphic, int frame, int tilesize_raw, Bitmap **bitmap, int *x, int *y) { struct { int width_mult, width_div; int height_mult, height_div; } offset_calc[6] = { { 15, 16, 2, 3 }, /* 1 x 1 */ { 7, 8, 2, 3 }, /* 2 x 2 */ { 3, 4, 2, 3 }, /* 4 x 4 */ { 1, 2, 2, 3 }, /* 8 x 8 */ { 0, 1, 2, 3 }, /* 16 x 16 */ { 0, 1, 0, 1 }, /* 32 x 32 */ }; struct GraphicInfo *g = &graphic_info[graphic]; Bitmap *src_bitmap = g->bitmap; int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE); int offset_calc_pos = log_2(tilesize); int width_mult = offset_calc[offset_calc_pos].width_mult; int width_div = offset_calc[offset_calc_pos].width_div; int height_mult = offset_calc[offset_calc_pos].height_mult; int height_div = offset_calc[offset_calc_pos].height_div; int startx = src_bitmap->width * width_mult / width_div; int starty = src_bitmap->height * height_mult / height_div; int src_x = g->src_x * tilesize / TILESIZE; int src_y = g->src_y * tilesize / TILESIZE; int width = g->width * tilesize / TILESIZE; int height = g->height * tilesize / TILESIZE; int offset_x = g->offset_x * tilesize / TILESIZE; int offset_y = g->offset_y * tilesize / TILESIZE; if (g->offset_y == 0) /* frames are ordered horizontally */ { int max_width = g->anim_frames_per_line * width; int pos = (src_y / height) * max_width + src_x + frame * offset_x; src_x = pos % max_width; src_y = src_y % height + pos / max_width * height; } else if (g->offset_x == 0) /* frames are ordered vertically */ { int max_height = g->anim_frames_per_line * height; int pos = (src_x / width) * max_height + src_y + frame * offset_y; src_x = src_x % width + pos / max_height * width; src_y = pos % max_height; } else /* frames are ordered diagonally */ { src_x = src_x + frame * offset_x; src_y = src_y + frame * offset_y; } *bitmap = src_bitmap; *x = startx + src_x; *y = starty + src_y; } void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) { #if 1 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y); #else struct GraphicInfo *g = &graphic_info[graphic]; int mini_startx = 0; int mini_starty = g->bitmap->height * 2 / 3; *bitmap = g->bitmap; *x = mini_startx + g->src_x / 2; *y = mini_starty + g->src_y / 2; #endif } inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap, int *x, int *y, boolean get_backside) { struct GraphicInfo *g = &graphic_info[graphic]; int src_x = g->src_x + (get_backside ? g->offset2_x : 0); int src_y = g->src_y + (get_backside ? g->offset2_y : 0); *bitmap = g->bitmap; if (g->offset_y == 0) /* frames are ordered horizontally */ { int max_width = g->anim_frames_per_line * g->width; int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x; *x = pos % max_width; *y = src_y % g->height + pos / max_width * g->height; } else if (g->offset_x == 0) /* frames are ordered vertically */ { int max_height = g->anim_frames_per_line * g->height; int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y; *x = src_x % g->width + pos / max_height * g->width; *y = pos % max_height; } else /* frames are ordered diagonally */ { *x = src_x + frame * g->offset_x; *y = src_y + frame * g->offset_y; } } void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y) { getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE); } void DrawGraphic(int x, int y, int graphic, int frame) { #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"); return; } #endif DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame); MarkTileDirty(x, y); } void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y); } void DrawGraphicThruMask(int x, int y, int graphic, int frame) { #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, frame); MarkTileDirty(x, y); } void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y); } void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize) { DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic, frame, tilesize); MarkTileDirty(x / tilesize, y / tilesize); } void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame, int tilesize) { Bitmap *src_bitmap; int src_x, src_y; getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, 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 DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic) { Bitmap *src_bitmap; int src_x, src_y; getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y); } inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { Bitmap *src_bitmap; int src_x, src_y; int dst_x, dst_y; int width = TILEX, height = TILEY; int cx = 0, cy = 0; if (dx || dy) /* shifted graphic */ { if (x < BX1) /* object enters playfield from the left */ { x = BX1; width = dx; cx = TILEX - dx; dx = 0; } else if (x > BX2) /* object enters playfield from the right */ { x = BX2; width = -dx; dx = TILEX + dx; } else if (x==BX1 && dx < 0) /* object leaves playfield to the left */ { width += dx; cx = -dx; dx = 0; } else if (x==BX2 && dx > 0) /* object leaves playfield to the right */ width -= dx; else if (dx) /* general horizontal movement */ MarkTileDirty(x + SIGN(dx), y); if (y < BY1) /* object enters playfield from the top */ { if (cut_mode==CUT_BELOW) /* object completely above top border */ return; y = BY1; height = dy; cy = TILEY - dy; dy = 0; } else if (y > BY2) /* object enters playfield from the bottom */ { y = BY2; height = -dy; dy = TILEY + dy; } else if (y==BY1 && dy < 0) /* object leaves playfield to the top */ { height += dy; cy = -dy; dy = 0; } else if (dy > 0 && cut_mode == CUT_ABOVE) { if (y == BY2) /* object completely above bottom border */ return; height = dy; cy = TILEY - dy; dy = TILEY; MarkTileDirty(x, y + 1); } /* object leaves playfield to the bottom */ else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW)) height -= dy; else if (dy) /* general vertical movement */ MarkTileDirty(x, y + SIGN(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 (width > 0 && height > 0) { getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); src_x += cx; src_y += cy; dst_x = FX + x * TILEX + dx; dst_y = FY + y * TILEY + dy; if (mask_mode == USE_MASKING) { SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x, y); } } inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { Bitmap *src_bitmap; int src_x, src_y; int dst_x, dst_y; int width = TILEX, height = TILEY; int x1 = x; int y1 = y; int x2 = x + SIGN(dx); int y2 = y + SIGN(dy); #if 0 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */ int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)]; #else /* movement with two-tile animations must be sync'ed with movement position, not with current GfxFrame (which can be higher when using slow movement) */ int anim_pos = (dx ? ABS(dx) : ABS(dy)); int anim_frames = graphic_info[graphic].anim_frames; #if 1 /* (we also need anim_delay here for movement animations with less frames) */ int anim_delay = graphic_info[graphic].anim_delay; int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE; #else int sync_frame = anim_pos * anim_frames / TILESIZE; #endif #endif boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */ boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */ /* re-calculate animation frame for two-tile movement animation */ frame = getGraphicAnimationFrame(graphic, sync_frame); #if 0 #if 0 printf("::: %d, %d, %d => %d [%d]\n", anim_pos, anim_frames, anim_delay, sync_frame, graphic); #else printf("::: %d, %d => %d\n", anim_pos, anim_frames, sync_frame); #endif #endif #if 0 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy, GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode); #endif /* check if movement start graphic inside screen area and should be drawn */ if (draw_start_tile && IN_SCR_FIELD(x1, y1)) { getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE); dst_x = FX + x1 * TILEX; dst_y = FY + y1 * TILEY; if (mask_mode == USE_MASKING) { SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x1, y1); } /* check if movement end graphic inside screen area and should be drawn */ if (draw_end_tile && IN_SCR_FIELD(x2, y2)) { getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE); dst_x = FX + x2 * TILEX; dst_y = FY + y2 * TILEY; if (mask_mode == USE_MASKING) { SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x2, y2); } } static void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { if (graphic < 0) { DrawGraphic(x, y, graphic, frame); return; } if (graphic_info[graphic].double_movement) /* EM style movement images */ DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode); else DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode); } void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode) { DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING); } void DrawScreenElementExt(int x, int y, int dx, int dy, int element, int cut_mode, int mask_mode) { int lx = LEVELX(x), ly = LEVELY(y); int graphic; int frame; if (IN_LEV_FIELD(lx, ly)) { SetRandomAnimationValue(lx, ly); graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]); frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]); /* do not use double (EM style) movement graphic when not moving */ if (graphic_info[graphic].double_movement && !dx && !dy) { graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]); frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]); } } else /* border element */ { graphic = el2img(element); frame = getGraphicAnimationFrame(graphic, -1); } if (element == EL_EXPANDABLE_WALL) { boolean left_stopped = FALSE, right_stopped = FALSE; if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly])) left_stopped = TRUE; if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly])) right_stopped = TRUE; if (left_stopped && right_stopped) graphic = IMG_WALL; else if (left_stopped) { graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT; frame = graphic_info[graphic].anim_frames - 1; } else if (right_stopped) { graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT; frame = graphic_info[graphic].anim_frames - 1; } } if (dx || dy) DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode); else if (mask_mode == USE_MASKING) DrawGraphicThruMask(x, y, graphic, frame); else DrawGraphic(x, y, graphic, frame); } 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 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); } /* !!! implementation of quicksand is totally broken !!! */ #define IS_CRUMBLED_TILE(x, y, e) \ (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \ !IS_MOVING(x, y) || \ (e) == EL_QUICKSAND_EMPTYING || \ (e) == EL_QUICKSAND_FAST_EMPTYING)) static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy, int graphic) { Bitmap *src_bitmap; int src_x, src_y; int width, height, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; int i; getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); for (i = 1; i < 4; i++) { int dxx = (i & 1 ? dx : 0); int dyy = (i & 2 ? dy : 0); int xx = x + dxx; int yy = y + dyy; int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ boolean same = (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class); /* return if check prevents inner corner */ if (same == (dxx == dx && dyy == dy)) return; } /* if we reach this point, we have an inner corner */ getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y); width = crumbled_border_size; height = crumbled_border_size; cx = (dx > 0 ? TILEX - crumbled_border_size : 0); cy = (dy > 0 ? TILEY - crumbled_border_size : 0); BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy); } static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame, int dir) { Bitmap *src_bitmap; int src_x, src_y; int width, height, bx, by, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; int i; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); /* draw simple, sloppy, non-corner-accurate crumbled border */ #if 1 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX); height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY); cx = (dir == 2 ? TILEX - crumbled_border_size : 0); cy = (dir == 3 ? TILEY - crumbled_border_size : 0); #else if (dir == 1 || dir == 2) /* left or right crumbled border */ { width = crumbled_border_size; height = TILEY; cx = (dir == 2 ? TILEX - crumbled_border_size : 0); cy = 0; } else /* top or bottom crumbled border */ { width = TILEX; height = crumbled_border_size; cx = 0; cy = (dir == 3 ? TILEY - crumbled_border_size : 0); } #endif BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy); /* (remaining middle border part must be at least as big as corner part) */ if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) || crumbled_border_size >= TILESIZE / 3) return; /* correct corners of crumbled border, if needed */ #if 1 for (i = -1; i <= 1; i+=2) { int xx = x + (dir == 0 || dir == 3 ? i : 0); int yy = y + (dir == 1 || dir == 2 ? i : 0); int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) { /* no crumbled corner, but continued crumbled border */ int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0); int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0); int b1 = (i == 1 ? crumbled_border_size : TILESIZE - 2 * crumbled_border_size); width = crumbled_border_size; height = crumbled_border_size; if (dir == 1 || dir == 2) { cx = c1; cy = c2; bx = cx; by = b1; } else { cx = c2; cy = c1; bx = b1; by = cy; } BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by, width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy); } } #else if (dir == 1 || dir == 2) /* left or right crumbled border */ { for (i = -1; i <= 1; i+=2) { int xx = x; int yy = y + i; int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) { /* no crumbled corner, but continued crumbled border */ width = crumbled_border_size; height = crumbled_border_size; cx = (dir == 2 ? TILEX - crumbled_border_size : 0); cy = (i == 1 ? TILEY - crumbled_border_size : 0); bx = cx; by = (i == 1 ? crumbled_border_size : TILEY - 2 * crumbled_border_size); BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by, width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy); } } } else /* top or bottom crumbled border */ { for (i = -1; i <= 1; i+=2) { int xx = x + i; int yy = y; int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) { /* no crumbled corner, but continued crumbled border */ width = crumbled_border_size; height = crumbled_border_size; cx = (i == 1 ? TILEX - crumbled_border_size : 0); cy = (dir == 3 ? TILEY - crumbled_border_size : 0); bx = (i == 1 ? crumbled_border_size : TILEX - 2 * crumbled_border_size); by = cy; BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by, width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy); } } } #endif } static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) { int sx = SCREENX(x), sy = SCREENY(y); int element; int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!IN_LEV_FIELD(x, y)) return; element = TILE_GFX_ELEMENT(x, y); /* crumble field itself */ if (IS_CRUMBLED_TILE(x, y, element)) { if (!IN_SCR_FIELD(sx, sy)) return; for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ #if 1 if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) continue; #else if (IS_CRUMBLED_TILE(xx, yy, element)) continue; #endif DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i); } if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && graphic_info[graphic].anim_frames == 2) { for (i = 0; i < 4; i++) { int dx = (i & 1 ? +1 : -1); int dy = (i & 2 ? +1 : -1); DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic); } } MarkTileDirty(sx, sy); } else /* center field not crumbled -- crumble neighbour fields */ { for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int sxx = sx + xy[i][0]; int syy = sy + xy[i][1]; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy)) continue; if (Feld[xx][yy] == EL_ELEMENT_SNAPPING) continue; element = TILE_GFX_ELEMENT(xx, yy); if (!IS_CRUMBLED_TILE(xx, yy, element)) continue; graphic = el_act2crm(element, ACTION_DEFAULT); DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i); MarkTileDirty(sxx, syy); } } } void DrawLevelFieldCrumbled(int x, int y) { int graphic; if (!IN_LEV_FIELD(x, y)) return; #if 1 /* !!! CHECK THIS !!! */ /* if (Feld[x][y] == EL_ELEMENT_SNAPPING && GFX_CRUMBLED(GfxElement[x][y])) */ if (Feld[x][y] == EL_ELEMENT_SNAPPING && GfxElement[x][y] != EL_UNDEFINED && GFX_CRUMBLED(GfxElement[x][y])) { DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]); return; } #endif #if 1 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT); #else graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT); #endif DrawLevelFieldCrumbledExt(x, y, graphic, 0); } void DrawLevelFieldCrumbledDigging(int x, int y, int direction, int step_frame) { int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction); int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction); int frame1 = getGraphicAnimationFrame(graphic1, step_frame); int frame2 = getGraphicAnimationFrame(graphic2, step_frame); int sx = SCREENX(x), sy = SCREENY(y); DrawGraphic(sx, sy, graphic1, frame1); DrawLevelFieldCrumbledExt(x, y, graphic2, frame2); } void DrawLevelFieldCrumbledNeighbours(int x, int y) { int sx = SCREENX(x), sy = SCREENY(y); static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; int i; for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int sxx = sx + xy[i][0]; int syy = sy + xy[i][1]; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy) || !GFX_CRUMBLED(Feld[xx][yy]) || IS_MOVING(xx, yy)) continue; DrawLevelField(xx, yy); } } static int getBorderElement(int x, int y) { int border[7][2] = { { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT }, { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT }, { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT }, { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT }, { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL }, { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL }, { EL_STEELWALL, EL_INVISIBLE_STEELWALL } }; int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1); int steel_position = (x == -1 && y == -1 ? 0 : x == lev_fieldx && y == -1 ? 1 : x == -1 && y == lev_fieldy ? 2 : x == lev_fieldx && y == lev_fieldy ? 3 : x == -1 || x == lev_fieldx ? 4 : y == -1 || y == lev_fieldy ? 5 : 6); return border[steel_position][steel_type]; } void DrawScreenElement(int x, int y, int element) { DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING); DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y)); } 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 lx = LEVELX(x), ly = LEVELY(y); int element, content; if (!IN_LEV_FIELD(lx, ly)) { if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy) element = EL_EMPTY; else element = getBorderElement(lx, ly); DrawScreenElement(x, y, element); return; } element = Feld[lx][ly]; content = Store[lx][ly]; if (IS_MOVING(lx, ly)) { int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT); boolean cut_mode = NO_CUTTING; if (element == EL_QUICKSAND_EMPTYING || element == EL_QUICKSAND_FAST_EMPTYING || element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_EMPTYING || element == EL_DC_MAGIC_WALL_EMPTYING || element == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; else if (element == EL_QUICKSAND_FILLING || element == EL_QUICKSAND_FAST_FILLING || element == EL_MAGIC_WALL_FILLING || element == EL_BD_MAGIC_WALL_FILLING || element == EL_DC_MAGIC_WALL_FILLING) cut_mode = CUT_BELOW; #if 0 if (lx == 9 && ly == 1) printf("::: %s [%d] [%d, %d] [%d]\n", EL_NAME(TILE_GFX_ELEMENT(lx, ly)), el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT), element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT], element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT], GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly))); #endif if (cut_mode == CUT_ABOVE) #if 1 DrawScreenElement(x, y, element); #else DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING); #endif else DrawScreenElement(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING); else if (cut_mode == NO_CUTTING) DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode); else { DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode); #if 1 if (cut_mode == CUT_BELOW && IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1)) DrawLevelElement(lx, ly + 1, element); #endif } if (content == EL_ACID) { int dir = MovDir[lx][ly]; int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0); int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); DrawLevelElementThruMask(newlx, newly, EL_ACID); } } else if (IS_BLOCKED(lx, ly)) { int oldx, oldy; int sx, sy; int horiz_move; boolean cut_mode = NO_CUTTING; int element_old, content_old; Blocked2Moving(lx, ly, &oldx, &oldy); sx = SCREENX(oldx); sy = SCREENY(oldy); horiz_move = (MovDir[oldx][oldy] == MV_LEFT || MovDir[oldx][oldy] == MV_RIGHT); element_old = Feld[oldx][oldy]; content_old = Store[oldx][oldy]; if (element_old == EL_QUICKSAND_EMPTYING || element_old == EL_QUICKSAND_FAST_EMPTYING || element_old == EL_MAGIC_WALL_EMPTYING || element_old == EL_BD_MAGIC_WALL_EMPTYING || element_old == EL_DC_MAGIC_WALL_EMPTYING || element_old == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; DrawScreenElement(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old, NO_CUTTING); else if (cut_mode == NO_CUTTING) DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old, cut_mode); else DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old, cut_mode); } else if (IS_DRAWABLE(element)) DrawScreenElement(x, y, element); else DrawScreenElement(x, y, EL_EMPTY); } void DrawLevelField(int x, int y) { if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) DrawScreenField(SCREENX(x), SCREENY(y)); else if (IS_MOVING(x, y)) { int newx,newy; Moving2Blocked(x, y, &newx, &newy); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) DrawScreenField(SCREENX(newx), SCREENY(newy)); } else if (IS_BLOCKED(x, y)) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy))) DrawScreenField(SCREENX(oldx), SCREENY(oldy)); } } void DrawMiniElement(int x, int y, int element) { int graphic; graphic = el2edimg(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]); else DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y))); } void DrawEnvelopeBackground(int envelope_nr, int startx, int starty, int x, int y, int xsize, int ysize, int font_nr) { int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; Bitmap *src_bitmap; int src_x, src_y; int dst_x = SX + startx + x * font_width; int dst_y = SY + starty + y * font_height; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int inner_width = MAX(width - 2 * font_width, font_width); int inner_height = MAX(height - 2 * font_height, font_height); int inner_sx = (width >= 3 * font_width ? font_width : 0); int inner_sy = (height >= 3 * font_height ? font_height : 0); boolean draw_masked = graphic_info[graphic].draw_masked; getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); if (src_bitmap == NULL || width < font_width || height < font_height) { ClearRectangle(drawto, dst_x, dst_y, font_width, font_height); return; } src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width : inner_sx + (x - 1) * font_width % inner_width); src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height : inner_sy + (y - 1) * font_height % inner_height); if (draw_masked) { SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height, dst_x, dst_y); } else BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height, dst_x, dst_y); } void AnimateEnvelope(int envelope_nr, int anim_mode, int action) { int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; Bitmap *src_bitmap = graphic_info[graphic].bitmap; int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); unsigned long anim_delay = 0; int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int anim_delay_value = (no_delay ? 0 : frame_delay_value); int font_nr = FONT_ENVELOPE_1 + envelope_nr; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int max_xsize = level.envelope[envelope_nr].xsize; int max_ysize = level.envelope[envelope_nr].ysize; int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0); int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0); int xend = max_xsize; int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0); int xstep = (xstart < xend ? 1 : 0); int ystep = (ystart < yend || xstep == 0 ? 1 : 0); int x, y; for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep) { int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2; int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2; int sx = (SXSIZE - xsize * font_width) / 2; int sy = (SYSIZE - ysize * font_height) / 2; int xx, yy; SetDrawtoField(DRAW_BUFFERED); BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); SetDrawtoField(DRAW_BACKBUFFER); for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr); #if 1 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, 0, mask_mode, level.envelope[envelope_nr].autowrap, level.envelope[envelope_nr].centered, FALSE); #else DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, mask_mode); #endif redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER; BackToFront(); WaitUntilDelayReached(&anim_delay, anim_delay_value / 2); } } void AnimateEnvelopeDoor(char *text, int anim_mode, int action) { #if 1 int envelope_nr = 0; #endif int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; Bitmap *src_bitmap = graphic_info[graphic].bitmap; int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); unsigned long anim_delay = 0; int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int anim_delay_value = (no_delay ? 0 : frame_delay_value); #if 1 int max_word_len = maxWordLengthInString(text); int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2); #else int font_nr = FONT_ENVELOPE_1 + envelope_nr; #endif int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); #if 1 #if 1 int max_xsize = DXSIZE / font_width; int max_ysize = DYSIZE / font_height; #else int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */ int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */ #endif #else int max_xsize = level.envelope[envelope_nr].xsize; int max_ysize = level.envelope[envelope_nr].ysize; #endif int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0); int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0); int xend = max_xsize; int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0); int xstep = (xstart < xend ? 1 : 0); int ystep = (ystart < yend || xstep == 0 ? 1 : 0); int x, y; #if 1 char *text_ptr; char *text_copy = getStringCopy(text); #else #if 1 font_nr = FONT_TEXT_2; if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */ { max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */ font_nr = FONT_TEXT_1; } #else int max_word_len = 0; char *text_ptr; char *text_copy = getStringCopy(text); font_nr = FONT_TEXT_2; for (text_ptr = text; *text_ptr; text_ptr++) { max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0); if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */ { max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */ font_nr = FONT_TEXT_1; break; } } #endif #endif #if 1 for (text_ptr = text_copy; *text_ptr; text_ptr++) if (*text_ptr == ' ') *text_ptr = '\n'; #endif #if 1 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX; dDY = SY + (SYSIZE - DYSIZE) / 2 - DY; #else dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX; dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY; #endif for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep) { int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2; int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2; int sx = (SXSIZE - xsize * font_width) / 2; int sy = (SYSIZE - ysize * font_height) / 2; int xx, yy; #if 1 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); #else SetDrawtoField(DRAW_BUFFERED); BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); SetDrawtoField(DRAW_BACKBUFFER); #endif for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr); #if 1 #if 1 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8, text_copy, font_nr, max_xsize, xsize - 2, ysize - 2, 2, mask_mode, FALSE, TRUE, FALSE); #else DrawTextBuffer(SX + sx + font_width, SY + sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, 0, mask_mode, level.envelope[envelope_nr].autowrap, level.envelope[envelope_nr].centered, FALSE); #endif #else DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, mask_mode); #endif /* copy request gadgets to door backbuffer */ #if 1 if ((ysize - 2) > 13) BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2, DOOR_GFX_PAGEY1 + 13 * font_height, (xsize - 2) * font_width, (ysize - 2 - 13) * font_height, SX + sx + font_width, SY + sy + font_height * (1 + 13)); #else if ((ysize - 2) > 13) BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2, DOOR_GFX_PAGEY1 + 13 * font_height, (xsize - 2) * font_width, (ysize - 2 - 13) * font_height, SX + sx + font_width, SY + sy + font_height * (1 + 13)); #endif #if 1 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER; // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER; #else redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER; #endif #if 1 DoAnimation(); BackToFront(); #else BackToFront(); #endif WaitUntilDelayReached(&anim_delay, anim_delay_value / 2); } #if 1 free(text_copy); #endif } void ShowEnvelope(int envelope_nr) { int element = EL_ENVELOPE_1 + envelope_nr; int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; int sound_opening = element_info[element].sound[ACTION_OPENING]; int sound_closing = element_info[element].sound[ACTION_CLOSING]; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1); int wait_delay_value = (no_delay ? 0 : normal_delay_value); int anim_mode = graphic_info[graphic].anim_mode; int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL: anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode); game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */ PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE); if (anim_mode == ANIM_DEFAULT) AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING); AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING); if (tape.playing) Delay(wait_delay_value); else WaitForEventToContinue(); PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE); if (anim_mode != ANIM_NONE) AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING); if (anim_mode == ANIM_DEFAULT) AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING); game.envelope_active = FALSE; SetDrawtoField(DRAW_BUFFERED); redraw_mask |= REDRAW_FIELD; BackToFront(); } void ShowEnvelopeDoor(char *text, int action) { #if 1 int last_game_status = game_status; /* save current game status */ // int last_draw_background_mask = gfx.draw_background_mask; int envelope_nr = 0; #endif int element = EL_ENVELOPE_1 + envelope_nr; int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; int sound_opening = element_info[element].sound[ACTION_OPENING]; int sound_closing = element_info[element].sound[ACTION_CLOSING]; #if 0 boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1); int wait_delay_value = (no_delay ? 0 : normal_delay_value); #endif int anim_mode = graphic_info[graphic].anim_mode; int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL: anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode); #if 1 if (game_status == GAME_MODE_PLAYING) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) BlitScreenToBitmap_EM(backbuffer); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) BlitScreenToBitmap_SP(backbuffer); else { BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); } } SetDrawtoField(DRAW_BACKBUFFER); // SetDrawBackgroundMask(REDRAW_NONE); if (action == ACTION_OPENING) { BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); if (game_status != GAME_MODE_MAIN) InitAnimation(); } /* force DOOR font inside door area */ game_status = GAME_MODE_PSEUDO_DOOR; #endif game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */ if (action == ACTION_OPENING) { PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE); if (anim_mode == ANIM_DEFAULT) AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING); AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING); #if 0 if (tape.playing) Delay(wait_delay_value); else WaitForEventToContinue(); #endif } else { PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE); if (anim_mode != ANIM_NONE) AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING); if (anim_mode == ANIM_DEFAULT) AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING); } game.envelope_active = FALSE; #if 1 game_status = last_game_status; /* restore current game status */ if (action == ACTION_CLOSING) { if (game_status != GAME_MODE_MAIN) StopAnimation(); BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); } #else SetDrawtoField(DRAW_BUFFERED); #endif // SetDrawBackgroundMask(last_draw_background_mask); #if 1 redraw_mask = REDRAW_FIELD; // redraw_mask |= REDRAW_ALL; #else redraw_mask |= REDRAW_FIELD; #endif #if 1 if (game_status == GAME_MODE_MAIN) DoAnimation(); BackToFront(); if (game_status == GAME_MODE_PLAYING && level.game_engine_type == GAME_ENGINE_TYPE_RND) SetDrawtoField(DRAW_BUFFERED); #else BackToFront(); #endif } void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize) { Bitmap *src_bitmap; int src_x, src_y; int graphic = el2preimg(element); getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y); } void DrawLevel() { int x,y; #if 1 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING); SetDrawBackgroundMask(REDRAW_FIELD); #else SetDrawBackgroundMask(REDRAW_NONE); #endif ClearField(); for (x = BX1; x <= BX2; x++) for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); redraw_mask |= REDRAW_FIELD; } void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) { int x,y; for (x = 0; x < size_x; x++) for (y = 0; y < size_y; y++) DrawMiniElementOrWall(x, y, scroll_x, scroll_y); redraw_mask |= REDRAW_FIELD; } static void DrawPreviewLevelExt(int from_x, int from_y) { boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); int tile_size = preview.tile_size; int preview_width = preview.xsize * tile_size; int preview_height = preview.ysize * tile_size; int real_preview_xsize = MIN(level_xsize, preview.xsize); int real_preview_ysize = MIN(level_ysize, preview.ysize); int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align); int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign); int x, y; DrawBackground(dst_x, dst_y, preview_width, preview_height); dst_x += (preview_width - real_preview_xsize * tile_size) / 2; dst_y += (preview_height - real_preview_ysize * tile_size) / 2; for (x = 0; x < real_preview_xsize; x++) { for (y = 0; y < real_preview_ysize; y++) { int lx = from_x + x + (show_level_border ? -1 : 0); int ly = from_y + y + (show_level_border ? -1 : 0); int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] : getBorderElement(lx, ly)); DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size, element, tile_size); } } redraw_mask |= REDRAW_MICROLEVEL; } #define MICROLABEL_EMPTY 0 #define MICROLABEL_LEVEL_NAME 1 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2 #define MICROLABEL_LEVEL_AUTHOR 3 #define MICROLABEL_IMPORTED_FROM_HEAD 4 #define MICROLABEL_IMPORTED_FROM 5 #define MICROLABEL_IMPORTED_BY_HEAD 6 #define MICROLABEL_IMPORTED_BY 7 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr) { int max_text_width = SXSIZE; int font_width = getFontWidth(font_nr); if (pos->align == ALIGN_CENTER) max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2); else if (pos->align == ALIGN_RIGHT) max_text_width = pos->x; else max_text_width = SXSIZE - pos->x; return max_text_width / font_width; } static void DrawPreviewLevelLabelExt(int mode) { struct TextPosInfo *pos = &menu.main.text.level_info_2; char label_text[MAX_OUTPUT_LINESIZE + 1]; int max_len_label_text; #if 1 int font_nr = pos->font; int i; if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD || mode == MICROLABEL_IMPORTED_FROM_HEAD || mode == MICROLABEL_IMPORTED_BY_HEAD) font_nr = pos->font_alt; #else int font_nr = FONT_TEXT_2; int i; if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD || mode == MICROLABEL_IMPORTED_FROM_HEAD || mode == MICROLABEL_IMPORTED_BY_HEAD) font_nr = FONT_TEXT_3; #endif #if 1 max_len_label_text = getMaxTextLength(pos, font_nr); #else max_len_label_text = SXSIZE / getFontWidth(font_nr); #endif #if 1 if (pos->size != -1) max_len_label_text = pos->size; #endif for (i = 0; i < max_len_label_text; i++) label_text[i] = ' '; label_text[max_len_label_text] = '\0'; if (strlen(label_text) > 0) { #if 1 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); #else int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; int lypos = MICROLABEL2_YPOS; DrawText(lxpos, lypos, label_text, font_nr); #endif } strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name : mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" : mode == MICROLABEL_LEVEL_AUTHOR ? level.author : mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" : mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from : mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" : mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""), max_len_label_text); label_text[max_len_label_text] = '\0'; if (strlen(label_text) > 0) { #if 1 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); #else int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; int lypos = MICROLABEL2_YPOS; DrawText(lxpos, lypos, label_text, font_nr); #endif } redraw_mask |= REDRAW_MICROLEVEL; } void DrawPreviewLevel(boolean restart) { static unsigned long scroll_delay = 0; static unsigned long label_delay = 0; static int from_x, from_y, scroll_direction; static int label_state, label_counter; unsigned long scroll_delay_value = preview.step_delay; boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); int last_game_status = game_status; /* save current game status */ #if 0 /* force PREVIEW font on preview level */ game_status = GAME_MODE_PSEUDO_PREVIEW; #endif if (restart) { from_x = 0; from_y = 0; if (preview.anim_mode == ANIM_CENTERED) { if (level_xsize > preview.xsize) from_x = (level_xsize - preview.xsize) / 2; if (level_ysize > preview.ysize) from_y = (level_ysize - preview.ysize) / 2; } from_x += preview.xoffset; from_y += preview.yoffset; scroll_direction = MV_RIGHT; label_state = 1; label_counter = 0; DrawPreviewLevelExt(from_x, from_y); DrawPreviewLevelLabelExt(label_state); /* initialize delay counters */ DelayReached(&scroll_delay, 0); DelayReached(&label_delay, 0); if (leveldir_current->name) { struct TextPosInfo *pos = &menu.main.text.level_info_1; char label_text[MAX_OUTPUT_LINESIZE + 1]; #if 1 int font_nr = pos->font; #else int font_nr = FONT_TEXT_1; #endif #if 1 int max_len_label_text = getMaxTextLength(pos, font_nr); #else int max_len_label_text = SXSIZE / getFontWidth(font_nr); #endif #if 0 int text_width; int lxpos, lypos; #endif #if 1 if (pos->size != -1) max_len_label_text = pos->size; #endif strncpy(label_text, leveldir_current->name, max_len_label_text); label_text[max_len_label_text] = '\0'; #if 1 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); #else lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; lypos = SY + MICROLABEL1_YPOS; DrawText(lxpos, lypos, label_text, font_nr); #endif } game_status = last_game_status; /* restore current game status */ return; } /* scroll preview level, if needed */ if (preview.anim_mode != ANIM_NONE && (level_xsize > preview.xsize || level_ysize > preview.ysize) && DelayReached(&scroll_delay, scroll_delay_value)) { switch (scroll_direction) { case MV_LEFT: if (from_x > 0) { from_x -= preview.step_offset; from_x = (from_x < 0 ? 0 : from_x); } else scroll_direction = MV_UP; break; case MV_RIGHT: if (from_x < level_xsize - preview.xsize) { from_x += preview.step_offset; from_x = (from_x > level_xsize - preview.xsize ? level_xsize - preview.xsize : from_x); } else scroll_direction = MV_DOWN; break; case MV_UP: if (from_y > 0) { from_y -= preview.step_offset; from_y = (from_y < 0 ? 0 : from_y); } else scroll_direction = MV_RIGHT; break; case MV_DOWN: if (from_y < level_ysize - preview.ysize) { from_y += preview.step_offset; from_y = (from_y > level_ysize - preview.ysize ? level_ysize - preview.ysize : from_y); } else scroll_direction = MV_LEFT; break; default: break; } DrawPreviewLevelExt(from_x, from_y); } /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */ /* redraw micro level label, if needed */ if (!strEqual(level.name, NAMELESS_LEVEL_NAME) && !strEqual(level.author, ANONYMOUS_NAME) && !strEqual(level.author, leveldir_current->name) && DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY)) { int max_label_counter = 23; if (leveldir_current->imported_from != NULL && strlen(leveldir_current->imported_from) > 0) max_label_counter += 14; if (leveldir_current->imported_by != NULL && strlen(leveldir_current->imported_by) > 0) 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_LEVEL_AUTHOR_HEAD : label_counter >= 14 && label_counter <= 21 ? MICROLABEL_LEVEL_AUTHOR : label_counter >= 23 && label_counter <= 26 ? MICROLABEL_IMPORTED_FROM_HEAD : label_counter >= 28 && label_counter <= 35 ? MICROLABEL_IMPORTED_FROM : label_counter >= 37 && label_counter <= 40 ? MICROLABEL_IMPORTED_BY_HEAD : label_counter >= 42 && label_counter <= 49 ? MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY); if (leveldir_current->imported_from == NULL && (label_state == MICROLABEL_IMPORTED_FROM_HEAD || label_state == MICROLABEL_IMPORTED_FROM)) label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ? MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY); DrawPreviewLevelLabelExt(label_state); } game_status = last_game_status; /* restore current game status */ } inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int sync_frame, int mask_mode) { int frame = getGraphicAnimationFrame(graphic, sync_frame); if (mask_mode == USE_MASKING) DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame); else DrawGraphicExt(dst_bitmap, x, y, graphic, frame); } inline void DrawGraphicAnimation(int x, int y, int graphic) { int lx = LEVELX(x), ly = LEVELY(y); if (!IN_SCR_FIELD(x, y)) return; DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, GfxFrame[lx][ly], NO_MASKING); MarkTileDirty(x, y); } void DrawLevelGraphicAnimation(int x, int y, int graphic) { DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); } void DrawLevelElementAnimation(int x, int y, int element) { int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); } inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic) { int sx = SCREENX(x), sy = SCREENY(y); if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy)) return; if (!IS_NEW_FRAME(GfxFrame[x][y], graphic)) return; DrawGraphicAnimation(sx, sy, graphic); #if 1 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y))) DrawLevelFieldCrumbled(x, y); #else if (GFX_CRUMBLED(Feld[x][y])) DrawLevelFieldCrumbled(x, y); #endif } void DrawLevelElementAnimationIfNeeded(int x, int y, int element) { int sx = SCREENX(x), sy = SCREENY(y); int graphic; if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy)) return; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (!IS_NEW_FRAME(GfxFrame[x][y], graphic)) return; DrawGraphicAnimation(sx, sy, graphic); if (GFX_CRUMBLED(element)) DrawLevelFieldCrumbled(x, y); } static int getPlayerGraphic(struct PlayerInfo *player, int move_dir) { if (player->use_murphy) { /* this works only because currently only one player can be "murphy" ... */ static int last_horizontal_dir = MV_LEFT; int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir); if (move_dir == MV_LEFT || move_dir == MV_RIGHT) last_horizontal_dir = move_dir; if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */ { int direction = (player->is_snapping ? move_dir : last_horizontal_dir); graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction); } return graphic; } else return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir); } static boolean equalGraphics(int graphic1, int graphic2) { struct GraphicInfo *g1 = &graphic_info[graphic1]; struct GraphicInfo *g2 = &graphic_info[graphic2]; return (g1->bitmap == g2->bitmap && g1->src_x == g2->src_x && g1->src_y == g2->src_y && g1->anim_frames == g2->anim_frames && g1->anim_delay == g2->anim_delay && g1->anim_mode == g2->anim_mode); } void DrawAllPlayers() { int i; for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) DrawPlayer(&stored_player[i]); } void DrawPlayerField(int x, int y) { if (!IS_PLAYER(x, y)) return; DrawPlayer(PLAYERINFO(x, y)); } #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1 void DrawPlayer(struct PlayerInfo *player) { int jx = player->jx; int jy = player->jy; int move_dir = player->MovDir; int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0); int last_jx = (player->is_moving ? jx - dx : jx); int last_jy = (player->is_moving ? jy - dy : jy); int next_jx = jx + dx; int next_jy = jy + dy; boolean player_is_moving = (player->MovPos ? TRUE : FALSE); boolean player_is_opaque = FALSE; int sx = SCREENX(jx), sy = SCREENY(jy); int sxx = 0, syy = 0; int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy]; int graphic; int action = ACTION_DEFAULT; int last_player_graphic = getPlayerGraphic(player, move_dir); int last_player_frame = player->Frame; int frame = 0; /* GfxElement[][] is set to the element the player is digging or collecting; remove also for off-screen player if the player is not moving anymore */ if (IN_LEV_FIELD(jx, jy) && !player_is_moving) GfxElement[jx][jy] = EL_UNDEFINED; if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy))) return; #if DEBUG if (!IN_LEV_FIELD(jx, jy)) { printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy); printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy); printf("DrawPlayerField(): This should never happen!\n"); return; } #endif if (element == EL_EXPLOSION) return; action = (player->is_pushing ? ACTION_PUSHING : player->is_digging ? ACTION_DIGGING : player->is_collecting ? ACTION_COLLECTING : player->is_moving ? ACTION_MOVING : player->is_snapping ? ACTION_SNAPPING : player->is_dropping ? ACTION_DROPPING : player->is_waiting ? player->action_waiting : ACTION_DEFAULT); if (player->is_waiting) move_dir = player->dir_waiting; InitPlayerGfxAnimation(player, action, move_dir); /* ----------------------------------------------------------------------- */ /* draw things in the field the player is leaving, if needed */ /* ----------------------------------------------------------------------- */ if (player->is_moving) { if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element)) { DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]); if (last_element == EL_DYNAMITE_ACTIVE || last_element == EL_EM_DYNAMITE_ACTIVE || last_element == EL_SP_DISK_RED_ACTIVE) DrawDynamite(last_jx, last_jy); else DrawLevelFieldThruMask(last_jx, last_jy); } else if (last_element == EL_DYNAMITE_ACTIVE || last_element == EL_EM_DYNAMITE_ACTIVE || last_element == EL_SP_DISK_RED_ACTIVE) DrawDynamite(last_jx, last_jy); #if 0 /* !!! this is not enough to prevent flickering of players which are moving next to each others without a free tile between them -- this can only be solved by drawing all players layer by layer (first the background, then the foreground etc.) !!! => TODO */ else if (!IS_PLAYER(last_jx, last_jy)) DrawLevelField(last_jx, last_jy); #else else DrawLevelField(last_jx, last_jy); #endif if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy))) DrawLevelElement(next_jx, next_jy, EL_EMPTY); } if (!IN_SCR_FIELD(sx, sy)) return; /* ----------------------------------------------------------------------- */ /* draw things behind the player, if needed */ /* ----------------------------------------------------------------------- */ if (Back[jx][jy]) DrawLevelElement(jx, jy, Back[jx][jy]); else if (IS_ACTIVE_BOMB(element)) DrawLevelElement(jx, jy, EL_EMPTY); else { if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED) { int old_element = GfxElement[jx][jy]; int old_graphic = el_act_dir2img(old_element, action, move_dir); int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame); if (GFX_CRUMBLED(old_element)) DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame); else DrawGraphic(sx, sy, old_graphic, frame); if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER) player_is_opaque = TRUE; } else { GfxElement[jx][jy] = EL_UNDEFINED; /* make sure that pushed elements are drawn with correct frame rate */ #if 1 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic)) GfxFrame[jx][jy] = player->StepFrame; #else if (player->is_pushing && player->is_moving) GfxFrame[jx][jy] = player->StepFrame; #endif DrawLevelField(jx, jy); } } #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT /* ----------------------------------------------------------------------- */ /* draw player himself */ /* ----------------------------------------------------------------------- */ graphic = getPlayerGraphic(player, move_dir); /* in the case of changed player action or direction, prevent the current animation frame from being restarted for identical animations */ if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic)) player->Frame = last_player_frame; frame = getGraphicAnimationFrame(graphic, player->Frame); if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } if (!setup.soft_scrolling && ScreenMovPos) sxx = syy = 0; if (player_is_opaque) DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING); else DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); if (SHIELD_ON(player)) { int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE : IMG_SHIELD_NORMAL_ACTIVE); int frame = getGraphicAnimationFrame(graphic, -1); DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); } #endif #if DRAW_PLAYER_OVER_PUSHED_ELEMENT if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } #endif /* ----------------------------------------------------------------------- */ /* draw things the player is pushing, if needed */ /* ----------------------------------------------------------------------- */ #if 0 printf("::: %d, %d [%d, %d] [%d]\n", player->is_pushing, player_is_moving, player->GfxAction, player->is_moving, player_is_moving); #endif #if 1 if (player->is_pushing && player->is_moving) { int px = SCREENX(jx), py = SCREENY(jy); int pxx = (TILEX - ABS(sxx)) * dx; int pyy = (TILEY - ABS(syy)) * dy; int gfx_frame = GfxFrame[jx][jy]; int graphic; int sync_frame; int frame; if (!IS_MOVING(jx, jy)) /* push movement already finished */ { element = Feld[next_jx][next_jy]; gfx_frame = GfxFrame[next_jx][next_jy]; } graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); #if 1 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame); frame = getGraphicAnimationFrame(graphic, sync_frame); #else frame = getGraphicAnimationFrame(graphic, player->StepFrame); #endif /* draw background element under pushed element (like the Sokoban field) */ #if 1 if (game.use_masked_pushing && IS_MOVING(jx, jy)) { /* this allows transparent pushing animation over non-black background */ if (Back[jx][jy]) DrawLevelElement(jx, jy, Back[jx][jy]); else DrawLevelElement(jx, jy, EL_EMPTY); if (Back[next_jx][next_jy]) DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]); else DrawLevelElement(next_jx, next_jy, EL_EMPTY); } else if (Back[next_jx][next_jy]) DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]); #else if (Back[next_jx][next_jy]) DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]); #endif #if 0 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n", jx, px, player->GfxPos, player->StepFrame, player->is_pushing, dx, sxx, pxx, IS_MOVING(jx, jy), graphic, frame, GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]); #endif #if 1 /* do not draw (EM style) pushing animation when pushing is finished */ /* (two-tile animations usually do not contain start and end frame) */ if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy)) DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]); else DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING); #else /* masked drawing is needed for EMC style (double) movement graphics */ /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */ DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING); #endif } #endif #if DRAW_PLAYER_OVER_PUSHED_ELEMENT /* ----------------------------------------------------------------------- */ /* draw player himself */ /* ----------------------------------------------------------------------- */ graphic = getPlayerGraphic(player, move_dir); /* in the case of changed player action or direction, prevent the current animation frame from being restarted for identical animations */ if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic)) player->Frame = last_player_frame; frame = getGraphicAnimationFrame(graphic, player->Frame); if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } if (!setup.soft_scrolling && ScreenMovPos) sxx = syy = 0; if (player_is_opaque) DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING); else DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); if (SHIELD_ON(player)) { int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE : IMG_SHIELD_NORMAL_ACTIVE); int frame = getGraphicAnimationFrame(graphic, -1); DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); } #endif /* ----------------------------------------------------------------------- */ /* draw things in front of player (active dynamite or dynabombs) */ /* ----------------------------------------------------------------------- */ if (IS_ACTIVE_BOMB(element)) { graphic = el2img(element); frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]); if (game.emulation == EMU_SUPAPLEX) DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame); else DrawGraphicThruMask(sx, sy, graphic, frame); } if (player_is_moving && last_element == EL_EXPLOSION) { int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ? GfxElement[last_jx][last_jy] : EL_EMPTY); int graphic = el_act2img(element, ACTION_EXPLODING); int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); int phase = ExplodePhase[last_jx][last_jy] - 1; int frame = getGraphicAnimationFrame(graphic, phase - delay); if (phase >= delay) DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame); } /* ----------------------------------------------------------------------- */ /* draw elements the player is just walking/passing through/under */ /* ----------------------------------------------------------------------- */ if (player_is_moving) { /* handle the field the player is leaving ... */ if (IS_ACCESSIBLE_INSIDE(last_element)) DrawLevelField(last_jx, last_jy); else if (IS_ACCESSIBLE_UNDER(last_element)) DrawLevelFieldThruMask(last_jx, last_jy); } /* do not redraw accessible elements if the player is just pushing them */ if (!player_is_moving || !player->is_pushing) { /* ... and the field the player is entering */ if (IS_ACCESSIBLE_INSIDE(element)) DrawLevelField(jx, jy); else if (IS_ACCESSIBLE_UNDER(element)) DrawLevelFieldThruMask(jx, jy); } MarkTileDirty(sx, sy); } /* ------------------------------------------------------------------------- */ void WaitForEventToContinue() { boolean still_wait = TRUE; /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); button_status = MB_RELEASED; #if 1 ClearEventQueue(); #endif while (still_wait) { if (PendingEvent()) { Event event; NextEvent(&event); switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_KEYPRESS: still_wait = FALSE; break; case EVENT_KEYRELEASE: ClearPlayerAction(); break; default: HandleOtherEvents(&event); break; } } else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED) { still_wait = FALSE; } DoAnimation(); /* don't eat all CPU time */ Delay(10); } } #define MAX_REQUEST_LINES 13 #define MAX_REQUEST_LINE_FONT1_LEN 7 #define MAX_REQUEST_LINE_FONT2_LEN 10 boolean Request(char *text, unsigned int req_state) { int mx, my, ty, result = -1; unsigned int old_door_state; int last_game_status = game_status; /* save current game status */ int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN; int font_nr = FONT_TEXT_2; boolean use_envelope_request = TRUE * 0; #if 0 int max_word_len = 0; #endif char *text_ptr; int i; #if 1 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN) { max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN; font_nr = FONT_TEXT_1; } #else for (text_ptr = text; *text_ptr; text_ptr++) { max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0); if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN) { max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN; #if 1 font_nr = FONT_TEXT_1; #else font_nr = FONT_LEVEL_NUMBER; #endif break; } } #endif if (game_status == GAME_MODE_PLAYING) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) BlitScreenToBitmap_EM(backbuffer); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) BlitScreenToBitmap_SP(backbuffer); } /* disable deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); SetMouseCursor(CURSOR_DEFAULT); #if defined(NETWORK_AVALIABLE) /* pause network game while waiting for request to answer */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_PausePlaying(); #endif old_door_state = GetDoorState(); /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); UnmapAllGadgets(); #if 1 if (old_door_state & DOOR_OPEN_1 && !use_envelope_request) #else if (old_door_state & DOOR_OPEN_1) #endif { CloseDoor(DOOR_CLOSE_1); /* save old door content */ BlitBitmap(bitmap_db_door, bitmap_db_door, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1); } #if 1 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); #endif SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); /* clear door drawing field */ DrawBackground(DX, DY, DXSIZE, DYSIZE); /* force DOOR font inside door area */ game_status = GAME_MODE_PSEUDO_DOOR; /* write text for request */ for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++) { char text_line[max_request_line_len + 1]; int tx, tl, tc = 0; if (!*text_ptr) break; for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++) { tc = *(text_ptr + tx); if (!tc || tc == ' ') break; } if (!tl) { text_ptr++; ty--; continue; } strncpy(text_line, text_ptr, tl); text_line[tl] = 0; DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2, DY + 8 + ty * (getFontHeight(font_nr) + 2), text_line, font_nr); text_ptr += tl + (tc == ' ' ? 1 : 0); } game_status = last_game_status; /* restore current game status */ #if 1 if (use_envelope_request) { /* !!! TMP !!! */ FreeToolButtons(); CreateToolButtons(); } #endif 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]); } else if (req_state & REQ_PLAYER) { MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]); } /* copy request gadgets to door backbuffer */ BlitBitmap(drawto, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); #if 1 if (use_envelope_request) { ShowEnvelopeDoor(text, ACTION_OPENING); for (i = 0; i < NUM_TOOL_BUTTONS; i++) { if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES || i == TOOL_CTRL_ID_NO)) || (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) || (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 && i == TOOL_CTRL_ID_PLAYER_2 && i == TOOL_CTRL_ID_PLAYER_3 && i == TOOL_CTRL_ID_PLAYER_4))) { int x = tool_gadget[i]->x + dDX; int y = tool_gadget[i]->y + dDY; ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END); } } } #endif #if 1 if (!use_envelope_request) OpenDoor(DOOR_OPEN_1); #else OpenDoor(DOOR_OPEN_1); #endif if (!(req_state & REQUEST_WAIT_FOR_INPUT)) { if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } return FALSE; } #if 1 if (game_status != GAME_MODE_MAIN && !use_envelope_request) InitAnimation(); #else if (game_status != GAME_MODE_MAIN) InitAnimation(); #endif button_status = MB_RELEASED; request_gadget_id = -1; SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_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; case TOOL_CTRL_ID_PLAYER_1: result = 1; break; case TOOL_CTRL_ID_PLAYER_2: result = 2; break; case TOOL_CTRL_ID_PLAYER_3: result = 3; break; case TOOL_CTRL_ID_PLAYER_4: result = 4; break; default: break; } break; } case EVENT_KEYPRESS: switch (GetEventKey((KeyEvent *)&event, TRUE)) { case KSYM_space: if (req_state & REQ_CONFIRM) result = 1; break; case KSYM_Return: result = 1; break; case KSYM_Escape: result = 0; break; default: break; } if (req_state & REQ_PLAYER) result = 0; break; case EVENT_KEYRELEASE: ClearPlayerAction(); break; default: HandleOtherEvents(&event); break; } } else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED) { int joy = AnyJoystick(); if (joy & JOY_BUTTON_1) result = 1; else if (joy & JOY_BUTTON_2) result = 0; } #if 1 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd) { HandleGameActions(); } else { DoAnimation(); if (!PendingEvent()) /* delay only if no pending events */ Delay(10); } BackToFront(); #else DoAnimation(); #if 1 if (!PendingEvent()) /* delay only if no pending events */ Delay(10); #else /* don't eat all CPU time */ Delay(10); #endif #endif } if (game_status != GAME_MODE_MAIN) StopAnimation(); UnmapToolButtons(); #if 1 if (use_envelope_request) ShowEnvelopeDoor(text, ACTION_CLOSING); #endif #if 1 if (!(req_state & REQ_STAY_OPEN) && !use_envelope_request) #else if (!(req_state & REQ_STAY_OPEN)) #endif { CloseDoor(DOOR_CLOSE_1); if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) || (req_state & REQ_REOPEN)) OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); } RemapAllGadgets(); if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } #if defined(NETWORK_AVALIABLE) /* continue network game after request */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_ContinuePlaying(); #endif /* restore deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); return result; } unsigned int OpenDoor(unsigned int door_state) { if (door_state & DOOR_COPY_BACK) { if (door_state & DOOR_OPEN_1) BlitBitmap(bitmap_db_door, bitmap_db_door, DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); if (door_state & DOOR_OPEN_2) BlitBitmap(bitmap_db_door, bitmap_db_door, DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2); door_state &= ~DOOR_COPY_BACK; } return MoveDoor(door_state); } unsigned int CloseDoor(unsigned int door_state) { unsigned int old_door_state = GetDoorState(); if (!(door_state & DOOR_NO_COPY_BACK)) { if (old_door_state & DOOR_OPEN_1) BlitBitmap(backbuffer, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); if (old_door_state & DOOR_OPEN_2) BlitBitmap(backbuffer, bitmap_db_door, VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2); door_state &= ~DOOR_NO_COPY_BACK; } return MoveDoor(door_state); } unsigned int GetDoorState() { return MoveDoor(DOOR_GET_STATE); } unsigned int SetDoorState(unsigned int door_state) { return MoveDoor(door_state | DOOR_SET_STATE); } unsigned int MoveDoor(unsigned int door_state) { static int door1 = DOOR_OPEN_1; static int door2 = DOOR_CLOSE_2; unsigned long door_delay = 0; unsigned long door_delay_value; int stepsize = 1; if (door_1.width < 0 || door_1.width > DXSIZE) door_1.width = DXSIZE; if (door_1.height < 0 || door_1.height > DYSIZE) door_1.height = DYSIZE; if (door_2.width < 0 || door_2.width > VXSIZE) door_2.width = VXSIZE; if (door_2.height < 0 || door_2.height > VYSIZE) door_2.height = VYSIZE; if (door_state == DOOR_GET_STATE) return (door1 | door2); if (door_state & DOOR_SET_STATE) { 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 (!(door_state & DOOR_FORCE_REDRAW)) { 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; } door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay : door_2.step_delay); if (setup.quick_doors) { stepsize = 20; /* must be chosen to always draw last frame */ door_delay_value = 0; } if (global.autoplay_leveldir) { door_state |= DOOR_NO_DELAY; door_state &= ~DOOR_CLOSE_ALL; } #if 1 if (game_status == GAME_MODE_EDITOR) door_state |= DOOR_NO_DELAY; #endif if (door_state & DOOR_ACTION) { boolean handle_door_1 = (door_state & DOOR_ACTION_1); boolean handle_door_2 = (door_state & DOOR_ACTION_2); boolean door_1_done = (!handle_door_1); boolean door_2_done = (!handle_door_2); boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL); boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL); int door_size_1 = (door_1_vertical ? door_1.height : door_1.width); int door_size_2 = (door_2_vertical ? door_2.height : door_2.width); int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE); int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE); int door_size = (handle_door_1 ? door_size_1 : door_size_2); int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2); int door_skip = max_door_size - door_size; int end = door_size; int start = ((door_state & DOOR_NO_DELAY) ? end : 0); int k; if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors) { /* opening door sound has priority over simultaneously closing door */ if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2)) PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE); else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2)) PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); } for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize) { int x = k; Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; GC gc = bitmap->stored_clip_gc; if (door_state & DOOR_ACTION_1) { int a = MIN(x * door_1.step_offset, end); int p = (door_state & DOOR_OPEN_1 ? end - a : a); int i = p + door_skip; if (door_1.anim_mode & ANIM_STATIC_PANEL) { BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); } else if (x <= a) { BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2, DXSIZE, DYSIZE - p / 2, DX, DY); ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2); } if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE) { int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1; int dst1_x = DX + DXSIZE - i, dst1_y = DY; int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1; int dst2_x = DX, dst2_y = DY; int width = i, height = DYSIZE; SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y); BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height, dst1_x, dst1_y); SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y); BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height, dst2_x, dst2_y); } else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE) { int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1; int dst1_x = DX, dst1_y = DY + DYSIZE - i; int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i; int dst2_x = DX, dst2_y = DY; int width = DXSIZE, height = i; SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y); BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height, dst1_x, dst1_y); SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y); BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height, dst2_x, dst2_y); } else if (x <= DXSIZE) /* ANIM_DEFAULT */ { int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0); SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i, DY + 140 + j); SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j)); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY); BlitBitmapMasked(bitmap, drawto, DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63, DX, DY + 77 - j); BlitBitmapMasked(bitmap, drawto, DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77, DX, DY + 203 - j); SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63, DX + DXSIZE - i, DY + 77 + j); BlitBitmapMasked(bitmap, drawto, DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j, DX + DXSIZE - i, DY + 203 + j); } redraw_mask |= REDRAW_DOOR_1; door_1_done = (a == end); } if (door_state & DOOR_ACTION_2) { int a = MIN(x * door_2.step_offset, door_size); int p = (door_state & DOOR_OPEN_2 ? door_size - a : a); int i = p + door_skip; if (door_2.anim_mode & ANIM_STATIC_PANEL) { BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE, VX, VY); } else if (x <= VYSIZE) { BlitBitmap(bitmap_db_door, drawto, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2, VXSIZE, VYSIZE - p / 2, VX, VY); ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2); } if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE) { int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2; int dst1_x = VX + VXSIZE - i, dst1_y = VY; int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2; int dst2_x = VX, dst2_y = VY; int width = i, height = VYSIZE; SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y); BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height, dst1_x, dst1_y); SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y); BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height, dst2_x, dst2_y); } else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE) { int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2; int dst1_x = VX, dst1_y = VY + VYSIZE - i; int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i; int dst2_x = VX, dst2_y = VY; int width = VXSIZE, height = i; SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y); BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height, dst1_x, dst1_y); SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y); BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height, dst2_x, dst2_y); } else if (x <= VXSIZE) /* ANIM_DEFAULT */ { int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0); SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2); BlitBitmapMasked(bitmap, drawto, VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE - i, VY + j); SetClipOrigin(bitmap, gc, VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j)); BlitBitmapMasked(bitmap, drawto, VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY); BlitBitmapMasked(bitmap, drawto, VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j); SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2); BlitBitmapMasked(bitmap, drawto, VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j, VX + VXSIZE - i, VY + VYSIZE / 2 + j); } redraw_mask |= REDRAW_DOOR_2; door_2_done = (a == VXSIZE); } if (!(door_state & DOOR_NO_DELAY)) { BackToFront(); if (game_status == GAME_MODE_MAIN) DoAnimation(); WaitUntilDelayReached(&door_delay, door_delay_value); } } } 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); } void DrawSpecialEditorDoor() { /* draw bigger toolbox window */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8, EX - 4, EY - 12); BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4, EX - 6, EY - 4); redraw_mask |= REDRAW_ALL; } void UndrawSpecialEditorDoor() { /* draw normal tape recorder window */ BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12, EX - 6, EY - 12); redraw_mask |= REDRAW_ALL; } /* ---------- 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 #define TOOL_BUTTON_PLAYER_XSIZE 30 #define TOOL_BUTTON_PLAYER_YSIZE 30 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2) #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2) #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \ + 0 * TOOL_BUTTON_PLAYER_XSIZE) #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \ + 1 * TOOL_BUTTON_PLAYER_XSIZE) #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \ + 0 * TOOL_BUTTON_PLAYER_XSIZE) #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \ + 1 * TOOL_BUTTON_PLAYER_XSIZE) #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \ + 0 * TOOL_BUTTON_PLAYER_YSIZE) #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \ + 0 * TOOL_BUTTON_PLAYER_YSIZE) #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \ + 1 * TOOL_BUTTON_PLAYER_YSIZE) #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \ + 1 * TOOL_BUTTON_PLAYER_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" }, { TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS, TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS, TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE, TOOL_CTRL_ID_PLAYER_1, "player 1" }, { TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS, TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS, TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE, TOOL_CTRL_ID_PLAYER_2, "player 2" }, { TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS, TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS, TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE, TOOL_CTRL_ID_PLAYER_3, "player 3" }, { TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS, TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS, TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE, TOOL_CTRL_ID_PLAYER_4, "player 4" } }; void CreateToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; Bitmap *deco_bitmap = None; int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0; struct GadgetInfo *gi; unsigned long event_mask; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y; int id = i; event_mask = GD_EVENT_RELEASED; gd_xoffset = toolbutton_info[i].xpos; gd_yoffset = toolbutton_info[i].ypos; gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset; gd_y = DOOR_GFX_PAGEY1 + gd_yoffset; if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4) { int player_nr = id - TOOL_CTRL_ID_PLAYER_1; getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), &deco_bitmap, &deco_x, &deco_y); deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2; deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, toolbutton_info[i].infotext, GDI_X, DX + toolbutton_info[i].x, GDI_Y, DY + toolbutton_info[i].y, GDI_WIDTH, toolbutton_info[i].width, GDI_HEIGHT, toolbutton_info[i].height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_DECORATION_POSITION, deco_xpos, deco_ypos, GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY, GDI_DECORATION_SHIFTING, 1, 1, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleToolButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); tool_gadget[id] = gi; } } void FreeToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) FreeGadget(tool_gadget[i]); } static void UnmapToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) UnmapGadget(tool_gadget[i]); } static void HandleToolButtons(struct GadgetInfo *gi) { request_gadget_id = gi->custom_id; } static struct Mapping_EM_to_RND_object { int element_em; boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */ boolean is_backside; /* backside of moving element */ int element_rnd; int action; int direction; } em_object_mapping_list[] = { { Xblank, TRUE, FALSE, EL_EMPTY, -1, -1 }, { Yacid_splash_eB, FALSE, FALSE, EL_ACID_SPLASH_RIGHT, -1, -1 }, { Yacid_splash_wB, FALSE, FALSE, EL_ACID_SPLASH_LEFT, -1, -1 }, #ifdef EM_ENGINE_BAD_ROLL { Xstone_force_e, FALSE, FALSE, EL_ROCK, -1, MV_BIT_RIGHT }, { Xstone_force_w, FALSE, FALSE, EL_ROCK, -1, MV_BIT_LEFT }, { Xnut_force_e, FALSE, FALSE, EL_NUT, -1, MV_BIT_RIGHT }, { Xnut_force_w, FALSE, FALSE, EL_NUT, -1, MV_BIT_LEFT }, { Xspring_force_e, FALSE, FALSE, EL_SPRING, -1, MV_BIT_RIGHT }, { Xspring_force_w, FALSE, FALSE, EL_SPRING, -1, MV_BIT_LEFT }, { Xemerald_force_e, FALSE, FALSE, EL_EMERALD, -1, MV_BIT_RIGHT }, { Xemerald_force_w, FALSE, FALSE, EL_EMERALD, -1, MV_BIT_LEFT }, { Xdiamond_force_e, FALSE, FALSE, EL_DIAMOND, -1, MV_BIT_RIGHT }, { Xdiamond_force_w, FALSE, FALSE, EL_DIAMOND, -1, MV_BIT_LEFT }, { Xbomb_force_e, FALSE, FALSE, EL_BOMB, -1, MV_BIT_RIGHT }, { Xbomb_force_w, FALSE, FALSE, EL_BOMB, -1, MV_BIT_LEFT }, #endif /* EM_ENGINE_BAD_ROLL */ { Xstone, TRUE, FALSE, EL_ROCK, -1, -1 }, { Xstone_pause, FALSE, FALSE, EL_ROCK, -1, -1 }, { Xstone_fall, FALSE, FALSE, EL_ROCK, -1, -1 }, { Ystone_s, FALSE, FALSE, EL_ROCK, ACTION_FALLING, -1 }, { Ystone_sB, FALSE, TRUE, EL_ROCK, ACTION_FALLING, -1 }, { Ystone_e, FALSE, FALSE, EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT }, { Ystone_eB, FALSE, TRUE, EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT }, { Ystone_w, FALSE, FALSE, EL_ROCK, ACTION_MOVING, MV_BIT_LEFT }, { Ystone_wB, FALSE, TRUE, EL_ROCK, ACTION_MOVING, MV_BIT_LEFT }, { Xnut, TRUE, FALSE, EL_NUT, -1, -1 }, { Xnut_pause, FALSE, FALSE, EL_NUT, -1, -1 }, { Xnut_fall, FALSE, FALSE, EL_NUT, -1, -1 }, { Ynut_s, FALSE, FALSE, EL_NUT, ACTION_FALLING, -1 }, { Ynut_sB, FALSE, TRUE, EL_NUT, ACTION_FALLING, -1 }, { Ynut_e, FALSE, FALSE, EL_NUT, ACTION_MOVING, MV_BIT_RIGHT }, { Ynut_eB, FALSE, TRUE, EL_NUT, ACTION_MOVING, MV_BIT_RIGHT }, { Ynut_w, FALSE, FALSE, EL_NUT, ACTION_MOVING, MV_BIT_LEFT }, { Ynut_wB, FALSE, TRUE, EL_NUT, ACTION_MOVING, MV_BIT_LEFT }, { Xbug_n, TRUE, FALSE, EL_BUG_UP, -1, -1 }, { Xbug_e, TRUE, FALSE, EL_BUG_RIGHT, -1, -1 }, { Xbug_s, TRUE, FALSE, EL_BUG_DOWN, -1, -1 }, { Xbug_w, TRUE, FALSE, EL_BUG_LEFT, -1, -1 }, { Xbug_gon, FALSE, FALSE, EL_BUG_UP, -1, -1 }, { Xbug_goe, FALSE, FALSE, EL_BUG_RIGHT, -1, -1 }, { Xbug_gos, FALSE, FALSE, EL_BUG_DOWN, -1, -1 }, { Xbug_gow, FALSE, FALSE, EL_BUG_LEFT, -1, -1 }, { Ybug_n, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_UP }, { Ybug_nB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_UP }, { Ybug_e, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_RIGHT }, { Ybug_eB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_RIGHT }, { Ybug_s, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_DOWN }, { Ybug_sB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_DOWN }, { Ybug_w, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_LEFT }, { Ybug_wB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_LEFT }, { Ybug_w_n, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP }, { Ybug_n_e, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT }, { Ybug_e_s, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN }, { Ybug_s_w, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT }, { Ybug_e_n, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP }, { Ybug_s_e, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT }, { Ybug_w_s, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN }, { Ybug_n_w, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT }, { Ybug_stone, FALSE, FALSE, EL_BUG, ACTION_SMASHED_BY_ROCK, -1 }, { Ybug_spring, FALSE, FALSE, EL_BUG, ACTION_SMASHED_BY_SPRING, -1 }, { Xtank_n, TRUE, FALSE, EL_SPACESHIP_UP, -1, -1 }, { Xtank_e, TRUE, FALSE, EL_SPACESHIP_RIGHT, -1, -1 }, { Xtank_s, TRUE, FALSE, EL_SPACESHIP_DOWN, -1, -1 }, { Xtank_w, TRUE, FALSE, EL_SPACESHIP_LEFT, -1, -1 }, { Xtank_gon, FALSE, FALSE, EL_SPACESHIP_UP, -1, -1 }, { Xtank_goe, FALSE, FALSE, EL_SPACESHIP_RIGHT, -1, -1 }, { Xtank_gos, FALSE, FALSE, EL_SPACESHIP_DOWN, -1, -1 }, { Xtank_gow, FALSE, FALSE, EL_SPACESHIP_LEFT, -1, -1 }, { Ytank_n, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP }, { Ytank_nB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP }, { Ytank_e, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT }, { Ytank_eB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT }, { Ytank_s, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN }, { Ytank_sB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN }, { Ytank_w, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT }, { Ytank_wB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT }, { Ytank_w_n, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP }, { Ytank_n_e, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT }, { Ytank_e_s, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN }, { Ytank_s_w, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT }, { Ytank_e_n, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP }, { Ytank_s_e, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT }, { Ytank_w_s, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN }, { Ytank_n_w, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT }, { Ytank_stone, FALSE, FALSE, EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1 }, { Ytank_spring, FALSE, FALSE, EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1 }, { Xandroid, TRUE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, -1 }, { Xandroid_1_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP }, { Xandroid_2_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP }, { Xandroid_1_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT }, { Xandroid_2_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT }, { Xandroid_1_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT }, { Xandroid_2_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT }, { Xandroid_1_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN }, { Xandroid_2_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN }, { Yandroid_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP }, { Yandroid_nB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP }, { Yandroid_ne, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT }, { Yandroid_neB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT }, { Yandroid_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT }, { Yandroid_eB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT }, { Yandroid_se, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT }, { Yandroid_seB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT }, { Yandroid_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN }, { Yandroid_sB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN }, { Yandroid_sw, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT }, { Yandroid_swB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT }, { Yandroid_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT }, { Yandroid_wB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT }, { Yandroid_nw, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT }, { Yandroid_nwB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT }, { Xspring, TRUE, FALSE, EL_SPRING, -1, -1 }, { Xspring_pause, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_e, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_w, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_fall, FALSE, FALSE, EL_SPRING, -1, -1 }, { Yspring_s, FALSE, FALSE, EL_SPRING, ACTION_FALLING, -1 }, { Yspring_sB, FALSE, TRUE, EL_SPRING, ACTION_FALLING, -1 }, { Yspring_e, FALSE, FALSE, EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT }, { Yspring_eB, FALSE, TRUE, EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT }, { Yspring_w, FALSE, FALSE, EL_SPRING, ACTION_MOVING, MV_BIT_LEFT }, { Yspring_wB, FALSE, TRUE, EL_SPRING, ACTION_MOVING, MV_BIT_LEFT }, { Yspring_kill_e, FALSE, FALSE, EL_SPRING, ACTION_EATING, MV_BIT_RIGHT }, { Yspring_kill_eB, FALSE, TRUE, EL_SPRING, ACTION_EATING, MV_BIT_RIGHT }, { Yspring_kill_w, FALSE, FALSE, EL_SPRING, ACTION_EATING, MV_BIT_LEFT }, { Yspring_kill_wB, FALSE, TRUE, EL_SPRING, ACTION_EATING, MV_BIT_LEFT }, { Xeater_n, TRUE, FALSE, EL_YAMYAM_UP, -1, -1 }, { Xeater_e, TRUE, FALSE, EL_YAMYAM_RIGHT, -1, -1 }, { Xeater_w, TRUE, FALSE, EL_YAMYAM_LEFT, -1, -1 }, { Xeater_s, TRUE, FALSE, EL_YAMYAM_DOWN, -1, -1 }, { Yeater_n, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_UP }, { Yeater_nB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_UP }, { Yeater_e, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT }, { Yeater_eB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT }, { Yeater_s, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN }, { Yeater_sB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN }, { Yeater_w, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT }, { Yeater_wB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT }, { Yeater_stone, FALSE, FALSE, EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1 }, { Yeater_spring, FALSE, FALSE, EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1 }, { Xalien, TRUE, FALSE, EL_ROBOT, -1, -1 }, { Xalien_pause, FALSE, FALSE, EL_ROBOT, -1, -1 }, { Yalien_n, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_UP }, { Yalien_nB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_UP }, { Yalien_e, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT }, { Yalien_eB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT }, { Yalien_s, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN }, { Yalien_sB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN }, { Yalien_w, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT }, { Yalien_wB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT }, { Yalien_stone, FALSE, FALSE, EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1 }, { Yalien_spring, FALSE, FALSE, EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1 }, { Xemerald, TRUE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_pause, FALSE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_fall, FALSE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_shine, FALSE, FALSE, EL_EMERALD, ACTION_TWINKLING, -1 }, { Yemerald_s, FALSE, FALSE, EL_EMERALD, ACTION_FALLING, -1 }, { Yemerald_sB, FALSE, TRUE, EL_EMERALD, ACTION_FALLING, -1 }, { Yemerald_e, FALSE, FALSE, EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT }, { Yemerald_eB, FALSE, TRUE, EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT }, { Yemerald_w, FALSE, FALSE, EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT }, { Yemerald_wB, FALSE, TRUE, EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT }, { Yemerald_eat, FALSE, FALSE, EL_EMERALD, ACTION_COLLECTING, -1 }, { Yemerald_stone, FALSE, FALSE, EL_NUT, ACTION_BREAKING, -1 }, { Xdiamond, TRUE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_pause, FALSE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_fall, FALSE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_shine, FALSE, FALSE, EL_DIAMOND, ACTION_TWINKLING, -1 }, { Ydiamond_s, FALSE, FALSE, EL_DIAMOND, ACTION_FALLING, -1 }, { Ydiamond_sB, FALSE, TRUE, EL_DIAMOND, ACTION_FALLING, -1 }, { Ydiamond_e, FALSE, FALSE, EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT }, { Ydiamond_eB, FALSE, TRUE, EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT }, { Ydiamond_w, FALSE, FALSE, EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT }, { Ydiamond_wB, FALSE, TRUE, EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT }, { Ydiamond_eat, FALSE, FALSE, EL_DIAMOND, ACTION_COLLECTING, -1 }, { Ydiamond_stone, FALSE, FALSE, EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1 }, { Xdrip_fall, TRUE, FALSE, EL_AMOEBA_DROP, -1, -1 }, { Xdrip_stretch, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xdrip_stretchB, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xdrip_eat, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_GROWING, -1 }, { Ydrip_s1, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s1B, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s2, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s2B, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xbomb, TRUE, FALSE, EL_BOMB, -1, -1 }, { Xbomb_pause, FALSE, FALSE, EL_BOMB, -1, -1 }, { Xbomb_fall, FALSE, FALSE, EL_BOMB, -1, -1 }, { Ybomb_s, FALSE, FALSE, EL_BOMB, ACTION_FALLING, -1 }, { Ybomb_sB, FALSE, TRUE, EL_BOMB, ACTION_FALLING, -1 }, { Ybomb_e, FALSE, FALSE, EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT }, { Ybomb_eB, FALSE, TRUE, EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT }, { Ybomb_w, FALSE, FALSE, EL_BOMB, ACTION_MOVING, MV_BIT_LEFT }, { Ybomb_wB, FALSE, TRUE, EL_BOMB, ACTION_MOVING, MV_BIT_LEFT }, { Ybomb_eat, FALSE, FALSE, EL_BOMB, ACTION_ACTIVATING, -1 }, { Xballoon, TRUE, FALSE, EL_BALLOON, -1, -1 }, { Yballoon_n, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_UP }, { Yballoon_nB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_UP }, { Yballoon_e, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT }, { Yballoon_eB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT }, { Yballoon_s, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN }, { Yballoon_sB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN }, { Yballoon_w, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT }, { Yballoon_wB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT }, { Xgrass, TRUE, FALSE, EL_EMC_GRASS, -1, -1 }, { Ygrass_nB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP }, { Ygrass_eB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT }, { Ygrass_sB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN }, { Ygrass_wB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT }, { Xdirt, TRUE, FALSE, EL_SAND, -1, -1 }, { Ydirt_nB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_UP }, { Ydirt_eB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT }, { Ydirt_sB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_DOWN }, { Ydirt_wB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_LEFT }, { Xacid_ne, TRUE, FALSE, EL_ACID_POOL_TOPRIGHT, -1, -1 }, { Xacid_se, TRUE, FALSE, EL_ACID_POOL_BOTTOMRIGHT, -1, -1 }, { Xacid_s, TRUE, FALSE, EL_ACID_POOL_BOTTOM, -1, -1 }, { Xacid_sw, TRUE, FALSE, EL_ACID_POOL_BOTTOMLEFT, -1, -1 }, { Xacid_nw, TRUE, FALSE, EL_ACID_POOL_TOPLEFT, -1, -1 }, { Xacid_1, TRUE, FALSE, EL_ACID, -1, -1 }, { Xacid_2, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_3, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_4, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_5, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_6, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_7, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_8, FALSE, FALSE, EL_ACID, -1, -1 }, { Xball_1, TRUE, FALSE, EL_EMC_MAGIC_BALL, -1, -1 }, { Xball_1B, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Xball_2, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Xball_2B, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Yball_eat, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1 }, { Ykey_1_eat, FALSE, FALSE, EL_EM_KEY_1, ACTION_COLLECTING, -1 }, { Ykey_2_eat, FALSE, FALSE, EL_EM_KEY_2, ACTION_COLLECTING, -1 }, { Ykey_3_eat, FALSE, FALSE, EL_EM_KEY_3, ACTION_COLLECTING, -1 }, { Ykey_4_eat, FALSE, FALSE, EL_EM_KEY_4, ACTION_COLLECTING, -1 }, { Ykey_5_eat, FALSE, FALSE, EL_EMC_KEY_5, ACTION_COLLECTING, -1 }, { Ykey_6_eat, FALSE, FALSE, EL_EMC_KEY_6, ACTION_COLLECTING, -1 }, { Ykey_7_eat, FALSE, FALSE, EL_EMC_KEY_7, ACTION_COLLECTING, -1 }, { Ykey_8_eat, FALSE, FALSE, EL_EMC_KEY_8, ACTION_COLLECTING, -1 }, { Ylenses_eat, FALSE, FALSE, EL_EMC_LENSES, ACTION_COLLECTING, -1 }, { Ymagnify_eat, FALSE, FALSE, EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1 }, { Ygrass_eat, FALSE, FALSE, EL_EMC_GRASS, ACTION_SNAPPING, -1 }, { Ydirt_eat, FALSE, FALSE, EL_SAND, ACTION_SNAPPING, -1 }, { Xgrow_ns, TRUE, FALSE, EL_EXPANDABLE_WALL_VERTICAL, -1, -1 }, { Ygrow_ns_eat, FALSE, FALSE, EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1 }, { Xgrow_ew, TRUE, FALSE, EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1 }, { Ygrow_ew_eat, FALSE, FALSE, EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1 }, { Xwonderwall, TRUE, FALSE, EL_MAGIC_WALL, -1, -1 }, { XwonderwallB, FALSE, FALSE, EL_MAGIC_WALL, ACTION_ACTIVE, -1 }, { Xamoeba_1, TRUE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_2, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_3, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_4, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_5, TRUE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_6, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_7, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_8, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xdoor_1, TRUE, FALSE, EL_EM_GATE_1, -1, -1 }, { Xdoor_2, TRUE, FALSE, EL_EM_GATE_2, -1, -1 }, { Xdoor_3, TRUE, FALSE, EL_EM_GATE_3, -1, -1 }, { Xdoor_4, TRUE, FALSE, EL_EM_GATE_4, -1, -1 }, { Xdoor_5, TRUE, FALSE, EL_EMC_GATE_5, -1, -1 }, { Xdoor_6, TRUE, FALSE, EL_EMC_GATE_6, -1, -1 }, { Xdoor_7, TRUE, FALSE, EL_EMC_GATE_7, -1, -1 }, { Xdoor_8, TRUE, FALSE, EL_EMC_GATE_8, -1, -1 }, { Xkey_1, TRUE, FALSE, EL_EM_KEY_1, -1, -1 }, { Xkey_2, TRUE, FALSE, EL_EM_KEY_2, -1, -1 }, { Xkey_3, TRUE, FALSE, EL_EM_KEY_3, -1, -1 }, { Xkey_4, TRUE, FALSE, EL_EM_KEY_4, -1, -1 }, { Xkey_5, TRUE, FALSE, EL_EMC_KEY_5, -1, -1 }, { Xkey_6, TRUE, FALSE, EL_EMC_KEY_6, -1, -1 }, { Xkey_7, TRUE, FALSE, EL_EMC_KEY_7, -1, -1 }, { Xkey_8, TRUE, FALSE, EL_EMC_KEY_8, -1, -1 }, { Xwind_n, TRUE, FALSE, EL_BALLOON_SWITCH_UP, -1, -1 }, { Xwind_e, TRUE, FALSE, EL_BALLOON_SWITCH_RIGHT, -1, -1 }, { Xwind_s, TRUE, FALSE, EL_BALLOON_SWITCH_DOWN, -1, -1 }, { Xwind_w, TRUE, FALSE, EL_BALLOON_SWITCH_LEFT, -1, -1 }, { Xwind_nesw, TRUE, FALSE, EL_BALLOON_SWITCH_ANY, -1, -1 }, { Xwind_stop, TRUE, FALSE, EL_BALLOON_SWITCH_NONE, -1, -1 }, { Xexit, TRUE, FALSE, EL_EM_EXIT_CLOSED, -1, -1 }, { Xexit_1, TRUE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_2, FALSE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_3, FALSE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xdynamite, TRUE, FALSE, EL_EM_DYNAMITE, -1, -1 }, { Ydynamite_eat, FALSE, FALSE, EL_EM_DYNAMITE, ACTION_COLLECTING, -1 }, { Xdynamite_1, TRUE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_2, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_3, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_4, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xbumper, TRUE, FALSE, EL_EMC_SPRING_BUMPER, -1, -1 }, { XbumperB, FALSE, FALSE, EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1 }, { Xwheel, TRUE, FALSE, EL_ROBOT_WHEEL, -1, -1 }, { XwheelB, FALSE, FALSE, EL_ROBOT_WHEEL, ACTION_ACTIVE, -1 }, { Xswitch, TRUE, FALSE, EL_EMC_MAGIC_BALL_SWITCH, -1, -1 }, { XswitchB, FALSE, FALSE, EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1 }, { Xsand, TRUE, FALSE, EL_QUICKSAND_EMPTY, -1, -1 }, { Xsand_stone, TRUE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_stonein_1, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_2, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_3, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_4, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, #if 1 { Xsand_stonesand_1, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_2, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_3, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_4, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_quickout_1, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_quickout_2, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, #else { Xsand_stonesand_1, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_stonesand_2, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_stonesand_3, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_stonesand_4, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, #endif { Xsand_stoneout_1, FALSE, FALSE, EL_ROCK, ACTION_EMPTYING, -1 }, { Xsand_stoneout_2, FALSE, FALSE, EL_ROCK, ACTION_EMPTYING, -1 }, #if 1 { Xsand_sandstone_1, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_2, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_3, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_4, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, #else { Xsand_sandstone_1, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_sandstone_2, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_sandstone_3, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_sandstone_4, FALSE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, #endif { Xplant, TRUE, FALSE, EL_EMC_PLANT, -1, -1 }, { Yplant, FALSE, FALSE, EL_EMC_PLANT, -1, -1 }, { Xlenses, TRUE, FALSE, EL_EMC_LENSES, -1, -1 }, { Xmagnify, TRUE, FALSE, EL_EMC_MAGNIFIER, -1, -1 }, { Xdripper, TRUE, FALSE, EL_EMC_DRIPPER, -1, -1 }, { XdripperB, FALSE, FALSE, EL_EMC_DRIPPER, ACTION_ACTIVE, -1 }, { Xfake_blank, TRUE, FALSE, EL_INVISIBLE_WALL, -1, -1 }, { Xfake_blankB, FALSE, FALSE, EL_INVISIBLE_WALL, ACTION_ACTIVE, -1 }, { Xfake_grass, TRUE, FALSE, EL_EMC_FAKE_GRASS, -1, -1 }, { Xfake_grassB, FALSE, FALSE, EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1 }, { Xfake_door_1, TRUE, FALSE, EL_EM_GATE_1_GRAY, -1, -1 }, { Xfake_door_2, TRUE, FALSE, EL_EM_GATE_2_GRAY, -1, -1 }, { Xfake_door_3, TRUE, FALSE, EL_EM_GATE_3_GRAY, -1, -1 }, { Xfake_door_4, TRUE, FALSE, EL_EM_GATE_4_GRAY, -1, -1 }, { Xfake_door_5, TRUE, FALSE, EL_EMC_GATE_5_GRAY, -1, -1 }, { Xfake_door_6, TRUE, FALSE, EL_EMC_GATE_6_GRAY, -1, -1 }, { Xfake_door_7, TRUE, FALSE, EL_EMC_GATE_7_GRAY, -1, -1 }, { Xfake_door_8, TRUE, FALSE, EL_EMC_GATE_8_GRAY, -1, -1 }, { Xfake_acid_1, TRUE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_2, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_3, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_4, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_5, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_6, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_7, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_8, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xsteel_1, TRUE, FALSE, EL_STEELWALL, -1, -1 }, { Xsteel_2, TRUE, FALSE, EL_EMC_STEELWALL_2, -1, -1 }, { Xsteel_3, TRUE, FALSE, EL_EMC_STEELWALL_3, -1, -1 }, { Xsteel_4, TRUE, FALSE, EL_EMC_STEELWALL_4, -1, -1 }, { Xwall_1, TRUE, FALSE, EL_WALL, -1, -1 }, { Xwall_2, TRUE, FALSE, EL_EMC_WALL_14, -1, -1 }, { Xwall_3, TRUE, FALSE, EL_EMC_WALL_15, -1, -1 }, { Xwall_4, TRUE, FALSE, EL_EMC_WALL_16, -1, -1 }, { Xround_wall_1, TRUE, FALSE, EL_WALL_SLIPPERY, -1, -1 }, { Xround_wall_2, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_2, -1, -1 }, { Xround_wall_3, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_3, -1, -1 }, { Xround_wall_4, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_4, -1, -1 }, { Xdecor_1, TRUE, FALSE, EL_EMC_WALL_8, -1, -1 }, { Xdecor_2, TRUE, FALSE, EL_EMC_WALL_6, -1, -1 }, { Xdecor_3, TRUE, FALSE, EL_EMC_WALL_4, -1, -1 }, { Xdecor_4, TRUE, FALSE, EL_EMC_WALL_7, -1, -1 }, { Xdecor_5, TRUE, FALSE, EL_EMC_WALL_5, -1, -1 }, { Xdecor_6, TRUE, FALSE, EL_EMC_WALL_9, -1, -1 }, { Xdecor_7, TRUE, FALSE, EL_EMC_WALL_10, -1, -1 }, { Xdecor_8, TRUE, FALSE, EL_EMC_WALL_1, -1, -1 }, { Xdecor_9, TRUE, FALSE, EL_EMC_WALL_2, -1, -1 }, { Xdecor_10, TRUE, FALSE, EL_EMC_WALL_3, -1, -1 }, { Xdecor_11, TRUE, FALSE, EL_EMC_WALL_11, -1, -1 }, { Xdecor_12, TRUE, FALSE, EL_EMC_WALL_12, -1, -1 }, { Xalpha_0, TRUE, FALSE, EL_CHAR('0'), -1, -1 }, { Xalpha_1, TRUE, FALSE, EL_CHAR('1'), -1, -1 }, { Xalpha_2, TRUE, FALSE, EL_CHAR('2'), -1, -1 }, { Xalpha_3, TRUE, FALSE, EL_CHAR('3'), -1, -1 }, { Xalpha_4, TRUE, FALSE, EL_CHAR('4'), -1, -1 }, { Xalpha_5, TRUE, FALSE, EL_CHAR('5'), -1, -1 }, { Xalpha_6, TRUE, FALSE, EL_CHAR('6'), -1, -1 }, { Xalpha_7, TRUE, FALSE, EL_CHAR('7'), -1, -1 }, { Xalpha_8, TRUE, FALSE, EL_CHAR('8'), -1, -1 }, { Xalpha_9, TRUE, FALSE, EL_CHAR('9'), -1, -1 }, { Xalpha_excla, TRUE, FALSE, EL_CHAR('!'), -1, -1 }, { Xalpha_quote, TRUE, FALSE, EL_CHAR('"'), -1, -1 }, { Xalpha_comma, TRUE, FALSE, EL_CHAR(','), -1, -1 }, { Xalpha_minus, TRUE, FALSE, EL_CHAR('-'), -1, -1 }, { Xalpha_perio, TRUE, FALSE, EL_CHAR('.'), -1, -1 }, { Xalpha_colon, TRUE, FALSE, EL_CHAR(':'), -1, -1 }, { Xalpha_quest, TRUE, FALSE, EL_CHAR('?'), -1, -1 }, { Xalpha_a, TRUE, FALSE, EL_CHAR('A'), -1, -1 }, { Xalpha_b, TRUE, FALSE, EL_CHAR('B'), -1, -1 }, { Xalpha_c, TRUE, FALSE, EL_CHAR('C'), -1, -1 }, { Xalpha_d, TRUE, FALSE, EL_CHAR('D'), -1, -1 }, { Xalpha_e, TRUE, FALSE, EL_CHAR('E'), -1, -1 }, { Xalpha_f, TRUE, FALSE, EL_CHAR('F'), -1, -1 }, { Xalpha_g, TRUE, FALSE, EL_CHAR('G'), -1, -1 }, { Xalpha_h, TRUE, FALSE, EL_CHAR('H'), -1, -1 }, { Xalpha_i, TRUE, FALSE, EL_CHAR('I'), -1, -1 }, { Xalpha_j, TRUE, FALSE, EL_CHAR('J'), -1, -1 }, { Xalpha_k, TRUE, FALSE, EL_CHAR('K'), -1, -1 }, { Xalpha_l, TRUE, FALSE, EL_CHAR('L'), -1, -1 }, { Xalpha_m, TRUE, FALSE, EL_CHAR('M'), -1, -1 }, { Xalpha_n, TRUE, FALSE, EL_CHAR('N'), -1, -1 }, { Xalpha_o, TRUE, FALSE, EL_CHAR('O'), -1, -1 }, { Xalpha_p, TRUE, FALSE, EL_CHAR('P'), -1, -1 }, { Xalpha_q, TRUE, FALSE, EL_CHAR('Q'), -1, -1 }, { Xalpha_r, TRUE, FALSE, EL_CHAR('R'), -1, -1 }, { Xalpha_s, TRUE, FALSE, EL_CHAR('S'), -1, -1 }, { Xalpha_t, TRUE, FALSE, EL_CHAR('T'), -1, -1 }, { Xalpha_u, TRUE, FALSE, EL_CHAR('U'), -1, -1 }, { Xalpha_v, TRUE, FALSE, EL_CHAR('V'), -1, -1 }, { Xalpha_w, TRUE, FALSE, EL_CHAR('W'), -1, -1 }, { Xalpha_x, TRUE, FALSE, EL_CHAR('X'), -1, -1 }, { Xalpha_y, TRUE, FALSE, EL_CHAR('Y'), -1, -1 }, { Xalpha_z, TRUE, FALSE, EL_CHAR('Z'), -1, -1 }, { Xalpha_arrow_e, TRUE, FALSE, EL_CHAR('>'), -1, -1 }, { Xalpha_arrow_w, TRUE, FALSE, EL_CHAR('<'), -1, -1 }, { Xalpha_copyr, TRUE, FALSE, EL_CHAR('©'), -1, -1 }, { Xboom_bug, FALSE, FALSE, EL_BUG, ACTION_EXPLODING, -1 }, { Xboom_bomb, FALSE, FALSE, EL_BOMB, ACTION_EXPLODING, -1 }, { Xboom_android, FALSE, FALSE, EL_EMC_ANDROID, ACTION_OTHER, -1 }, { Xboom_1, FALSE, FALSE, EL_DEFAULT, ACTION_EXPLODING, -1 }, { Xboom_2, FALSE, FALSE, EL_DEFAULT, ACTION_EXPLODING, -1 }, { Znormal, FALSE, FALSE, EL_EMPTY, -1, -1 }, { Zdynamite, FALSE, FALSE, EL_EMPTY, -1, -1 }, { Zplayer, FALSE, FALSE, EL_EMPTY, -1, -1 }, { ZBORDER, FALSE, FALSE, EL_EMPTY, -1, -1 }, { -1, FALSE, FALSE, -1, -1, -1 } }; static struct Mapping_EM_to_RND_player { int action_em; int player_nr; int element_rnd; int action; int direction; } em_player_mapping_list[] = { { SPR_walk + 0, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_walk + 0, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_still, 0, EL_PLAYER_1, ACTION_DEFAULT, -1, }, { SPR_still, 1, EL_PLAYER_2, ACTION_DEFAULT, -1, }, { SPR_walk + 0, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_walk + 0, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_still, 2, EL_PLAYER_3, ACTION_DEFAULT, -1, }, { SPR_still, 3, EL_PLAYER_4, ACTION_DEFAULT, -1, }, { -1, -1, -1, -1, -1 } }; int map_element_RND_to_EM(int element_rnd) { static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS]; static boolean mapping_initialized = FALSE; if (!mapping_initialized) { int i; /* return "Xalpha_quest" for all undefined elements in mapping array */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) mapping_RND_to_EM[i] = Xalpha_quest; for (i = 0; em_object_mapping_list[i].element_em != -1; i++) if (em_object_mapping_list[i].is_rnd_to_em_mapping) mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] = em_object_mapping_list[i].element_em; mapping_initialized = TRUE; } if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS) return mapping_RND_to_EM[element_rnd]; Error(ERR_WARN, "invalid RND level element %d", element_rnd); return EL_UNKNOWN; } int map_element_EM_to_RND(int element_em) { static unsigned short mapping_EM_to_RND[TILE_MAX]; static boolean mapping_initialized = FALSE; if (!mapping_initialized) { int i; /* return "EL_UNKNOWN" for all undefined elements in mapping array */ for (i = 0; i < TILE_MAX; i++) mapping_EM_to_RND[i] = EL_UNKNOWN; for (i = 0; em_object_mapping_list[i].element_em != -1; i++) mapping_EM_to_RND[em_object_mapping_list[i].element_em] = em_object_mapping_list[i].element_rnd; mapping_initialized = TRUE; } if (element_em >= 0 && element_em < TILE_MAX) return mapping_EM_to_RND[element_em]; Error(ERR_WARN, "invalid EM level element %d", element_em); return EL_UNKNOWN; } void map_android_clone_elements_RND_to_EM(struct LevelInfo *level) { struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; int i, j; for (i = 0; i < TILE_MAX; i++) lev->android_array[i] = Xblank; for (i = 0; i < level->num_android_clone_elements; i++) { int element_rnd = level->android_clone_element[i]; int element_em = map_element_RND_to_EM(element_rnd); for (j = 0; em_object_mapping_list[j].element_em != -1; j++) if (em_object_mapping_list[j].element_rnd == element_rnd) lev->android_array[em_object_mapping_list[j].element_em] = element_em; } } void map_android_clone_elements_EM_to_RND(struct LevelInfo *level) { struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; int i, j; level->num_android_clone_elements = 0; for (i = 0; i < TILE_MAX; i++) { int element_em = lev->android_array[i]; int element_rnd; boolean element_found = FALSE; if (element_em == Xblank) continue; element_rnd = map_element_EM_to_RND(element_em); for (j = 0; j < level->num_android_clone_elements; j++) if (level->android_clone_element[j] == element_rnd) element_found = TRUE; if (!element_found) { level->android_clone_element[level->num_android_clone_elements++] = element_rnd; if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS) break; } } if (level->num_android_clone_elements == 0) { level->num_android_clone_elements = 1; level->android_clone_element[0] = EL_EMPTY; } } int map_direction_RND_to_EM(int direction) { return (direction == MV_UP ? 0 : direction == MV_RIGHT ? 1 : direction == MV_DOWN ? 2 : direction == MV_LEFT ? 3 : -1); } int map_direction_EM_to_RND(int direction) { return (direction == 0 ? MV_UP : direction == 1 ? MV_RIGHT : direction == 2 ? MV_DOWN : direction == 3 ? MV_LEFT : MV_NONE); } int map_element_RND_to_SP(int element_rnd) { int element_sp = 0x20; /* map unknown elements to yellow "hardware" */ if (element_rnd >= EL_SP_START && element_rnd <= EL_SP_END) element_sp = element_rnd - EL_SP_START; else if (element_rnd == EL_EMPTY_SPACE) element_sp = 0x00; else if (element_rnd == EL_INVISIBLE_WALL) element_sp = 0x28; return element_sp; } int map_element_SP_to_RND(int element_sp) { int element_rnd = EL_UNKNOWN; if (element_sp >= 0x00 && element_sp <= 0x27) element_rnd = EL_SP_START + element_sp; else if (element_sp == 0x28) element_rnd = EL_INVISIBLE_WALL; return element_rnd; } int map_action_SP_to_RND(int action_sp) { switch (action_sp) { case actActive: return ACTION_ACTIVE; case actImpact: return ACTION_IMPACT; case actExploding: return ACTION_EXPLODING; case actDigging: return ACTION_DIGGING; case actSnapping: return ACTION_SNAPPING; case actCollecting: return ACTION_COLLECTING; case actPassing: return ACTION_PASSING; case actPushing: return ACTION_PUSHING; case actDropping: return ACTION_DROPPING; default: return ACTION_DEFAULT; } } int get_next_element(int element) { switch (element) { case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL; case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY; case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL; case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY; case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL; case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE; case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL; case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE; case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL; case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE; case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET; default: return element; } } #if 0 int el_act_dir2img(int element, int action, int direction) { element = GFX_ELEMENT(element); if (direction == MV_NONE) return element_info[element].graphic[action]; direction = MV_DIR_TO_BIT(direction); return element_info[element].direction_graphic[action][direction]; } #else int el_act_dir2img(int element, int action, int direction) { element = GFX_ELEMENT(element); direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */ /* direction_graphic[][] == graphic[] for undefined direction graphics */ return element_info[element].direction_graphic[action][direction]; } #endif #if 0 static int el_act_dir2crm(int element, int action, int direction) { element = GFX_ELEMENT(element); if (direction == MV_NONE) return element_info[element].crumbled[action]; direction = MV_DIR_TO_BIT(direction); return element_info[element].direction_crumbled[action][direction]; } #else static int el_act_dir2crm(int element, int action, int direction) { element = GFX_ELEMENT(element); direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */ /* direction_graphic[][] == graphic[] for undefined direction graphics */ return element_info[element].direction_crumbled[action][direction]; } #endif int el_act2img(int element, int action) { element = GFX_ELEMENT(element); return element_info[element].graphic[action]; } int el_act2crm(int element, int action) { element = GFX_ELEMENT(element); return element_info[element].crumbled[action]; } int el_dir2img(int element, int direction) { element = GFX_ELEMENT(element); return el_act_dir2img(element, ACTION_DEFAULT, direction); } int el2baseimg(int element) { return element_info[element].graphic[ACTION_DEFAULT]; } int el2img(int element) { element = GFX_ELEMENT(element); return element_info[element].graphic[ACTION_DEFAULT]; } int el2edimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR]; } int el2preimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW]; } int el2panelimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL]; } int font2baseimg(int font_nr) { return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT]; } int getBeltNrFromBeltElement(int element) { return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 : element < EL_CONVEYOR_BELT_3_LEFT ? 1 : element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3); } int getBeltNrFromBeltActiveElement(int element) { return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 : element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 : element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3); } int getBeltNrFromBeltSwitchElement(int element) { return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 : element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 : element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3); } int getBeltDirNrFromBeltElement(int element) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; int belt_nr = getBeltNrFromBeltElement(element); int belt_dir_nr = element - belt_base_element[belt_nr]; return (belt_dir_nr % 3); } int getBeltDirNrFromBeltSwitchElement(int element) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; int belt_nr = getBeltNrFromBeltSwitchElement(element); int belt_dir_nr = element - belt_base_element[belt_nr]; return (belt_dir_nr % 3); } int getBeltDirFromBeltElement(int element) { static int belt_move_dir[3] = { MV_LEFT, MV_NONE, MV_RIGHT }; int belt_dir_nr = getBeltDirNrFromBeltElement(element); return belt_move_dir[belt_dir_nr]; } int getBeltDirFromBeltSwitchElement(int element) { static int belt_move_dir[3] = { MV_LEFT, MV_NONE, MV_RIGHT }; int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element); return belt_move_dir[belt_dir_nr]; } int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; return belt_base_element[belt_nr] + belt_dir_nr; } int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir) { int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1); return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr); } int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; return belt_base_element[belt_nr] + belt_dir_nr; } int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir) { int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1); return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr); } int getNumActivePlayers_EM() { int num_players = 0; int i; if (!tape.playing) return -1; for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) num_players++; return num_players; } int getGameFrameDelay_EM(int native_em_game_frame_delay) { int game_frame_delay_value; game_frame_delay_value = (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay : GameFrameDelay); if (tape.playing && tape.warp_forward && !tape.pausing) game_frame_delay_value = 0; return game_frame_delay_value; } unsigned int InitRND(long seed) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return InitEngineRandom_EM(seed); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return InitEngineRandom_SP(seed); else return InitEngineRandom_RND(seed); } #if 1 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX]; static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX]; #endif inline static int get_effective_element_EM(int tile, int frame_em) { int element = object_mapping[tile].element_rnd; int action = object_mapping[tile].action; boolean is_backside = object_mapping[tile].is_backside; boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); if (frame_em < 7) { switch (tile) { case Yacid_splash_eB: case Yacid_splash_wB: return (frame_em > 5 ? EL_EMPTY : element); #if 0 case Ydiamond_stone: // if (!game.use_native_emc_graphics_engine) return EL_ROCK; #endif default: return element; } } else /* frame_em == 7 */ { switch (tile) { case Yacid_splash_eB: case Yacid_splash_wB: return EL_EMPTY; case Yemerald_stone: return EL_EMERALD; case Ydiamond_stone: return EL_ROCK; case Xdrip_stretch: case Xdrip_stretchB: case Ydrip_s1: case Ydrip_s1B: case Xball_1B: case Xball_2: case Xball_2B: case Yball_eat: case Ykey_1_eat: case Ykey_2_eat: case Ykey_3_eat: case Ykey_4_eat: case Ykey_5_eat: case Ykey_6_eat: case Ykey_7_eat: case Ykey_8_eat: case Ylenses_eat: case Ymagnify_eat: case Ygrass_eat: case Ydirt_eat: case Xsand_stonein_1: case Xsand_stonein_2: case Xsand_stonein_3: case Xsand_stonein_4: return element; default: return (is_backside || action_removing ? EL_EMPTY : element); } } } inline static boolean check_linear_animation_EM(int tile) { switch (tile) { case Xsand_stonesand_1: case Xsand_stonesand_quickout_1: case Xsand_sandstone_1: case Xsand_stonein_1: case Xsand_stoneout_1: case Xboom_1: case Xdynamite_1: case Ybug_w_n: case Ybug_n_e: case Ybug_e_s: case Ybug_s_w: case Ybug_e_n: case Ybug_s_e: case Ybug_w_s: case Ybug_n_w: case Ytank_w_n: case Ytank_n_e: case Ytank_e_s: case Ytank_s_w: case Ytank_e_n: case Ytank_s_e: case Ytank_w_s: case Ytank_n_w: #if 1 case Yacid_splash_eB: case Yacid_splash_wB: case Yemerald_stone: #endif return TRUE; } return FALSE; } inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em, boolean has_crumbled_graphics, int crumbled, int sync_frame) { /* if element can be crumbled, but certain action graphics are just empty space (like instantly snapping sand to empty space in 1 frame), do not treat these empty space graphics as crumbled graphics in EMC engine */ if (crumbled == IMG_EMPTY_SPACE) has_crumbled_graphics = FALSE; if (has_crumbled_graphics) { struct GraphicInfo *g_crumbled = &graphic_info[crumbled]; int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames, g_crumbled->anim_delay, g_crumbled->anim_mode, g_crumbled->anim_start_frame, sync_frame); getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap, &g_em->crumbled_src_x, &g_em->crumbled_src_y); g_em->crumbled_border_size = graphic_info[crumbled].border_size; g_em->has_crumbled_graphics = TRUE; } else { g_em->crumbled_bitmap = NULL; g_em->crumbled_src_x = 0; g_em->crumbled_src_y = 0; g_em->crumbled_border_size = 0; g_em->has_crumbled_graphics = FALSE; } } void ResetGfxAnimation_EM(int x, int y, int tile) { GfxFrame[x][y] = 0; } void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em, int tile, int frame_em, int x, int y) { int action = object_mapping[tile].action; #if 1 int direction = object_mapping[tile].direction; int effective_element = get_effective_element_EM(tile, frame_em); int graphic = (direction == MV_NONE ? el_act2img(effective_element, action) : el_act_dir2img(effective_element, action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; int sync_frame; #endif boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); boolean action_moving = (action == ACTION_FALLING || action == ACTION_MOVING || action == ACTION_PUSHING || action == ACTION_EATING || action == ACTION_FILLING || action == ACTION_EMPTYING); boolean action_falling = (action == ACTION_FALLING || action == ACTION_FILLING || action == ACTION_EMPTYING); /* special case: graphic uses "2nd movement tile" and has defined 7 frames for movement animation (or less) => use default graphic for last (8th) frame which ends the movement animation */ if (g->double_movement && g->anim_frames < 8 && frame_em == 7) { action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */ graphic = (direction == MV_NONE ? el_act2img(effective_element, action) : el_act_dir2img(effective_element, action, direction)); g = &graphic_info[graphic]; } #if 0 if (tile == Xsand_stonesand_1 || tile == Xsand_stonesand_2 || tile == Xsand_stonesand_3 || tile == Xsand_stonesand_4) printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile); #endif #if 1 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0) { GfxFrame[x][y] = 0; // printf("::: resetting... [%d]\n", tile); } #else if (action_removing || check_linear_animation_EM(tile)) { GfxFrame[x][y] = frame_em; // printf("::: resetting... [%d]\n", tile); } #endif else if (action_moving) { boolean is_backside = object_mapping[tile].is_backside; if (is_backside) { int direction = object_mapping[tile].direction; int move_dir = (action_falling ? MV_DOWN : direction); GfxFrame[x][y]++; #if 1 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */ if (g->double_movement && frame_em == 0) { GfxFrame[x][y] = 0; // printf("::: resetting... [%d]\n", tile); } #endif if (move_dir == MV_LEFT) GfxFrame[x - 1][y] = GfxFrame[x][y]; else if (move_dir == MV_RIGHT) GfxFrame[x + 1][y] = GfxFrame[x][y]; else if (move_dir == MV_UP) GfxFrame[x][y - 1] = GfxFrame[x][y]; else if (move_dir == MV_DOWN) GfxFrame[x][y + 1] = GfxFrame[x][y]; } } else { GfxFrame[x][y]++; /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */ if (tile == Xsand_stonesand_quickout_1 || tile == Xsand_stonesand_quickout_2) GfxFrame[x][y]++; } #if 0 if (tile == Xsand_stonesand_1 || tile == Xsand_stonesand_2 || tile == Xsand_stonesand_3 || tile == Xsand_stonesand_4) printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile); #endif #if 1 if (graphic_info[graphic].anim_global_sync) sync_frame = FrameCounter; else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY)) sync_frame = GfxFrame[x][y]; else sync_frame = 0; /* playfield border (pseudo steel) */ SetRandomAnimationValue(x, y); int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); g_em->unique_identifier = (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height; #endif } void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em, int tile, int frame_em, int x, int y) { int action = object_mapping[tile].action; int direction = object_mapping[tile].direction; boolean is_backside = object_mapping[tile].is_backside; int effective_element = get_effective_element_EM(tile, frame_em); #if 1 int effective_action = action; #else int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT); #endif int graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); int crumbled = (direction == MV_NONE ? el_act2crm(effective_element, effective_action) : el_act_dir2crm(effective_element, effective_action, direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; #if 0 struct GraphicInfo *g_crumbled = &graphic_info[crumbled]; #endif int sync_frame; /* special case: graphic uses "2nd movement tile" and has defined 7 frames for movement animation (or less) => use default graphic for last (8th) frame which ends the movement animation */ if (g->double_movement && g->anim_frames < 8 && frame_em == 7) { effective_action = ACTION_DEFAULT; graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); crumbled = (direction == MV_NONE ? el_act2crm(effective_element, effective_action) : el_act_dir2crm(effective_element, effective_action, direction)); g = &graphic_info[graphic]; } #if 0 if (frame_em == 7) return; #endif #if 0 if (frame_em == 0) /* reset animation frame for certain elements */ { if (check_linear_animation_EM(tile)) GfxFrame[x][y] = 0; } #endif if (graphic_info[graphic].anim_global_sync) sync_frame = FrameCounter; else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY)) sync_frame = GfxFrame[x][y]; else sync_frame = 0; /* playfield border (pseudo steel) */ SetRandomAnimationValue(x, y); #if 0 int i = tile; int j = frame_em; int xxx_sync_frame = (i == Xdrip_stretch ? 7 : i == Xdrip_stretchB ? 7 : i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xacid_1 ? 0 : i == Xacid_2 ? 10 : i == Xacid_3 ? 20 : i == Xacid_4 ? 30 : i == Xacid_5 ? 40 : i == Xacid_6 ? 50 : i == Xacid_7 ? 60 : i == Xacid_8 ? 70 : i == Xfake_acid_1 ? 0 : i == Xfake_acid_2 ? 10 : i == Xfake_acid_3 ? 20 : i == Xfake_acid_4 ? 30 : i == Xfake_acid_5 ? 40 : i == Xfake_acid_6 ? 50 : i == Xfake_acid_7 ? 60 : i == Xfake_acid_8 ? 70 : i == Xball_2 ? 7 : i == Xball_2B ? j + 8 : i == Yball_eat ? j + 1 : i == Ykey_1_eat ? j + 1 : i == Ykey_2_eat ? j + 1 : i == Ykey_3_eat ? j + 1 : i == Ykey_4_eat ? j + 1 : i == Ykey_5_eat ? j + 1 : i == Ykey_6_eat ? j + 1 : i == Ykey_7_eat ? j + 1 : i == Ykey_8_eat ? j + 1 : i == Ylenses_eat ? j + 1 : i == Ymagnify_eat ? j + 1 : i == Ygrass_eat ? j + 1 : i == Ydirt_eat ? j + 1 : i == Xamoeba_1 ? 0 : i == Xamoeba_2 ? 1 : i == Xamoeba_3 ? 2 : i == Xamoeba_4 ? 3 : i == Xamoeba_5 ? 0 : i == Xamoeba_6 ? 1 : i == Xamoeba_7 ? 2 : i == Xamoeba_8 ? 3 : i == Xexit_2 ? j + 8 : i == Xexit_3 ? j + 16 : i == Xdynamite_1 ? 0 : i == Xdynamite_2 ? 8 : i == Xdynamite_3 ? 16 : i == Xdynamite_4 ? 24 : i == Xsand_stonein_1 ? j + 1 : i == Xsand_stonein_2 ? j + 9 : i == Xsand_stonein_3 ? j + 17 : i == Xsand_stonein_4 ? j + 25 : i == Xsand_stoneout_1 && j == 0 ? 0 : i == Xsand_stoneout_1 && j == 1 ? 0 : i == Xsand_stoneout_1 && j == 2 ? 1 : i == Xsand_stoneout_1 && j == 3 ? 2 : i == Xsand_stoneout_1 && j == 4 ? 2 : i == Xsand_stoneout_1 && j == 5 ? 3 : i == Xsand_stoneout_1 && j == 6 ? 4 : i == Xsand_stoneout_1 && j == 7 ? 4 : i == Xsand_stoneout_2 && j == 0 ? 5 : i == Xsand_stoneout_2 && j == 1 ? 6 : i == Xsand_stoneout_2 && j == 2 ? 7 : i == Xsand_stoneout_2 && j == 3 ? 8 : i == Xsand_stoneout_2 && j == 4 ? 9 : i == Xsand_stoneout_2 && j == 5 ? 11 : i == Xsand_stoneout_2 && j == 6 ? 13 : i == Xsand_stoneout_2 && j == 7 ? 15 : i == Xboom_bug && j == 1 ? 2 : i == Xboom_bug && j == 2 ? 2 : i == Xboom_bug && j == 3 ? 4 : i == Xboom_bug && j == 4 ? 4 : i == Xboom_bug && j == 5 ? 2 : i == Xboom_bug && j == 6 ? 2 : i == Xboom_bug && j == 7 ? 0 : i == Xboom_bomb && j == 1 ? 2 : i == Xboom_bomb && j == 2 ? 2 : i == Xboom_bomb && j == 3 ? 4 : i == Xboom_bomb && j == 4 ? 4 : i == Xboom_bomb && j == 5 ? 2 : i == Xboom_bomb && j == 6 ? 2 : i == Xboom_bomb && j == 7 ? 0 : i == Xboom_android && j == 7 ? 6 : i == Xboom_1 && j == 1 ? 2 : i == Xboom_1 && j == 2 ? 2 : i == Xboom_1 && j == 3 ? 4 : i == Xboom_1 && j == 4 ? 4 : i == Xboom_1 && j == 5 ? 6 : i == Xboom_1 && j == 6 ? 6 : i == Xboom_1 && j == 7 ? 8 : i == Xboom_2 && j == 0 ? 8 : i == Xboom_2 && j == 1 ? 8 : i == Xboom_2 && j == 2 ? 10 : i == Xboom_2 && j == 3 ? 10 : i == Xboom_2 && j == 4 ? 10 : i == Xboom_2 && j == 5 ? 12 : i == Xboom_2 && j == 6 ? 12 : i == Xboom_2 && j == 7 ? 12 : #if 0 special_animation && j == 4 ? 3 : effective_action != action ? 0 : #endif j); #endif #if 0 int xxx_effective_action; int xxx_has_action_graphics; { int element = object_mapping[i].element_rnd; int action = object_mapping[i].action; int direction = object_mapping[i].direction; boolean is_backside = object_mapping[i].is_backside; #if 0 boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); #endif boolean action_exploding = ((action == ACTION_EXPLODING || action == ACTION_SMASHED_BY_ROCK || action == ACTION_SMASHED_BY_SPRING) && element != EL_DIAMOND); boolean action_active = (action == ACTION_ACTIVE); boolean action_other = (action == ACTION_OTHER); { #if 1 int effective_element = get_effective_element_EM(i, j); #else int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY : j > 5 && i == Yacid_splash_wB ? EL_EMPTY : j < 7 ? element : i == Xdrip_stretch ? element : i == Xdrip_stretchB ? element : i == Ydrip_s1 ? element : i == Ydrip_s1B ? element : i == Xball_1B ? element : i == Xball_2 ? element : i == Xball_2B ? element : i == Yball_eat ? element : i == Ykey_1_eat ? element : i == Ykey_2_eat ? element : i == Ykey_3_eat ? element : i == Ykey_4_eat ? element : i == Ykey_5_eat ? element : i == Ykey_6_eat ? element : i == Ykey_7_eat ? element : i == Ykey_8_eat ? element : i == Ylenses_eat ? element : i == Ymagnify_eat ? element : i == Ygrass_eat ? element : i == Ydirt_eat ? element : i == Yemerald_stone ? EL_EMERALD : i == Ydiamond_stone ? EL_ROCK : i == Xsand_stonein_1 ? element : i == Xsand_stonein_2 ? element : i == Xsand_stonein_3 ? element : i == Xsand_stonein_4 ? element : is_backside ? EL_EMPTY : action_removing ? EL_EMPTY : element); #endif int effective_action = (j < 7 ? action : i == Xdrip_stretch ? action : i == Xdrip_stretchB ? action : i == Ydrip_s1 ? action : i == Ydrip_s1B ? action : i == Xball_1B ? action : i == Xball_2 ? action : i == Xball_2B ? action : i == Yball_eat ? action : i == Ykey_1_eat ? action : i == Ykey_2_eat ? action : i == Ykey_3_eat ? action : i == Ykey_4_eat ? action : i == Ykey_5_eat ? action : i == Ykey_6_eat ? action : i == Ykey_7_eat ? action : i == Ykey_8_eat ? action : i == Ylenses_eat ? action : i == Ymagnify_eat ? action : i == Ygrass_eat ? action : i == Ydirt_eat ? action : i == Xsand_stonein_1 ? action : i == Xsand_stonein_2 ? action : i == Xsand_stonein_3 ? action : i == Xsand_stonein_4 ? action : i == Xsand_stoneout_1 ? action : i == Xsand_stoneout_2 ? action : i == Xboom_android ? ACTION_EXPLODING : action_exploding ? ACTION_EXPLODING : action_active ? action : action_other ? action : ACTION_DEFAULT); int graphic = (el_act_dir2img(effective_element, effective_action, direction)); int crumbled = (el_act_dir2crm(effective_element, effective_action, direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); boolean has_action_graphics = (graphic != base_graphic); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; #if 0 struct GraphicInfo *g_crumbled = &graphic_info[crumbled]; #endif struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; Bitmap *src_bitmap; int src_x, src_y; /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */ boolean special_animation = (action != ACTION_DEFAULT && g->anim_frames == 3 && g->anim_delay == 2 && g->anim_mode & ANIM_LINEAR); xxx_sync_frame = (i == Xdrip_stretch ? 7 : i == Xdrip_stretchB ? 7 : i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xacid_1 ? 0 : i == Xacid_2 ? 10 : i == Xacid_3 ? 20 : i == Xacid_4 ? 30 : i == Xacid_5 ? 40 : i == Xacid_6 ? 50 : i == Xacid_7 ? 60 : i == Xacid_8 ? 70 : i == Xfake_acid_1 ? 0 : i == Xfake_acid_2 ? 10 : i == Xfake_acid_3 ? 20 : i == Xfake_acid_4 ? 30 : i == Xfake_acid_5 ? 40 : i == Xfake_acid_6 ? 50 : i == Xfake_acid_7 ? 60 : i == Xfake_acid_8 ? 70 : i == Xball_2 ? 7 : i == Xball_2B ? j + 8 : i == Yball_eat ? j + 1 : i == Ykey_1_eat ? j + 1 : i == Ykey_2_eat ? j + 1 : i == Ykey_3_eat ? j + 1 : i == Ykey_4_eat ? j + 1 : i == Ykey_5_eat ? j + 1 : i == Ykey_6_eat ? j + 1 : i == Ykey_7_eat ? j + 1 : i == Ykey_8_eat ? j + 1 : i == Ylenses_eat ? j + 1 : i == Ymagnify_eat ? j + 1 : i == Ygrass_eat ? j + 1 : i == Ydirt_eat ? j + 1 : i == Xamoeba_1 ? 0 : i == Xamoeba_2 ? 1 : i == Xamoeba_3 ? 2 : i == Xamoeba_4 ? 3 : i == Xamoeba_5 ? 0 : i == Xamoeba_6 ? 1 : i == Xamoeba_7 ? 2 : i == Xamoeba_8 ? 3 : i == Xexit_2 ? j + 8 : i == Xexit_3 ? j + 16 : i == Xdynamite_1 ? 0 : i == Xdynamite_2 ? 8 : i == Xdynamite_3 ? 16 : i == Xdynamite_4 ? 24 : i == Xsand_stonein_1 ? j + 1 : i == Xsand_stonein_2 ? j + 9 : i == Xsand_stonein_3 ? j + 17 : i == Xsand_stonein_4 ? j + 25 : i == Xsand_stoneout_1 && j == 0 ? 0 : i == Xsand_stoneout_1 && j == 1 ? 0 : i == Xsand_stoneout_1 && j == 2 ? 1 : i == Xsand_stoneout_1 && j == 3 ? 2 : i == Xsand_stoneout_1 && j == 4 ? 2 : i == Xsand_stoneout_1 && j == 5 ? 3 : i == Xsand_stoneout_1 && j == 6 ? 4 : i == Xsand_stoneout_1 && j == 7 ? 4 : i == Xsand_stoneout_2 && j == 0 ? 5 : i == Xsand_stoneout_2 && j == 1 ? 6 : i == Xsand_stoneout_2 && j == 2 ? 7 : i == Xsand_stoneout_2 && j == 3 ? 8 : i == Xsand_stoneout_2 && j == 4 ? 9 : i == Xsand_stoneout_2 && j == 5 ? 11 : i == Xsand_stoneout_2 && j == 6 ? 13 : i == Xsand_stoneout_2 && j == 7 ? 15 : i == Xboom_bug && j == 1 ? 2 : i == Xboom_bug && j == 2 ? 2 : i == Xboom_bug && j == 3 ? 4 : i == Xboom_bug && j == 4 ? 4 : i == Xboom_bug && j == 5 ? 2 : i == Xboom_bug && j == 6 ? 2 : i == Xboom_bug && j == 7 ? 0 : i == Xboom_bomb && j == 1 ? 2 : i == Xboom_bomb && j == 2 ? 2 : i == Xboom_bomb && j == 3 ? 4 : i == Xboom_bomb && j == 4 ? 4 : i == Xboom_bomb && j == 5 ? 2 : i == Xboom_bomb && j == 6 ? 2 : i == Xboom_bomb && j == 7 ? 0 : i == Xboom_android && j == 7 ? 6 : i == Xboom_1 && j == 1 ? 2 : i == Xboom_1 && j == 2 ? 2 : i == Xboom_1 && j == 3 ? 4 : i == Xboom_1 && j == 4 ? 4 : i == Xboom_1 && j == 5 ? 6 : i == Xboom_1 && j == 6 ? 6 : i == Xboom_1 && j == 7 ? 8 : i == Xboom_2 && j == 0 ? 8 : i == Xboom_2 && j == 1 ? 8 : i == Xboom_2 && j == 2 ? 10 : i == Xboom_2 && j == 3 ? 10 : i == Xboom_2 && j == 4 ? 10 : i == Xboom_2 && j == 5 ? 12 : i == Xboom_2 && j == 6 ? 12 : i == Xboom_2 && j == 7 ? 12 : special_animation && j == 4 ? 3 : effective_action != action ? 0 : j); xxx_effective_action = effective_action; xxx_has_action_graphics = has_action_graphics; } } #endif int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); #if 0 return; #endif #if 0 if (frame_em == 7) return; #endif #if 0 int old_src_x = g_em->src_x; int old_src_y = g_em->src_y; #endif #if 1 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y, g->double_movement && is_backside); #else getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y, FALSE); #endif #if 0 if (tile == Ydiamond_stone) printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n", frame_em, g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame, frame, g_em->src_x, g_em->src_y, g_em->src_offset_x, g_em->src_offset_y, g_em->dst_offset_x, g_em->dst_offset_y, graphic); #endif #if 0 return; #endif #if 0 if (frame_em == 7) { if (graphic == IMG_BUG_MOVING_RIGHT) printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y, g->double_movement, is_backside, old_src_x, old_src_y, g_em->src_x, g_em->src_y); return; } #endif #if 0 g_em->src_offset_x = 0; g_em->src_offset_y = 0; g_em->dst_offset_x = 0; g_em->dst_offset_y = 0; g_em->width = TILEX; g_em->height = TILEY; g_em->preserve_background = FALSE; #endif /* (updating the "crumbled" graphic definitions is probably not really needed, as animations for crumbled graphics can't be longer than one EMC cycle) */ #if 1 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled, sync_frame); #else g_em->crumbled_bitmap = NULL; g_em->crumbled_src_x = 0; g_em->crumbled_src_y = 0; g_em->has_crumbled_graphics = FALSE; if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE) { int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames, g_crumbled->anim_delay, g_crumbled->anim_mode, g_crumbled->anim_start_frame, sync_frame); getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap, &g_em->crumbled_src_x, &g_em->crumbled_src_y); g_em->has_crumbled_graphics = TRUE; } #endif #if 0 { int effective_action = xxx_effective_action; int has_action_graphics = xxx_has_action_graphics; if ((!g->double_movement && (effective_action == ACTION_FALLING || effective_action == ACTION_MOVING || effective_action == ACTION_PUSHING || effective_action == ACTION_EATING)) || (!has_action_graphics && (effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING))) { int move_dir = (effective_action == ACTION_FALLING || effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING ? MV_DOWN : direction); int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0); int num_steps = (i == Ydrip_s1 ? 16 : i == Ydrip_s1B ? 16 : i == Ydrip_s2 ? 16 : i == Ydrip_s2B ? 16 : i == Xsand_stonein_1 ? 32 : i == Xsand_stonein_2 ? 32 : i == Xsand_stonein_3 ? 32 : i == Xsand_stonein_4 ? 32 : i == Xsand_stoneout_1 ? 16 : i == Xsand_stoneout_2 ? 16 : 8); int cx = ABS(dx) * (TILEX / num_steps); int cy = ABS(dy) * (TILEY / num_steps); int step_frame = (i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xsand_stonein_2 ? j + 8 : i == Xsand_stonein_3 ? j + 16 : i == Xsand_stonein_4 ? j + 24 : i == Xsand_stoneout_2 ? j + 8 : j) + 1; int step = (is_backside ? step_frame : num_steps - step_frame); if (is_backside) /* tile where movement starts */ { if (dx < 0 || dy < 0) { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } else { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } } else /* tile where movement ends */ { if (dx < 0 || dy < 0) { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } else { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } } g_em->width = TILEX - cx * step; g_em->height = TILEY - cy * step; } /* create unique graphic identifier to decide if tile must be redrawn */ /* bit 31 - 16 (16 bit): EM style graphic bit 15 - 12 ( 4 bit): EM style frame bit 11 - 6 ( 6 bit): graphic width bit 5 - 0 ( 6 bit): graphic height */ g_em->unique_identifier = (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height; } #endif } void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em, int player_nr, int anim, int frame_em) { int element = player_mapping[player_nr][anim].element_rnd; int action = player_mapping[player_nr][anim].action; int direction = player_mapping[player_nr][anim].direction; int graphic = (direction == MV_NONE ? el_act2img(element, action) : el_act_dir2img(element, action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; int sync_frame; InitPlayerGfxAnimation(&stored_player[player_nr], action, direction); stored_player[player_nr].StepFrame = frame_em; sync_frame = stored_player[player_nr].Frame; int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y, FALSE); #if 0 printf("::: %d: %d, %d [%d]\n", player_nr, stored_player[player_nr].Frame, stored_player[player_nr].StepFrame, FrameCounter); #endif } void InitGraphicInfo_EM(void) { #if 0 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX]; struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX]; #endif int i, j, p; #if DEBUG_EM_GFX int num_em_gfx_errors = 0; if (graphic_info_em_object[0][0].bitmap == NULL) { /* EM graphics not yet initialized in em_open_all() */ return; } printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n"); #endif /* always start with reliable default values */ for (i = 0; i < TILE_MAX; i++) { object_mapping[i].element_rnd = EL_UNKNOWN; object_mapping[i].is_backside = FALSE; object_mapping[i].action = ACTION_DEFAULT; object_mapping[i].direction = MV_NONE; } /* always start with reliable default values */ for (p = 0; p < MAX_PLAYERS; p++) { for (i = 0; i < SPR_MAX; i++) { player_mapping[p][i].element_rnd = EL_UNKNOWN; player_mapping[p][i].action = ACTION_DEFAULT; player_mapping[p][i].direction = MV_NONE; } } for (i = 0; em_object_mapping_list[i].element_em != -1; i++) { int e = em_object_mapping_list[i].element_em; object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd; object_mapping[e].is_backside = em_object_mapping_list[i].is_backside; if (em_object_mapping_list[i].action != -1) object_mapping[e].action = em_object_mapping_list[i].action; if (em_object_mapping_list[i].direction != -1) object_mapping[e].direction = MV_DIR_FROM_BIT(em_object_mapping_list[i].direction); } for (i = 0; em_player_mapping_list[i].action_em != -1; i++) { int a = em_player_mapping_list[i].action_em; int p = em_player_mapping_list[i].player_nr; player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd; if (em_player_mapping_list[i].action != -1) player_mapping[p][a].action = em_player_mapping_list[i].action; if (em_player_mapping_list[i].direction != -1) player_mapping[p][a].direction = MV_DIR_FROM_BIT(em_player_mapping_list[i].direction); } for (i = 0; i < TILE_MAX; i++) { int element = object_mapping[i].element_rnd; int action = object_mapping[i].action; int direction = object_mapping[i].direction; boolean is_backside = object_mapping[i].is_backside; #if 0 boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); #endif boolean action_exploding = ((action == ACTION_EXPLODING || action == ACTION_SMASHED_BY_ROCK || action == ACTION_SMASHED_BY_SPRING) && element != EL_DIAMOND); boolean action_active = (action == ACTION_ACTIVE); boolean action_other = (action == ACTION_OTHER); for (j = 0; j < 8; j++) { #if 1 int effective_element = get_effective_element_EM(i, j); #else int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY : j > 5 && i == Yacid_splash_wB ? EL_EMPTY : j < 7 ? element : i == Xdrip_stretch ? element : i == Xdrip_stretchB ? element : i == Ydrip_s1 ? element : i == Ydrip_s1B ? element : i == Xball_1B ? element : i == Xball_2 ? element : i == Xball_2B ? element : i == Yball_eat ? element : i == Ykey_1_eat ? element : i == Ykey_2_eat ? element : i == Ykey_3_eat ? element : i == Ykey_4_eat ? element : i == Ykey_5_eat ? element : i == Ykey_6_eat ? element : i == Ykey_7_eat ? element : i == Ykey_8_eat ? element : i == Ylenses_eat ? element : i == Ymagnify_eat ? element : i == Ygrass_eat ? element : i == Ydirt_eat ? element : i == Yemerald_stone ? EL_EMERALD : i == Ydiamond_stone ? EL_ROCK : i == Xsand_stonein_1 ? element : i == Xsand_stonein_2 ? element : i == Xsand_stonein_3 ? element : i == Xsand_stonein_4 ? element : is_backside ? EL_EMPTY : action_removing ? EL_EMPTY : element); #endif int effective_action = (j < 7 ? action : i == Xdrip_stretch ? action : i == Xdrip_stretchB ? action : i == Ydrip_s1 ? action : i == Ydrip_s1B ? action : i == Xball_1B ? action : i == Xball_2 ? action : i == Xball_2B ? action : i == Yball_eat ? action : i == Ykey_1_eat ? action : i == Ykey_2_eat ? action : i == Ykey_3_eat ? action : i == Ykey_4_eat ? action : i == Ykey_5_eat ? action : i == Ykey_6_eat ? action : i == Ykey_7_eat ? action : i == Ykey_8_eat ? action : i == Ylenses_eat ? action : i == Ymagnify_eat ? action : i == Ygrass_eat ? action : i == Ydirt_eat ? action : i == Xsand_stonein_1 ? action : i == Xsand_stonein_2 ? action : i == Xsand_stonein_3 ? action : i == Xsand_stonein_4 ? action : i == Xsand_stoneout_1 ? action : i == Xsand_stoneout_2 ? action : i == Xboom_android ? ACTION_EXPLODING : action_exploding ? ACTION_EXPLODING : action_active ? action : action_other ? action : ACTION_DEFAULT); int graphic = (el_act_dir2img(effective_element, effective_action, direction)); int crumbled = (el_act_dir2crm(effective_element, effective_action, direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); boolean has_action_graphics = (graphic != base_graphic); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; #if 0 struct GraphicInfo *g_crumbled = &graphic_info[crumbled]; #endif struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; Bitmap *src_bitmap; int src_x, src_y; /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */ boolean special_animation = (action != ACTION_DEFAULT && g->anim_frames == 3 && g->anim_delay == 2 && g->anim_mode & ANIM_LINEAR); int sync_frame = (i == Xdrip_stretch ? 7 : i == Xdrip_stretchB ? 7 : i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xacid_1 ? 0 : i == Xacid_2 ? 10 : i == Xacid_3 ? 20 : i == Xacid_4 ? 30 : i == Xacid_5 ? 40 : i == Xacid_6 ? 50 : i == Xacid_7 ? 60 : i == Xacid_8 ? 70 : i == Xfake_acid_1 ? 0 : i == Xfake_acid_2 ? 10 : i == Xfake_acid_3 ? 20 : i == Xfake_acid_4 ? 30 : i == Xfake_acid_5 ? 40 : i == Xfake_acid_6 ? 50 : i == Xfake_acid_7 ? 60 : i == Xfake_acid_8 ? 70 : i == Xball_2 ? 7 : i == Xball_2B ? j + 8 : i == Yball_eat ? j + 1 : i == Ykey_1_eat ? j + 1 : i == Ykey_2_eat ? j + 1 : i == Ykey_3_eat ? j + 1 : i == Ykey_4_eat ? j + 1 : i == Ykey_5_eat ? j + 1 : i == Ykey_6_eat ? j + 1 : i == Ykey_7_eat ? j + 1 : i == Ykey_8_eat ? j + 1 : i == Ylenses_eat ? j + 1 : i == Ymagnify_eat ? j + 1 : i == Ygrass_eat ? j + 1 : i == Ydirt_eat ? j + 1 : i == Xamoeba_1 ? 0 : i == Xamoeba_2 ? 1 : i == Xamoeba_3 ? 2 : i == Xamoeba_4 ? 3 : i == Xamoeba_5 ? 0 : i == Xamoeba_6 ? 1 : i == Xamoeba_7 ? 2 : i == Xamoeba_8 ? 3 : i == Xexit_2 ? j + 8 : i == Xexit_3 ? j + 16 : i == Xdynamite_1 ? 0 : i == Xdynamite_2 ? 8 : i == Xdynamite_3 ? 16 : i == Xdynamite_4 ? 24 : i == Xsand_stonein_1 ? j + 1 : i == Xsand_stonein_2 ? j + 9 : i == Xsand_stonein_3 ? j + 17 : i == Xsand_stonein_4 ? j + 25 : i == Xsand_stoneout_1 && j == 0 ? 0 : i == Xsand_stoneout_1 && j == 1 ? 0 : i == Xsand_stoneout_1 && j == 2 ? 1 : i == Xsand_stoneout_1 && j == 3 ? 2 : i == Xsand_stoneout_1 && j == 4 ? 2 : i == Xsand_stoneout_1 && j == 5 ? 3 : i == Xsand_stoneout_1 && j == 6 ? 4 : i == Xsand_stoneout_1 && j == 7 ? 4 : i == Xsand_stoneout_2 && j == 0 ? 5 : i == Xsand_stoneout_2 && j == 1 ? 6 : i == Xsand_stoneout_2 && j == 2 ? 7 : i == Xsand_stoneout_2 && j == 3 ? 8 : i == Xsand_stoneout_2 && j == 4 ? 9 : i == Xsand_stoneout_2 && j == 5 ? 11 : i == Xsand_stoneout_2 && j == 6 ? 13 : i == Xsand_stoneout_2 && j == 7 ? 15 : i == Xboom_bug && j == 1 ? 2 : i == Xboom_bug && j == 2 ? 2 : i == Xboom_bug && j == 3 ? 4 : i == Xboom_bug && j == 4 ? 4 : i == Xboom_bug && j == 5 ? 2 : i == Xboom_bug && j == 6 ? 2 : i == Xboom_bug && j == 7 ? 0 : i == Xboom_bomb && j == 1 ? 2 : i == Xboom_bomb && j == 2 ? 2 : i == Xboom_bomb && j == 3 ? 4 : i == Xboom_bomb && j == 4 ? 4 : i == Xboom_bomb && j == 5 ? 2 : i == Xboom_bomb && j == 6 ? 2 : i == Xboom_bomb && j == 7 ? 0 : i == Xboom_android && j == 7 ? 6 : i == Xboom_1 && j == 1 ? 2 : i == Xboom_1 && j == 2 ? 2 : i == Xboom_1 && j == 3 ? 4 : i == Xboom_1 && j == 4 ? 4 : i == Xboom_1 && j == 5 ? 6 : i == Xboom_1 && j == 6 ? 6 : i == Xboom_1 && j == 7 ? 8 : i == Xboom_2 && j == 0 ? 8 : i == Xboom_2 && j == 1 ? 8 : i == Xboom_2 && j == 2 ? 10 : i == Xboom_2 && j == 3 ? 10 : i == Xboom_2 && j == 4 ? 10 : i == Xboom_2 && j == 5 ? 12 : i == Xboom_2 && j == 6 ? 12 : i == Xboom_2 && j == 7 ? 12 : special_animation && j == 4 ? 3 : effective_action != action ? 0 : j); #if DEBUG_EM_GFX Bitmap *debug_bitmap = g_em->bitmap; int debug_src_x = g_em->src_x; int debug_src_y = g_em->src_y; #endif int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, g->double_movement && is_backside); g_em->bitmap = src_bitmap; g_em->src_x = src_x; g_em->src_y = src_y; g_em->src_offset_x = 0; g_em->src_offset_y = 0; g_em->dst_offset_x = 0; g_em->dst_offset_y = 0; g_em->width = TILEX; g_em->height = TILEY; g_em->preserve_background = FALSE; #if 1 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled, sync_frame); #else g_em->crumbled_bitmap = NULL; g_em->crumbled_src_x = 0; g_em->crumbled_src_y = 0; g_em->crumbled_border_size = 0; g_em->has_crumbled_graphics = FALSE; #if 0 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE) printf("::: empty crumbled: %d [%s], %d, %d\n", effective_element, element_info[effective_element].token_name, effective_action, direction); #endif /* if element can be crumbled, but certain action graphics are just empty space (like instantly snapping sand to empty space in 1 frame), do not treat these empty space graphics as crumbled graphics in EMC engine */ if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE) { int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames, g_crumbled->anim_delay, g_crumbled->anim_mode, g_crumbled->anim_start_frame, sync_frame); getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y); g_em->has_crumbled_graphics = TRUE; g_em->crumbled_bitmap = src_bitmap; g_em->crumbled_src_x = src_x; g_em->crumbled_src_y = src_y; g_em->crumbled_border_size = graphic_info[crumbled].border_size; #if 0 if (g_em == &graphic_info_em_object[207][0]) printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n", graphic_info_em_object[207][0].crumbled_src_x, graphic_info_em_object[207][0].crumbled_src_y, crumbled, frame, src_x, src_y, g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame, gfx.anim_random_frame, frame); #endif #if 0 printf("::: EMC tile %d is crumbled\n", i); #endif } #endif #if 0 if (element == EL_ROCK && effective_action == ACTION_FILLING) printf("::: has_action_graphics == %d\n", has_action_graphics); #endif if ((!g->double_movement && (effective_action == ACTION_FALLING || effective_action == ACTION_MOVING || effective_action == ACTION_PUSHING || effective_action == ACTION_EATING)) || (!has_action_graphics && (effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING))) { int move_dir = (effective_action == ACTION_FALLING || effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING ? MV_DOWN : direction); int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0); int num_steps = (i == Ydrip_s1 ? 16 : i == Ydrip_s1B ? 16 : i == Ydrip_s2 ? 16 : i == Ydrip_s2B ? 16 : i == Xsand_stonein_1 ? 32 : i == Xsand_stonein_2 ? 32 : i == Xsand_stonein_3 ? 32 : i == Xsand_stonein_4 ? 32 : i == Xsand_stoneout_1 ? 16 : i == Xsand_stoneout_2 ? 16 : 8); int cx = ABS(dx) * (TILEX / num_steps); int cy = ABS(dy) * (TILEY / num_steps); int step_frame = (i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xsand_stonein_2 ? j + 8 : i == Xsand_stonein_3 ? j + 16 : i == Xsand_stonein_4 ? j + 24 : i == Xsand_stoneout_2 ? j + 8 : j) + 1; int step = (is_backside ? step_frame : num_steps - step_frame); if (is_backside) /* tile where movement starts */ { if (dx < 0 || dy < 0) { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } else { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } } else /* tile where movement ends */ { if (dx < 0 || dy < 0) { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } else { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } } g_em->width = TILEX - cx * step; g_em->height = TILEY - cy * step; } /* create unique graphic identifier to decide if tile must be redrawn */ /* bit 31 - 16 (16 bit): EM style graphic bit 15 - 12 ( 4 bit): EM style frame bit 11 - 6 ( 6 bit): graphic width bit 5 - 0 ( 6 bit): graphic height */ g_em->unique_identifier = (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height; #if DEBUG_EM_GFX /* skip check for EMC elements not contained in original EMC artwork */ if (element == EL_EMC_FAKE_ACID) continue; if (g_em->bitmap != debug_bitmap || g_em->src_x != debug_src_x || g_em->src_y != debug_src_y || g_em->src_offset_x != 0 || g_em->src_offset_y != 0 || g_em->dst_offset_x != 0 || g_em->dst_offset_y != 0 || g_em->width != TILEX || g_em->height != TILEY) { static int last_i = -1; if (i != last_i) { printf("\n"); last_i = i; } printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)", i, element, element_info[element].token_name, element_action_info[effective_action].suffix, direction); if (element != effective_element) printf(" [%d ('%s')]", effective_element, element_info[effective_element].token_name); printf("\n"); if (g_em->bitmap != debug_bitmap) printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n", j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap)); if (g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n", j, (is_backside ? 'B' : 'F'), g_em->src_x, g_em->src_y, g_em->src_x / 32, g_em->src_y / 32, debug_src_x, debug_src_y, debug_src_x / 32, debug_src_y / 32); if (g_em->src_offset_x != 0 || g_em->src_offset_y != 0 || g_em->dst_offset_x != 0 || g_em->dst_offset_y != 0) printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n", j, is_backside, g_em->src_offset_x, g_em->src_offset_y, g_em->dst_offset_x, g_em->dst_offset_y); if (g_em->width != TILEX || g_em->height != TILEY) printf(" %d (%d): size %d,%d should be %d,%d\n", j, is_backside, g_em->width, g_em->height, TILEX, TILEY); num_em_gfx_errors++; } #endif } } for (i = 0; i < TILE_MAX; i++) { for (j = 0; j < 8; j++) { int element = object_mapping[i].element_rnd; int action = object_mapping[i].action; int direction = object_mapping[i].direction; boolean is_backside = object_mapping[i].is_backside; int graphic_action = el_act_dir2img(element, action, direction); int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction); if ((action == ACTION_SMASHED_BY_ROCK || action == ACTION_SMASHED_BY_SPRING || action == ACTION_EATING) && graphic_action == graphic_default) { int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s : action == ACTION_SMASHED_BY_SPRING ? Yspring_s : direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) : direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) : Xspring); /* no separate animation for "smashed by rock" -- use rock instead */ struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j]; g_em->bitmap = g_xx->bitmap; g_em->src_x = g_xx->src_x; g_em->src_y = g_xx->src_y; g_em->src_offset_x = g_xx->src_offset_x; g_em->src_offset_y = g_xx->src_offset_y; g_em->dst_offset_x = g_xx->dst_offset_x; g_em->dst_offset_y = g_xx->dst_offset_y; g_em->width = g_xx->width; g_em->height = g_xx->height; g_em->unique_identifier = g_xx->unique_identifier; if (!is_backside) g_em->preserve_background = TRUE; } } } for (p = 0; p < MAX_PLAYERS; p++) { for (i = 0; i < SPR_MAX; i++) { int element = player_mapping[p][i].element_rnd; int action = player_mapping[p][i].action; int direction = player_mapping[p][i].direction; for (j = 0; j < 8; j++) { int effective_element = element; int effective_action = action; int graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j]; Bitmap *src_bitmap; int src_x, src_y; int sync_frame = j; #if DEBUG_EM_GFX Bitmap *debug_bitmap = g_em->bitmap; int debug_src_x = g_em->src_x; int debug_src_y = g_em->src_y; #endif int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE); g_em->bitmap = src_bitmap; g_em->src_x = src_x; g_em->src_y = src_y; g_em->src_offset_x = 0; g_em->src_offset_y = 0; g_em->dst_offset_x = 0; g_em->dst_offset_y = 0; g_em->width = TILEX; g_em->height = TILEY; #if DEBUG_EM_GFX /* skip check for EMC elements not contained in original EMC artwork */ if (element == EL_PLAYER_3 || element == EL_PLAYER_4) continue; if (g_em->bitmap != debug_bitmap || g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) { static int last_i = -1; if (i != last_i) { printf("\n"); last_i = i; } printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)", p, i, element, element_info[element].token_name, element_action_info[effective_action].suffix, direction); if (element != effective_element) printf(" [%d ('%s')]", effective_element, element_info[effective_element].token_name); printf("\n"); if (g_em->bitmap != debug_bitmap) printf(" %d: different bitmap! (0x%08x != 0x%08x)\n", j, (int)(g_em->bitmap), (int)(debug_bitmap)); if (g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n", j, g_em->src_x, g_em->src_y, g_em->src_x / 32, g_em->src_y / 32, debug_src_x, debug_src_y, debug_src_x / 32, debug_src_y / 32); num_em_gfx_errors++; } #endif } } } #if DEBUG_EM_GFX printf("\n"); printf("::: [%d errors found]\n", num_em_gfx_errors); exit(0); #endif } void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame, boolean any_player_moving) { int i; if (tape.single_step && tape.recording && !tape.pausing) { boolean active_players = FALSE; for (i = 0; i < MAX_PLAYERS; i++) if (action[i] != JOY_NO_ACTION) active_players = TRUE; if (frame == 0) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); } } void CheckSingleStepMode_SP(boolean murphy_is_moving) { if (tape.single_step && tape.recording && !tape.pausing) { if (!murphy_is_moving) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); } } void getGraphicSource_SP(struct GraphicInfo_SP *g_sp, int graphic, int sync_frame, int x, int y) { int frame = getGraphicAnimationFrame(graphic, sync_frame); getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y); } boolean isNextAnimationFrame_SP(int graphic, int sync_frame) { return (IS_NEXT_FRAME(sync_frame, graphic)); } int getGraphicInfo_Delay(int graphic) { return graphic_info[graphic].anim_delay; } void PlayMenuSoundExt(int sound) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundLoop(sound); else PlaySound(sound); } void PlayMenuSound() { PlayMenuSoundExt(menu.sound[game_status]); } void PlayMenuSoundStereo(int sound, int stereo_position) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP); else PlaySoundStereo(sound, stereo_position); } void PlayMenuSoundIfLoopExt(int sound) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundLoop(sound); } void PlayMenuSoundIfLoop() { PlayMenuSoundIfLoopExt(menu.sound[game_status]); } void PlayMenuMusicExt(int music) { if (music == MUS_UNDEFINED) return; if (!setup.sound_music) return; PlayMusic(music); } void PlayMenuMusic() { PlayMenuMusicExt(menu.music[game_status]); } void PlaySoundActivating() { #if 0 PlaySound(SND_MENU_ITEM_ACTIVATING); #endif } void PlaySoundSelecting() { #if 0 PlaySound(SND_MENU_ITEM_SELECTING); #endif } void ToggleFullscreenIfNeeded() { boolean change_fullscreen = (setup.fullscreen != video.fullscreen_enabled); boolean change_fullscreen_mode = (video.fullscreen_enabled && !strEqual(setup.fullscreen_mode, video.fullscreen_mode_current)); if (!video.fullscreen_available) return; if (change_fullscreen || change_fullscreen_mode) { Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); /* save backbuffer content which gets lost when toggling fullscreen mode */ BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); if (change_fullscreen_mode) { /* keep fullscreen, but change fullscreen mode (screen resolution) */ video.fullscreen_enabled = FALSE; /* force new fullscreen mode */ } /* toggle fullscreen */ ChangeVideoModeIfNeeded(setup.fullscreen); setup.fullscreen = video.fullscreen_enabled; /* restore backbuffer content from temporary backbuffer backup bitmap */ BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); FreeBitmap(tmp_backbuffer); #if 1 /* update visible window/screen */ BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); #else redraw_mask = REDRAW_ALL; #endif } } void ChangeViewportPropertiesIfNeeded() { int *door_1_x = &DX; int *door_1_y = &DY; int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX); int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY); int gfx_game_mode = (game_status == GAME_MODE_PLAYING || game_status == GAME_MODE_EDITOR ? game_status : GAME_MODE_MAIN); struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode]; struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode]; struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode]; int border_size = vp_playfield->border_size; int new_sx = vp_playfield->x + border_size; int new_sy = vp_playfield->y + border_size; int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE; int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE; #if 0 /* !!! TEST ONLY !!! */ // InitGfxBuffers(); return; #endif if (viewport.window.width != WIN_XSIZE || viewport.window.height != WIN_YSIZE) { WIN_XSIZE = viewport.window.width; WIN_YSIZE = viewport.window.height; InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); InitGfxBuffers(); #if 1 SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); // RedrawBackground(); #endif } if (new_scr_fieldx != SCR_FIELDX || new_scr_fieldy != SCR_FIELDY || new_sx != SX || new_sy != SY || vp_playfield->x != REAL_SX || vp_playfield->y != REAL_SY || vp_door_1->x != *door_1_x || vp_door_1->y != *door_1_y || vp_door_2->x != *door_2_x || vp_door_2->y != *door_2_y) { SCR_FIELDX = new_scr_fieldx; SCR_FIELDY = new_scr_fieldy; SX = new_sx; SY = new_sy; REAL_SX = vp_playfield->x; REAL_SY = vp_playfield->y; *door_1_x = vp_door_1->x; *door_1_y = vp_door_1->y; *door_2_x = vp_door_2->x; *door_2_y = vp_door_2->y; InitGfxBuffers(); if (gfx_game_mode == GAME_MODE_MAIN) { InitGadgets(); InitToons(); } } #if 0 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status); #endif } rocksndiamonds-3.3.0.1+dfsg1/src/conf_esg.c0000644000175000017500000007703411375255512017365 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_esg.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_ESG_C #define CONF_ESG_C /* values for element/graphics mapping configuration (special) */ static struct { int element; int special; int graphic; } element_to_special_graphic[] = { { EL_BD_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_BD_WALL_EDITOR }, { EL_BD_ROCK, GFX_SPECIAL_ARG_EDITOR, IMG_BD_ROCK_EDITOR }, { EL_BD_AMOEBA, GFX_SPECIAL_ARG_EDITOR, IMG_BD_AMOEBA_EDITOR }, { EL_BD_BUTTERFLY_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_RIGHT_EDITOR }, { EL_BD_BUTTERFLY_UP, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_UP_EDITOR }, { EL_BD_BUTTERFLY_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_LEFT_EDITOR }, { EL_BD_BUTTERFLY_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_DOWN_EDITOR }, { EL_BD_FIREFLY_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_RIGHT_EDITOR }, { EL_BD_FIREFLY_UP, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_UP_EDITOR }, { EL_BD_FIREFLY_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_LEFT_EDITOR }, { EL_BD_FIREFLY_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_DOWN_EDITOR }, { EL_SP_INFOTRON, GFX_SPECIAL_ARG_EDITOR, IMG_SP_INFOTRON_EDITOR }, { EL_SP_GRAVITY_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_UP_EDITOR }, { EL_SP_GRAVITY_ON_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_ON_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_ON_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_ON_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_UP_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR }, { EL_SP_ELECTRON, GFX_SPECIAL_ARG_EDITOR, IMG_SP_ELECTRON_EDITOR }, { EL_SP_TERMINAL, GFX_SPECIAL_ARG_EDITOR, IMG_SP_TERMINAL_EDITOR }, { EL_SP_BUGGY_BASE, GFX_SPECIAL_ARG_EDITOR, IMG_SP_BUGGY_BASE_EDITOR }, { EL_SOKOBAN_OBJECT, GFX_SPECIAL_ARG_EDITOR, IMG_SOKOBAN_OBJECT_EDITOR }, { EL_SOKOBAN_FIELD_PLAYER, GFX_SPECIAL_ARG_EDITOR, IMG_SOKOBAN_FIELD_PLAYER_EDITOR }, { EL_DYNAMITE, GFX_SPECIAL_ARG_EDITOR, IMG_DYNAMITE_EDITOR }, { EL_DYNAMITE_ACTIVE, GFX_SPECIAL_ARG_EDITOR, IMG_DYNAMITE_ACTIVE_EDITOR }, { EL_EM_DYNAMITE_ACTIVE, GFX_SPECIAL_ARG_EDITOR, IMG_EM_DYNAMITE_ACTIVE_EDITOR }, { EL_YAMYAM_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_LEFT_EDITOR }, { EL_YAMYAM_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_RIGHT_EDITOR }, { EL_YAMYAM_UP, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_UP_EDITOR }, { EL_YAMYAM_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_DOWN_EDITOR }, { EL_QUICKSAND_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_QUICKSAND_FULL_EDITOR }, { EL_QUICKSAND_FAST_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_QUICKSAND_FAST_FULL_EDITOR }, { EL_AMOEBA_WET, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_WET_EDITOR }, { EL_AMOEBA_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_FULL_EDITOR }, { EL_AMOEBA_DEAD, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_DEAD_EDITOR }, { EL_EM_GATE_1_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_1_GRAY_EDITOR }, { EL_EM_GATE_2_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_2_GRAY_EDITOR }, { EL_EM_GATE_3_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_3_GRAY_EDITOR }, { EL_EM_GATE_4_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_4_GRAY_EDITOR }, { EL_DC_GATE_WHITE_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_DC_GATE_WHITE_GRAY_EDITOR }, { EL_INVISIBLE_STEELWALL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_EDITOR }, { EL_INVISIBLE_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_WALL_EDITOR }, { EL_INVISIBLE_SAND, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_SAND_EDITOR }, { EL_KEY_1, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_1_EDITOR }, { EL_KEY_2, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_2_EDITOR }, { EL_KEY_3, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_3_EDITOR }, { EL_KEY_4, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_4_EDITOR }, { EL_GATE_1_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_1_GRAY_EDITOR }, { EL_GATE_2_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_2_GRAY_EDITOR }, { EL_GATE_3_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_3_GRAY_EDITOR }, { EL_GATE_4_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_4_GRAY_EDITOR }, { EL_LAMP, GFX_SPECIAL_ARG_EDITOR, IMG_LAMP_EDITOR }, { EL_EXPANDABLE_WALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR }, { EL_EXPANDABLE_WALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_VERTICAL_EDITOR }, { EL_EXPANDABLE_WALL_ANY, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_ANY_EDITOR }, { EL_EXPANDABLE_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_HORIZONTAL_EDITOR }, { EL_EXPANDABLE_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_VERTICAL_EDITOR }, { EL_EXPANDABLE_STEELWALL_ANY, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_ANY_EDITOR }, { EL_BD_EXPANDABLE_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_BD_EXPANDABLE_WALL_EDITOR }, { EL_PENGUIN, GFX_SPECIAL_ARG_EDITOR, IMG_PENGUIN_EDITOR }, { EL_PLAYER_1, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_1_EDITOR }, { EL_PLAYER_2, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_2_EDITOR }, { EL_PLAYER_3, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_3_EDITOR }, { EL_PLAYER_4, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_4_EDITOR }, { EL_STEELWALL_TOPLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_TOPLEFT_EDITOR }, { EL_STEELWALL_TOPRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_TOPRIGHT_EDITOR }, { EL_STEELWALL_BOTTOMLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_BOTTOMLEFT_EDITOR }, { EL_STEELWALL_BOTTOMRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_BOTTOMRIGHT_EDITOR }, { EL_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_HORIZONTAL_EDITOR }, { EL_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_VERTICAL_EDITOR }, { EL_INVISIBLE_STEELWALL_TOPLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR }, { EL_INVISIBLE_STEELWALL_TOPRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR }, { EL_INVISIBLE_STEELWALL_BOTTOMLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR }, { EL_INVISIBLE_STEELWALL_BOTTOMRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR }, { EL_INVISIBLE_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR }, { EL_INVISIBLE_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR }, { EL_EMC_GATE_5_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_5_GRAY_EDITOR }, { EL_EMC_GATE_6_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_6_GRAY_EDITOR }, { EL_EMC_GATE_7_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_7_GRAY_EDITOR }, { EL_EMC_GATE_8_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_8_GRAY_EDITOR }, { EL_EMC_FAKE_GRASS, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_FAKE_GRASS_EDITOR }, { EL_EMC_DRIPPER, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_DRIPPER_EDITOR }, { EL_CUSTOM_1, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_1_EDITOR }, { EL_CUSTOM_2, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_2_EDITOR }, { EL_CUSTOM_3, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_3_EDITOR }, { EL_CUSTOM_4, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_4_EDITOR }, { EL_CUSTOM_5, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_5_EDITOR }, { EL_CUSTOM_6, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_6_EDITOR }, { EL_CUSTOM_7, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_7_EDITOR }, { EL_CUSTOM_8, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_8_EDITOR }, { EL_CUSTOM_9, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_9_EDITOR }, { EL_CUSTOM_10, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_10_EDITOR }, { EL_CUSTOM_11, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_11_EDITOR }, { EL_CUSTOM_12, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_12_EDITOR }, { EL_CUSTOM_13, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_13_EDITOR }, { EL_CUSTOM_14, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_14_EDITOR }, { EL_CUSTOM_15, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_15_EDITOR }, { EL_CUSTOM_16, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_16_EDITOR }, { EL_CUSTOM_17, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_17_EDITOR }, { EL_CUSTOM_18, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_18_EDITOR }, { EL_CUSTOM_19, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_19_EDITOR }, { EL_CUSTOM_20, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_20_EDITOR }, { EL_CUSTOM_21, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_21_EDITOR }, { EL_CUSTOM_22, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_22_EDITOR }, { EL_CUSTOM_23, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_23_EDITOR }, { EL_CUSTOM_24, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_24_EDITOR }, { EL_CUSTOM_25, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_25_EDITOR }, { EL_CUSTOM_26, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_26_EDITOR }, { EL_CUSTOM_27, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_27_EDITOR }, { EL_CUSTOM_28, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_28_EDITOR }, { EL_CUSTOM_29, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_29_EDITOR }, { EL_CUSTOM_30, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_30_EDITOR }, { EL_CUSTOM_31, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_31_EDITOR }, { EL_CUSTOM_32, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_32_EDITOR }, { EL_CUSTOM_33, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_33_EDITOR }, { EL_CUSTOM_34, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_34_EDITOR }, { EL_CUSTOM_35, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_35_EDITOR }, { EL_CUSTOM_36, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_36_EDITOR }, { EL_CUSTOM_37, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_37_EDITOR }, { EL_CUSTOM_38, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_38_EDITOR }, { EL_CUSTOM_39, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_39_EDITOR }, { EL_CUSTOM_40, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_40_EDITOR }, { EL_CUSTOM_41, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_41_EDITOR }, { EL_CUSTOM_42, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_42_EDITOR }, { EL_CUSTOM_43, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_43_EDITOR }, { EL_CUSTOM_44, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_44_EDITOR }, { EL_CUSTOM_45, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_45_EDITOR }, { EL_CUSTOM_46, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_46_EDITOR }, { EL_CUSTOM_47, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_47_EDITOR }, { EL_CUSTOM_48, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_48_EDITOR }, { EL_CUSTOM_49, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_49_EDITOR }, { EL_CUSTOM_50, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_50_EDITOR }, { EL_CUSTOM_51, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_51_EDITOR }, { EL_CUSTOM_52, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_52_EDITOR }, { EL_CUSTOM_53, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_53_EDITOR }, { EL_CUSTOM_54, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_54_EDITOR }, { EL_CUSTOM_55, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_55_EDITOR }, { EL_CUSTOM_56, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_56_EDITOR }, { EL_CUSTOM_57, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_57_EDITOR }, { EL_CUSTOM_58, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_58_EDITOR }, { EL_CUSTOM_59, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_59_EDITOR }, { EL_CUSTOM_60, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_60_EDITOR }, { EL_CUSTOM_61, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_61_EDITOR }, { EL_CUSTOM_62, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_62_EDITOR }, { EL_CUSTOM_63, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_63_EDITOR }, { EL_CUSTOM_64, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_64_EDITOR }, { EL_CUSTOM_65, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_65_EDITOR }, { EL_CUSTOM_66, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_66_EDITOR }, { EL_CUSTOM_67, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_67_EDITOR }, { EL_CUSTOM_68, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_68_EDITOR }, { EL_CUSTOM_69, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_69_EDITOR }, { EL_CUSTOM_70, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_70_EDITOR }, { EL_CUSTOM_71, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_71_EDITOR }, { EL_CUSTOM_72, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_72_EDITOR }, { EL_CUSTOM_73, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_73_EDITOR }, { EL_CUSTOM_74, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_74_EDITOR }, { EL_CUSTOM_75, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_75_EDITOR }, { EL_CUSTOM_76, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_76_EDITOR }, { EL_CUSTOM_77, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_77_EDITOR }, { EL_CUSTOM_78, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_78_EDITOR }, { EL_CUSTOM_79, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_79_EDITOR }, { EL_CUSTOM_80, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_80_EDITOR }, { EL_CUSTOM_81, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_81_EDITOR }, { EL_CUSTOM_82, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_82_EDITOR }, { EL_CUSTOM_83, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_83_EDITOR }, { EL_CUSTOM_84, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_84_EDITOR }, { EL_CUSTOM_85, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_85_EDITOR }, { EL_CUSTOM_86, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_86_EDITOR }, { EL_CUSTOM_87, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_87_EDITOR }, { EL_CUSTOM_88, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_88_EDITOR }, { EL_CUSTOM_89, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_89_EDITOR }, { EL_CUSTOM_90, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_90_EDITOR }, { EL_CUSTOM_91, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_91_EDITOR }, { EL_CUSTOM_92, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_92_EDITOR }, { EL_CUSTOM_93, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_93_EDITOR }, { EL_CUSTOM_94, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_94_EDITOR }, { EL_CUSTOM_95, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_95_EDITOR }, { EL_CUSTOM_96, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_96_EDITOR }, { EL_CUSTOM_97, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_97_EDITOR }, { EL_CUSTOM_98, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_98_EDITOR }, { EL_CUSTOM_99, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_99_EDITOR }, { EL_CUSTOM_100, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_100_EDITOR }, { EL_CUSTOM_101, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_101_EDITOR }, { EL_CUSTOM_102, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_102_EDITOR }, { EL_CUSTOM_103, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_103_EDITOR }, { EL_CUSTOM_104, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_104_EDITOR }, { EL_CUSTOM_105, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_105_EDITOR }, { EL_CUSTOM_106, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_106_EDITOR }, { EL_CUSTOM_107, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_107_EDITOR }, { EL_CUSTOM_108, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_108_EDITOR }, { EL_CUSTOM_109, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_109_EDITOR }, { EL_CUSTOM_110, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_110_EDITOR }, { EL_CUSTOM_111, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_111_EDITOR }, { EL_CUSTOM_112, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_112_EDITOR }, { EL_CUSTOM_113, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_113_EDITOR }, { EL_CUSTOM_114, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_114_EDITOR }, { EL_CUSTOM_115, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_115_EDITOR }, { EL_CUSTOM_116, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_116_EDITOR }, { EL_CUSTOM_117, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_117_EDITOR }, { EL_CUSTOM_118, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_118_EDITOR }, { EL_CUSTOM_119, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_119_EDITOR }, { EL_CUSTOM_120, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_120_EDITOR }, { EL_CUSTOM_121, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_121_EDITOR }, { EL_CUSTOM_122, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_122_EDITOR }, { EL_CUSTOM_123, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_123_EDITOR }, { EL_CUSTOM_124, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_124_EDITOR }, { EL_CUSTOM_125, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_125_EDITOR }, { EL_CUSTOM_126, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_126_EDITOR }, { EL_CUSTOM_127, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_127_EDITOR }, { EL_CUSTOM_128, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_128_EDITOR }, { EL_CUSTOM_129, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_129_EDITOR }, { EL_CUSTOM_130, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_130_EDITOR }, { EL_CUSTOM_131, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_131_EDITOR }, { EL_CUSTOM_132, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_132_EDITOR }, { EL_CUSTOM_133, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_133_EDITOR }, { EL_CUSTOM_134, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_134_EDITOR }, { EL_CUSTOM_135, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_135_EDITOR }, { EL_CUSTOM_136, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_136_EDITOR }, { EL_CUSTOM_137, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_137_EDITOR }, { EL_CUSTOM_138, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_138_EDITOR }, { EL_CUSTOM_139, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_139_EDITOR }, { EL_CUSTOM_140, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_140_EDITOR }, { EL_CUSTOM_141, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_141_EDITOR }, { EL_CUSTOM_142, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_142_EDITOR }, { EL_CUSTOM_143, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_143_EDITOR }, { EL_CUSTOM_144, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_144_EDITOR }, { EL_CUSTOM_145, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_145_EDITOR }, { EL_CUSTOM_146, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_146_EDITOR }, { EL_CUSTOM_147, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_147_EDITOR }, { EL_CUSTOM_148, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_148_EDITOR }, { EL_CUSTOM_149, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_149_EDITOR }, { EL_CUSTOM_150, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_150_EDITOR }, { EL_CUSTOM_151, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_151_EDITOR }, { EL_CUSTOM_152, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_152_EDITOR }, { EL_CUSTOM_153, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_153_EDITOR }, { EL_CUSTOM_154, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_154_EDITOR }, { EL_CUSTOM_155, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_155_EDITOR }, { EL_CUSTOM_156, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_156_EDITOR }, { EL_CUSTOM_157, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_157_EDITOR }, { EL_CUSTOM_158, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_158_EDITOR }, { EL_CUSTOM_159, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_159_EDITOR }, { EL_CUSTOM_160, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_160_EDITOR }, { EL_CUSTOM_161, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_161_EDITOR }, { EL_CUSTOM_162, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_162_EDITOR }, { EL_CUSTOM_163, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_163_EDITOR }, { EL_CUSTOM_164, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_164_EDITOR }, { EL_CUSTOM_165, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_165_EDITOR }, { EL_CUSTOM_166, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_166_EDITOR }, { EL_CUSTOM_167, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_167_EDITOR }, { EL_CUSTOM_168, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_168_EDITOR }, { EL_CUSTOM_169, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_169_EDITOR }, { EL_CUSTOM_170, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_170_EDITOR }, { EL_CUSTOM_171, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_171_EDITOR }, { EL_CUSTOM_172, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_172_EDITOR }, { EL_CUSTOM_173, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_173_EDITOR }, { EL_CUSTOM_174, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_174_EDITOR }, { EL_CUSTOM_175, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_175_EDITOR }, { EL_CUSTOM_176, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_176_EDITOR }, { EL_CUSTOM_177, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_177_EDITOR }, { EL_CUSTOM_178, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_178_EDITOR }, { EL_CUSTOM_179, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_179_EDITOR }, { EL_CUSTOM_180, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_180_EDITOR }, { EL_CUSTOM_181, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_181_EDITOR }, { EL_CUSTOM_182, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_182_EDITOR }, { EL_CUSTOM_183, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_183_EDITOR }, { EL_CUSTOM_184, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_184_EDITOR }, { EL_CUSTOM_185, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_185_EDITOR }, { EL_CUSTOM_186, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_186_EDITOR }, { EL_CUSTOM_187, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_187_EDITOR }, { EL_CUSTOM_188, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_188_EDITOR }, { EL_CUSTOM_189, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_189_EDITOR }, { EL_CUSTOM_190, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_190_EDITOR }, { EL_CUSTOM_191, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_191_EDITOR }, { EL_CUSTOM_192, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_192_EDITOR }, { EL_CUSTOM_193, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_193_EDITOR }, { EL_CUSTOM_194, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_194_EDITOR }, { EL_CUSTOM_195, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_195_EDITOR }, { EL_CUSTOM_196, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_196_EDITOR }, { EL_CUSTOM_197, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_197_EDITOR }, { EL_CUSTOM_198, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_198_EDITOR }, { EL_CUSTOM_199, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_199_EDITOR }, { EL_CUSTOM_200, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_200_EDITOR }, { EL_CUSTOM_201, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_201_EDITOR }, { EL_CUSTOM_202, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_202_EDITOR }, { EL_CUSTOM_203, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_203_EDITOR }, { EL_CUSTOM_204, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_204_EDITOR }, { EL_CUSTOM_205, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_205_EDITOR }, { EL_CUSTOM_206, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_206_EDITOR }, { EL_CUSTOM_207, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_207_EDITOR }, { EL_CUSTOM_208, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_208_EDITOR }, { EL_CUSTOM_209, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_209_EDITOR }, { EL_CUSTOM_210, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_210_EDITOR }, { EL_CUSTOM_211, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_211_EDITOR }, { EL_CUSTOM_212, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_212_EDITOR }, { EL_CUSTOM_213, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_213_EDITOR }, { EL_CUSTOM_214, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_214_EDITOR }, { EL_CUSTOM_215, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_215_EDITOR }, { EL_CUSTOM_216, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_216_EDITOR }, { EL_CUSTOM_217, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_217_EDITOR }, { EL_CUSTOM_218, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_218_EDITOR }, { EL_CUSTOM_219, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_219_EDITOR }, { EL_CUSTOM_220, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_220_EDITOR }, { EL_CUSTOM_221, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_221_EDITOR }, { EL_CUSTOM_222, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_222_EDITOR }, { EL_CUSTOM_223, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_223_EDITOR }, { EL_CUSTOM_224, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_224_EDITOR }, { EL_CUSTOM_225, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_225_EDITOR }, { EL_CUSTOM_226, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_226_EDITOR }, { EL_CUSTOM_227, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_227_EDITOR }, { EL_CUSTOM_228, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_228_EDITOR }, { EL_CUSTOM_229, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_229_EDITOR }, { EL_CUSTOM_230, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_230_EDITOR }, { EL_CUSTOM_231, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_231_EDITOR }, { EL_CUSTOM_232, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_232_EDITOR }, { EL_CUSTOM_233, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_233_EDITOR }, { EL_CUSTOM_234, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_234_EDITOR }, { EL_CUSTOM_235, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_235_EDITOR }, { EL_CUSTOM_236, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_236_EDITOR }, { EL_CUSTOM_237, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_237_EDITOR }, { EL_CUSTOM_238, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_238_EDITOR }, { EL_CUSTOM_239, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_239_EDITOR }, { EL_CUSTOM_240, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_240_EDITOR }, { EL_CUSTOM_241, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_241_EDITOR }, { EL_CUSTOM_242, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_242_EDITOR }, { EL_CUSTOM_243, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_243_EDITOR }, { EL_CUSTOM_244, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_244_EDITOR }, { EL_CUSTOM_245, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_245_EDITOR }, { EL_CUSTOM_246, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_246_EDITOR }, { EL_CUSTOM_247, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_247_EDITOR }, { EL_CUSTOM_248, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_248_EDITOR }, { EL_CUSTOM_249, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_249_EDITOR }, { EL_CUSTOM_250, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_250_EDITOR }, { EL_CUSTOM_251, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_251_EDITOR }, { EL_CUSTOM_252, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_252_EDITOR }, { EL_CUSTOM_253, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_253_EDITOR }, { EL_CUSTOM_254, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_254_EDITOR }, { EL_CUSTOM_255, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_255_EDITOR }, { EL_CUSTOM_256, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_256_EDITOR }, { EL_GROUP_1, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_1_EDITOR }, { EL_GROUP_2, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_2_EDITOR }, { EL_GROUP_3, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_3_EDITOR }, { EL_GROUP_4, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_4_EDITOR }, { EL_GROUP_5, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_5_EDITOR }, { EL_GROUP_6, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_6_EDITOR }, { EL_GROUP_7, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_7_EDITOR }, { EL_GROUP_8, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_8_EDITOR }, { EL_GROUP_9, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_9_EDITOR }, { EL_GROUP_10, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_10_EDITOR }, { EL_GROUP_11, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_11_EDITOR }, { EL_GROUP_12, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_12_EDITOR }, { EL_GROUP_13, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_13_EDITOR }, { EL_GROUP_14, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_14_EDITOR }, { EL_GROUP_15, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_15_EDITOR }, { EL_GROUP_16, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_16_EDITOR }, { EL_GROUP_17, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_17_EDITOR }, { EL_GROUP_18, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_18_EDITOR }, { EL_GROUP_19, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_19_EDITOR }, { EL_GROUP_20, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_20_EDITOR }, { EL_GROUP_21, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_21_EDITOR }, { EL_GROUP_22, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_22_EDITOR }, { EL_GROUP_23, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_23_EDITOR }, { EL_GROUP_24, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_24_EDITOR }, { EL_GROUP_25, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_25_EDITOR }, { EL_GROUP_26, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_26_EDITOR }, { EL_GROUP_27, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_27_EDITOR }, { EL_GROUP_28, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_28_EDITOR }, { EL_GROUP_29, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_29_EDITOR }, { EL_GROUP_30, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_30_EDITOR }, { EL_GROUP_31, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_31_EDITOR }, { EL_GROUP_32, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_32_EDITOR }, { EL_CHAR_SPACE, GFX_SPECIAL_ARG_EDITOR, IMG_CHAR_SPACE_EDITOR }, { -1, -1, -1 }, }; #endif /* CONF_ESG_C */ rocksndiamonds-3.3.0.1+dfsg1/src/events.h0000644000175000017500000000255211004470552017074 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * events.h * ***********************************************************/ #ifndef EVENTS_H #define EVENTS_H #include "main.h" int FilterMouseMotionEvents(const Event *); void EventLoop(void); void HandleOtherEvents(Event *); void ClearEventQueue(void); void ClearPlayerAction(void); void SleepWhileUnmapped(void); void HandleExposeEvent(ExposeEvent *); void HandleButtonEvent(ButtonEvent *); void HandleMotionEvent(MotionEvent *); void HandleKeyEvent(KeyEvent *); void HandleFocusEvent(FocusChangeEvent *); void HandleClientMessageEvent(ClientMessageEvent *); void HandleWindowManagerEvent(Event *); void HandleNoEvent(void); void HandleButton(int, int, int, int); void HandleKey(Key, int); void HandleJoystick(); #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_var.c0000644000175000017500000032367111375255513017401 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_var.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_VAR_C #define CONF_VAR_C /* values for image and layout parameter configuration */ struct TokenIntPtrInfo image_config_vars[] = { { "[title_initial].fade_mode", &title_initial_default.fade_mode }, { "[title_initial].fade_delay", &title_initial_default.fade_delay }, { "[title_initial].post_delay", &title_initial_default.post_delay }, { "[title_initial].auto_delay", &title_initial_default.auto_delay }, { "[title].fade_mode", &title_default.fade_mode }, { "[title].fade_delay", &title_default.fade_delay }, { "[title].post_delay", &title_default.post_delay }, { "[title].auto_delay", &title_default.auto_delay }, { "[titlemessage_initial].x", &titlemessage_initial_default.x }, { "[titlemessage_initial].y", &titlemessage_initial_default.y }, { "[titlemessage_initial].width", &titlemessage_initial_default.width }, { "[titlemessage_initial].height", &titlemessage_initial_default.height }, { "[titlemessage_initial].chars", &titlemessage_initial_default.chars }, { "[titlemessage_initial].lines", &titlemessage_initial_default.lines }, { "[titlemessage_initial].align", &titlemessage_initial_default.align }, { "[titlemessage_initial].valign", &titlemessage_initial_default.valign }, { "[titlemessage_initial].font", &titlemessage_initial_default.font }, { "[titlemessage_initial].autowrap", &titlemessage_initial_default.autowrap }, { "[titlemessage_initial].centered", &titlemessage_initial_default.centered }, { "[titlemessage_initial].parse_comments", &titlemessage_initial_default.parse_comments }, { "[titlemessage_initial].sort_priority", &titlemessage_initial_default.sort_priority }, { "[titlemessage_initial].fade_mode", &titlemessage_initial_default.fade_mode }, { "[titlemessage_initial].fade_delay", &titlemessage_initial_default.fade_delay }, { "[titlemessage_initial].post_delay", &titlemessage_initial_default.post_delay }, { "[titlemessage_initial].auto_delay", &titlemessage_initial_default.auto_delay }, { "[titlemessage].x", &titlemessage_default.x }, { "[titlemessage].y", &titlemessage_default.y }, { "[titlemessage].width", &titlemessage_default.width }, { "[titlemessage].height", &titlemessage_default.height }, { "[titlemessage].chars", &titlemessage_default.chars }, { "[titlemessage].lines", &titlemessage_default.lines }, { "[titlemessage].align", &titlemessage_default.align }, { "[titlemessage].valign", &titlemessage_default.valign }, { "[titlemessage].font", &titlemessage_default.font }, { "[titlemessage].autowrap", &titlemessage_default.autowrap }, { "[titlemessage].centered", &titlemessage_default.centered }, { "[titlemessage].parse_comments", &titlemessage_default.parse_comments }, { "[titlemessage].sort_priority", &titlemessage_default.sort_priority }, { "[titlemessage].fade_mode", &titlemessage_default.fade_mode }, { "[titlemessage].fade_delay", &titlemessage_default.fade_delay }, { "[titlemessage].post_delay", &titlemessage_default.post_delay }, { "[titlemessage].auto_delay", &titlemessage_default.auto_delay }, { "titlemessage_initial_1.x", &titlemessage_initial[0].x }, { "titlemessage_initial_1.y", &titlemessage_initial[0].y }, { "titlemessage_initial_1.width", &titlemessage_initial[0].width }, { "titlemessage_initial_1.height", &titlemessage_initial[0].height }, { "titlemessage_initial_1.chars", &titlemessage_initial[0].chars }, { "titlemessage_initial_1.lines", &titlemessage_initial[0].lines }, { "titlemessage_initial_1.align", &titlemessage_initial[0].align }, { "titlemessage_initial_1.valign", &titlemessage_initial[0].valign }, { "titlemessage_initial_1.font", &titlemessage_initial[0].font }, { "titlemessage_initial_1.autowrap", &titlemessage_initial[0].autowrap }, { "titlemessage_initial_1.centered", &titlemessage_initial[0].centered }, { "titlemessage_initial_1.parse_comments", &titlemessage_initial[0].parse_comments }, { "titlemessage_initial_1.sort_priority", &titlemessage_initial[0].sort_priority }, { "titlemessage_initial_1.fade_mode", &titlemessage_initial[0].fade_mode }, { "titlemessage_initial_1.fade_delay", &titlemessage_initial[0].fade_delay }, { "titlemessage_initial_1.post_delay", &titlemessage_initial[0].post_delay }, { "titlemessage_initial_1.auto_delay", &titlemessage_initial[0].auto_delay }, { "titlemessage_initial_2.x", &titlemessage_initial[1].x }, { "titlemessage_initial_2.y", &titlemessage_initial[1].y }, { "titlemessage_initial_2.width", &titlemessage_initial[1].width }, { "titlemessage_initial_2.height", &titlemessage_initial[1].height }, { "titlemessage_initial_2.chars", &titlemessage_initial[1].chars }, { "titlemessage_initial_2.lines", &titlemessage_initial[1].lines }, { "titlemessage_initial_2.align", &titlemessage_initial[1].align }, { "titlemessage_initial_2.valign", &titlemessage_initial[1].valign }, { "titlemessage_initial_2.font", &titlemessage_initial[1].font }, { "titlemessage_initial_2.autowrap", &titlemessage_initial[1].autowrap }, { "titlemessage_initial_2.centered", &titlemessage_initial[1].centered }, { "titlemessage_initial_2.parse_comments", &titlemessage_initial[1].parse_comments }, { "titlemessage_initial_2.sort_priority", &titlemessage_initial[1].sort_priority }, { "titlemessage_initial_2.fade_mode", &titlemessage_initial[1].fade_mode }, { "titlemessage_initial_2.fade_delay", &titlemessage_initial[1].fade_delay }, { "titlemessage_initial_2.post_delay", &titlemessage_initial[1].post_delay }, { "titlemessage_initial_2.auto_delay", &titlemessage_initial[1].auto_delay }, { "titlemessage_initial_3.x", &titlemessage_initial[2].x }, { "titlemessage_initial_3.y", &titlemessage_initial[2].y }, { "titlemessage_initial_3.width", &titlemessage_initial[2].width }, { "titlemessage_initial_3.height", &titlemessage_initial[2].height }, { "titlemessage_initial_3.chars", &titlemessage_initial[2].chars }, { "titlemessage_initial_3.lines", &titlemessage_initial[2].lines }, { "titlemessage_initial_3.align", &titlemessage_initial[2].align }, { "titlemessage_initial_3.valign", &titlemessage_initial[2].valign }, { "titlemessage_initial_3.font", &titlemessage_initial[2].font }, { "titlemessage_initial_3.autowrap", &titlemessage_initial[2].autowrap }, { "titlemessage_initial_3.centered", &titlemessage_initial[2].centered }, { "titlemessage_initial_3.parse_comments", &titlemessage_initial[2].parse_comments }, { "titlemessage_initial_3.sort_priority", &titlemessage_initial[2].sort_priority }, { "titlemessage_initial_3.fade_mode", &titlemessage_initial[2].fade_mode }, { "titlemessage_initial_3.fade_delay", &titlemessage_initial[2].fade_delay }, { "titlemessage_initial_3.post_delay", &titlemessage_initial[2].post_delay }, { "titlemessage_initial_3.auto_delay", &titlemessage_initial[2].auto_delay }, { "titlemessage_initial_4.x", &titlemessage_initial[3].x }, { "titlemessage_initial_4.y", &titlemessage_initial[3].y }, { "titlemessage_initial_4.width", &titlemessage_initial[3].width }, { "titlemessage_initial_4.height", &titlemessage_initial[3].height }, { "titlemessage_initial_4.chars", &titlemessage_initial[3].chars }, { "titlemessage_initial_4.lines", &titlemessage_initial[3].lines }, { "titlemessage_initial_4.align", &titlemessage_initial[3].align }, { "titlemessage_initial_4.valign", &titlemessage_initial[3].valign }, { "titlemessage_initial_4.font", &titlemessage_initial[3].font }, { "titlemessage_initial_4.autowrap", &titlemessage_initial[3].autowrap }, { "titlemessage_initial_4.centered", &titlemessage_initial[3].centered }, { "titlemessage_initial_4.parse_comments", &titlemessage_initial[3].parse_comments }, { "titlemessage_initial_4.sort_priority", &titlemessage_initial[3].sort_priority }, { "titlemessage_initial_4.fade_mode", &titlemessage_initial[3].fade_mode }, { "titlemessage_initial_4.fade_delay", &titlemessage_initial[3].fade_delay }, { "titlemessage_initial_4.post_delay", &titlemessage_initial[3].post_delay }, { "titlemessage_initial_4.auto_delay", &titlemessage_initial[3].auto_delay }, { "titlemessage_initial_5.x", &titlemessage_initial[4].x }, { "titlemessage_initial_5.y", &titlemessage_initial[4].y }, { "titlemessage_initial_5.width", &titlemessage_initial[4].width }, { "titlemessage_initial_5.height", &titlemessage_initial[4].height }, { "titlemessage_initial_5.chars", &titlemessage_initial[4].chars }, { "titlemessage_initial_5.lines", &titlemessage_initial[4].lines }, { "titlemessage_initial_5.align", &titlemessage_initial[4].align }, { "titlemessage_initial_5.valign", &titlemessage_initial[4].valign }, { "titlemessage_initial_5.font", &titlemessage_initial[4].font }, { "titlemessage_initial_5.autowrap", &titlemessage_initial[4].autowrap }, { "titlemessage_initial_5.centered", &titlemessage_initial[4].centered }, { "titlemessage_initial_5.parse_comments", &titlemessage_initial[4].parse_comments }, { "titlemessage_initial_5.sort_priority", &titlemessage_initial[4].sort_priority }, { "titlemessage_initial_5.fade_mode", &titlemessage_initial[4].fade_mode }, { "titlemessage_initial_5.fade_delay", &titlemessage_initial[4].fade_delay }, { "titlemessage_initial_5.post_delay", &titlemessage_initial[4].post_delay }, { "titlemessage_initial_5.auto_delay", &titlemessage_initial[4].auto_delay }, { "titlemessage_1.x", &titlemessage[0].x }, { "titlemessage_1.y", &titlemessage[0].y }, { "titlemessage_1.width", &titlemessage[0].width }, { "titlemessage_1.height", &titlemessage[0].height }, { "titlemessage_1.chars", &titlemessage[0].chars }, { "titlemessage_1.lines", &titlemessage[0].lines }, { "titlemessage_1.align", &titlemessage[0].align }, { "titlemessage_1.valign", &titlemessage[0].valign }, { "titlemessage_1.font", &titlemessage[0].font }, { "titlemessage_1.autowrap", &titlemessage[0].autowrap }, { "titlemessage_1.centered", &titlemessage[0].centered }, { "titlemessage_1.parse_comments", &titlemessage[0].parse_comments }, { "titlemessage_1.sort_priority", &titlemessage[0].sort_priority }, { "titlemessage_1.fade_mode", &titlemessage[0].fade_mode }, { "titlemessage_1.fade_delay", &titlemessage[0].fade_delay }, { "titlemessage_1.post_delay", &titlemessage[0].post_delay }, { "titlemessage_1.auto_delay", &titlemessage[0].auto_delay }, { "titlemessage_2.x", &titlemessage[1].x }, { "titlemessage_2.y", &titlemessage[1].y }, { "titlemessage_2.width", &titlemessage[1].width }, { "titlemessage_2.height", &titlemessage[1].height }, { "titlemessage_2.chars", &titlemessage[1].chars }, { "titlemessage_2.lines", &titlemessage[1].lines }, { "titlemessage_2.align", &titlemessage[1].align }, { "titlemessage_2.valign", &titlemessage[1].valign }, { "titlemessage_2.font", &titlemessage[1].font }, { "titlemessage_2.autowrap", &titlemessage[1].autowrap }, { "titlemessage_2.centered", &titlemessage[1].centered }, { "titlemessage_2.parse_comments", &titlemessage[1].parse_comments }, { "titlemessage_2.sort_priority", &titlemessage[1].sort_priority }, { "titlemessage_2.fade_mode", &titlemessage[1].fade_mode }, { "titlemessage_2.fade_delay", &titlemessage[1].fade_delay }, { "titlemessage_2.post_delay", &titlemessage[1].post_delay }, { "titlemessage_2.auto_delay", &titlemessage[1].auto_delay }, { "titlemessage_3.x", &titlemessage[2].x }, { "titlemessage_3.y", &titlemessage[2].y }, { "titlemessage_3.width", &titlemessage[2].width }, { "titlemessage_3.height", &titlemessage[2].height }, { "titlemessage_3.chars", &titlemessage[2].chars }, { "titlemessage_3.lines", &titlemessage[2].lines }, { "titlemessage_3.align", &titlemessage[2].align }, { "titlemessage_3.valign", &titlemessage[2].valign }, { "titlemessage_3.font", &titlemessage[2].font }, { "titlemessage_3.autowrap", &titlemessage[2].autowrap }, { "titlemessage_3.centered", &titlemessage[2].centered }, { "titlemessage_3.parse_comments", &titlemessage[2].parse_comments }, { "titlemessage_3.sort_priority", &titlemessage[2].sort_priority }, { "titlemessage_3.fade_mode", &titlemessage[2].fade_mode }, { "titlemessage_3.fade_delay", &titlemessage[2].fade_delay }, { "titlemessage_3.post_delay", &titlemessage[2].post_delay }, { "titlemessage_3.auto_delay", &titlemessage[2].auto_delay }, { "titlemessage_4.x", &titlemessage[3].x }, { "titlemessage_4.y", &titlemessage[3].y }, { "titlemessage_4.width", &titlemessage[3].width }, { "titlemessage_4.height", &titlemessage[3].height }, { "titlemessage_4.chars", &titlemessage[3].chars }, { "titlemessage_4.lines", &titlemessage[3].lines }, { "titlemessage_4.align", &titlemessage[3].align }, { "titlemessage_4.valign", &titlemessage[3].valign }, { "titlemessage_4.font", &titlemessage[3].font }, { "titlemessage_4.autowrap", &titlemessage[3].autowrap }, { "titlemessage_4.centered", &titlemessage[3].centered }, { "titlemessage_4.parse_comments", &titlemessage[3].parse_comments }, { "titlemessage_4.sort_priority", &titlemessage[3].sort_priority }, { "titlemessage_4.fade_mode", &titlemessage[3].fade_mode }, { "titlemessage_4.fade_delay", &titlemessage[3].fade_delay }, { "titlemessage_4.post_delay", &titlemessage[3].post_delay }, { "titlemessage_4.auto_delay", &titlemessage[3].auto_delay }, { "titlemessage_5.x", &titlemessage[4].x }, { "titlemessage_5.y", &titlemessage[4].y }, { "titlemessage_5.width", &titlemessage[4].width }, { "titlemessage_5.height", &titlemessage[4].height }, { "titlemessage_5.chars", &titlemessage[4].chars }, { "titlemessage_5.lines", &titlemessage[4].lines }, { "titlemessage_5.align", &titlemessage[4].align }, { "titlemessage_5.valign", &titlemessage[4].valign }, { "titlemessage_5.font", &titlemessage[4].font }, { "titlemessage_5.autowrap", &titlemessage[4].autowrap }, { "titlemessage_5.centered", &titlemessage[4].centered }, { "titlemessage_5.parse_comments", &titlemessage[4].parse_comments }, { "titlemessage_5.sort_priority", &titlemessage[4].sort_priority }, { "titlemessage_5.fade_mode", &titlemessage[4].fade_mode }, { "titlemessage_5.fade_delay", &titlemessage[4].fade_delay }, { "titlemessage_5.post_delay", &titlemessage[4].post_delay }, { "titlemessage_5.auto_delay", &titlemessage[4].auto_delay }, { "readme.x", &readme.x }, { "readme.y", &readme.y }, { "readme.width", &readme.width }, { "readme.height", &readme.height }, { "readme.chars", &readme.chars }, { "readme.lines", &readme.lines }, { "readme.align", &readme.align }, { "readme.valign", &readme.valign }, { "readme.font", &readme.font }, { "readme.autowrap", &readme.autowrap }, { "readme.centered", &readme.centered }, { "readme.parse_comments", &readme.parse_comments }, { "readme.sort_priority", &readme.sort_priority }, { "global.num_toons", &global.num_toons }, { "border.draw_masked.TITLE", &border.draw_masked[GFX_SPECIAL_ARG_TITLE] }, { "border.draw_masked.MAIN", &border.draw_masked[GFX_SPECIAL_ARG_MAIN] }, { "border.draw_masked.LEVELS", &border.draw_masked[GFX_SPECIAL_ARG_LEVELS] }, { "border.draw_masked.SCORES", &border.draw_masked[GFX_SPECIAL_ARG_SCORES] }, { "border.draw_masked.EDITOR", &border.draw_masked[GFX_SPECIAL_ARG_EDITOR] }, { "border.draw_masked.INFO", &border.draw_masked[GFX_SPECIAL_ARG_INFO] }, { "border.draw_masked.SETUP", &border.draw_masked[GFX_SPECIAL_ARG_SETUP] }, { "border.draw_masked.PLAYING", &border.draw_masked[GFX_SPECIAL_ARG_PLAYING] }, { "border.draw_masked.DOOR", &border.draw_masked[GFX_SPECIAL_ARG_DOOR] }, { "border.draw_masked_when_fading", &border.draw_masked_when_fading }, { "init.busy.x", &init.busy.x }, { "init.busy.y", &init.busy.y }, { "init.busy.align", &init.busy.align }, { "init.busy.valign", &init.busy.valign }, { "menu.enter_menu.fade_mode", &menu.enter_menu.fade_mode }, { "menu.enter_menu.fade_delay", &menu.enter_menu.fade_delay }, { "menu.enter_menu.post_delay", &menu.enter_menu.post_delay }, { "menu.leave_menu.fade_mode", &menu.leave_menu.fade_mode }, { "menu.leave_menu.fade_delay", &menu.leave_menu.fade_delay }, { "menu.leave_menu.post_delay", &menu.leave_menu.post_delay }, { "menu.enter_screen.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].fade_mode }, { "menu.enter_screen.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].fade_delay }, { "menu.enter_screen.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].post_delay }, { "menu.next_screen.fade_mode", &menu.next_screen.fade_mode }, { "menu.next_screen.fade_delay", &menu.next_screen.fade_delay }, { "menu.next_screen.post_delay", &menu.next_screen.post_delay }, { "menu.leave_screen.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].fade_mode }, { "menu.leave_screen.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].fade_delay }, { "menu.leave_screen.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].post_delay }, { "menu.enter_screen.SCORES.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].fade_mode }, { "menu.enter_screen.SCORES.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].fade_delay }, { "menu.enter_screen.SCORES.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].post_delay }, { "menu.enter_screen.EDITOR.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].fade_mode }, { "menu.enter_screen.EDITOR.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].fade_delay }, { "menu.enter_screen.EDITOR.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].post_delay }, { "menu.enter_screen.INFO.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].fade_mode }, { "menu.enter_screen.INFO.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].fade_delay }, { "menu.enter_screen.INFO.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].post_delay }, { "menu.enter_screen.PLAYING.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].fade_mode }, { "menu.enter_screen.PLAYING.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].fade_delay }, { "menu.enter_screen.PLAYING.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].post_delay }, { "menu.leave_screen.SCORES.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].fade_mode }, { "menu.leave_screen.SCORES.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].fade_delay }, { "menu.leave_screen.SCORES.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].post_delay }, { "menu.leave_screen.EDITOR.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].fade_mode }, { "menu.leave_screen.EDITOR.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].fade_delay }, { "menu.leave_screen.EDITOR.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].post_delay }, { "menu.leave_screen.INFO.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].fade_mode }, { "menu.leave_screen.INFO.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].fade_delay }, { "menu.leave_screen.INFO.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].post_delay }, { "menu.leave_screen.PLAYING.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].fade_mode }, { "menu.leave_screen.PLAYING.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].fade_delay }, { "menu.leave_screen.PLAYING.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].post_delay }, { "menu.draw_xoffset", &menu.draw_xoffset[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.draw_yoffset", &menu.draw_yoffset[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.draw_xoffset.MAIN", &menu.draw_xoffset[GFX_SPECIAL_ARG_MAIN] }, { "menu.draw_yoffset.MAIN", &menu.draw_yoffset[GFX_SPECIAL_ARG_MAIN] }, { "menu.draw_xoffset.LEVELS", &menu.draw_xoffset[GFX_SPECIAL_ARG_LEVELS] }, { "menu.draw_yoffset.LEVELS", &menu.draw_yoffset[GFX_SPECIAL_ARG_LEVELS] }, { "menu.draw_xoffset.SCORES", &menu.draw_xoffset[GFX_SPECIAL_ARG_SCORES] }, { "menu.draw_yoffset.SCORES", &menu.draw_yoffset[GFX_SPECIAL_ARG_SCORES] }, { "menu.draw_xoffset.EDITOR", &menu.draw_xoffset[GFX_SPECIAL_ARG_EDITOR] }, { "menu.draw_yoffset.EDITOR", &menu.draw_yoffset[GFX_SPECIAL_ARG_EDITOR] }, { "menu.draw_xoffset.INFO", &menu.draw_xoffset[GFX_SPECIAL_ARG_INFO] }, { "menu.draw_yoffset.INFO", &menu.draw_yoffset[GFX_SPECIAL_ARG_INFO] }, { "menu.draw_xoffset.INFO[ELEMENTS]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.draw_yoffset.INFO[ELEMENTS]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.draw_xoffset.INFO[MUSIC]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.draw_yoffset.INFO[MUSIC]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.draw_xoffset.INFO[CREDITS]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.draw_yoffset.INFO[CREDITS]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.draw_xoffset.INFO[PROGRAM]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.draw_yoffset.INFO[PROGRAM]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.draw_xoffset.INFO[VERSION]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.draw_yoffset.INFO[VERSION]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.draw_xoffset.INFO[LEVELSET]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.draw_yoffset.INFO[LEVELSET]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.draw_xoffset.SETUP", &menu.draw_xoffset[GFX_SPECIAL_ARG_SETUP] }, { "menu.draw_yoffset.SETUP", &menu.draw_yoffset[GFX_SPECIAL_ARG_SETUP] }, { "menu.draw_xoffset.SETUP[GAME]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_GAME] }, { "menu.draw_yoffset.SETUP[GAME]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_GAME] }, { "menu.draw_xoffset.SETUP[EDITOR]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_EDITOR] }, { "menu.draw_yoffset.SETUP[EDITOR]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_EDITOR] }, { "menu.draw_xoffset.SETUP[GRAPHICS]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_GRAPHICS] }, { "menu.draw_yoffset.SETUP[GRAPHICS]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_GRAPHICS] }, { "menu.draw_xoffset.SETUP[SOUND]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SOUND] }, { "menu.draw_yoffset.SETUP[SOUND]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SOUND] }, { "menu.draw_xoffset.SETUP[ARTWORK]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_ARTWORK] }, { "menu.draw_yoffset.SETUP[ARTWORK]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_ARTWORK] }, { "menu.draw_xoffset.SETUP[INPUT]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.draw_yoffset.SETUP[INPUT]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.draw_xoffset.SETUP[SHORTCUTS]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS] }, { "menu.draw_yoffset.SETUP[SHORTCUTS]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_1]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_1]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_2]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_2]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_3]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_3]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_4]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_4]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4] }, { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK] }, { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK] }, { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER] }, { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER] }, { "menu.scrollbar_xoffset", &menu.scrollbar_xoffset }, { "menu.list_size", &menu.list_size[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.list_size.LEVELS", &menu.list_size[GFX_SPECIAL_ARG_LEVELS] }, { "menu.list_size.SCORES", &menu.list_size[GFX_SPECIAL_ARG_SCORES] }, { "menu.list_size.INFO", &menu.list_size[GFX_SPECIAL_ARG_INFO] }, { "menu.list_size.SETUP", &menu.list_size[GFX_SPECIAL_ARG_SETUP] }, { "main.button.name.x", &menu.main.button.name.x }, { "main.button.name.y", &menu.main.button.name.y }, { "main.button.levels.x", &menu.main.button.levels.x }, { "main.button.levels.y", &menu.main.button.levels.y }, { "main.button.scores.x", &menu.main.button.scores.x }, { "main.button.scores.y", &menu.main.button.scores.y }, { "main.button.editor.x", &menu.main.button.editor.x }, { "main.button.editor.y", &menu.main.button.editor.y }, { "main.button.info.x", &menu.main.button.info.x }, { "main.button.info.y", &menu.main.button.info.y }, { "main.button.game.x", &menu.main.button.game.x }, { "main.button.game.y", &menu.main.button.game.y }, { "main.button.setup.x", &menu.main.button.setup.x }, { "main.button.setup.y", &menu.main.button.setup.y }, { "main.button.quit.x", &menu.main.button.quit.x }, { "main.button.quit.y", &menu.main.button.quit.y }, { "main.button.prev_level.x", &menu.main.button.prev_level.x }, { "main.button.prev_level.y", &menu.main.button.prev_level.y }, { "main.button.next_level.x", &menu.main.button.next_level.x }, { "main.button.next_level.y", &menu.main.button.next_level.y }, { "main.text.name.x", &menu.main.text.name.x }, { "main.text.name.y", &menu.main.text.name.y }, { "main.text.name.width", &menu.main.text.name.width }, { "main.text.name.height", &menu.main.text.name.height }, { "main.text.name.align", &menu.main.text.name.align }, { "main.text.name.valign", &menu.main.text.name.valign }, { "main.text.name.font", &menu.main.text.name.font }, { "main.text.levels.x", &menu.main.text.levels.x }, { "main.text.levels.y", &menu.main.text.levels.y }, { "main.text.levels.width", &menu.main.text.levels.width }, { "main.text.levels.height", &menu.main.text.levels.height }, { "main.text.levels.align", &menu.main.text.levels.align }, { "main.text.levels.valign", &menu.main.text.levels.valign }, { "main.text.levels.font", &menu.main.text.levels.font }, { "main.text.scores.x", &menu.main.text.scores.x }, { "main.text.scores.y", &menu.main.text.scores.y }, { "main.text.scores.width", &menu.main.text.scores.width }, { "main.text.scores.height", &menu.main.text.scores.height }, { "main.text.scores.align", &menu.main.text.scores.align }, { "main.text.scores.valign", &menu.main.text.scores.valign }, { "main.text.scores.font", &menu.main.text.scores.font }, { "main.text.editor.x", &menu.main.text.editor.x }, { "main.text.editor.y", &menu.main.text.editor.y }, { "main.text.editor.width", &menu.main.text.editor.width }, { "main.text.editor.height", &menu.main.text.editor.height }, { "main.text.editor.align", &menu.main.text.editor.align }, { "main.text.editor.valign", &menu.main.text.editor.valign }, { "main.text.editor.font", &menu.main.text.editor.font }, { "main.text.info.x", &menu.main.text.info.x }, { "main.text.info.y", &menu.main.text.info.y }, { "main.text.info.width", &menu.main.text.info.width }, { "main.text.info.height", &menu.main.text.info.height }, { "main.text.info.align", &menu.main.text.info.align }, { "main.text.info.valign", &menu.main.text.info.valign }, { "main.text.info.font", &menu.main.text.info.font }, { "main.text.game.x", &menu.main.text.game.x }, { "main.text.game.y", &menu.main.text.game.y }, { "main.text.game.width", &menu.main.text.game.width }, { "main.text.game.height", &menu.main.text.game.height }, { "main.text.game.align", &menu.main.text.game.align }, { "main.text.game.valign", &menu.main.text.game.valign }, { "main.text.game.font", &menu.main.text.game.font }, { "main.text.setup.x", &menu.main.text.setup.x }, { "main.text.setup.y", &menu.main.text.setup.y }, { "main.text.setup.width", &menu.main.text.setup.width }, { "main.text.setup.height", &menu.main.text.setup.height }, { "main.text.setup.align", &menu.main.text.setup.align }, { "main.text.setup.valign", &menu.main.text.setup.valign }, { "main.text.setup.font", &menu.main.text.setup.font }, { "main.text.quit.x", &menu.main.text.quit.x }, { "main.text.quit.y", &menu.main.text.quit.y }, { "main.text.quit.width", &menu.main.text.quit.width }, { "main.text.quit.height", &menu.main.text.quit.height }, { "main.text.quit.align", &menu.main.text.quit.align }, { "main.text.quit.valign", &menu.main.text.quit.valign }, { "main.text.quit.font", &menu.main.text.quit.font }, { "main.text.first_level.x", &menu.main.text.first_level.x }, { "main.text.first_level.y", &menu.main.text.first_level.y }, { "main.text.first_level.align", &menu.main.text.first_level.align }, { "main.text.first_level.valign", &menu.main.text.first_level.valign }, { "main.text.first_level.digits", &menu.main.text.first_level.size }, { "main.text.first_level.font", &menu.main.text.first_level.font }, { "main.text.last_level.x", &menu.main.text.last_level.x }, { "main.text.last_level.y", &menu.main.text.last_level.y }, { "main.text.last_level.align", &menu.main.text.last_level.align }, { "main.text.last_level.valign", &menu.main.text.last_level.valign }, { "main.text.last_level.digits", &menu.main.text.last_level.size }, { "main.text.last_level.font", &menu.main.text.last_level.font }, { "main.text.level_number.x", &menu.main.text.level_number.x }, { "main.text.level_number.y", &menu.main.text.level_number.y }, { "main.text.level_number.align", &menu.main.text.level_number.align }, { "main.text.level_number.valign", &menu.main.text.level_number.valign }, { "main.text.level_number.digits", &menu.main.text.level_number.size }, { "main.text.level_number.font", &menu.main.text.level_number.font }, { "main.text.level_info_1.x", &menu.main.text.level_info_1.x }, { "main.text.level_info_1.y", &menu.main.text.level_info_1.y }, { "main.text.level_info_1.align", &menu.main.text.level_info_1.align }, { "main.text.level_info_1.valign", &menu.main.text.level_info_1.valign }, { "main.text.level_info_1.chars", &menu.main.text.level_info_1.size }, { "main.text.level_info_1.font", &menu.main.text.level_info_1.font }, { "main.text.level_info_2.x", &menu.main.text.level_info_2.x }, { "main.text.level_info_2.y", &menu.main.text.level_info_2.y }, { "main.text.level_info_2.align", &menu.main.text.level_info_2.align }, { "main.text.level_info_2.valign", &menu.main.text.level_info_2.valign }, { "main.text.level_info_2.chars", &menu.main.text.level_info_2.size }, { "main.text.level_info_2.font", &menu.main.text.level_info_2.font }, { "main.text.level_info_2.font_header", &menu.main.text.level_info_2.font_alt }, { "main.text.level_name.x", &menu.main.text.level_name.x }, { "main.text.level_name.y", &menu.main.text.level_name.y }, { "main.text.level_name.align", &menu.main.text.level_name.align }, { "main.text.level_name.valign", &menu.main.text.level_name.valign }, { "main.text.level_name.chars", &menu.main.text.level_name.size }, { "main.text.level_name.font", &menu.main.text.level_name.font }, { "main.text.level_author.x", &menu.main.text.level_author.x }, { "main.text.level_author.y", &menu.main.text.level_author.y }, { "main.text.level_author.align", &menu.main.text.level_author.align }, { "main.text.level_author.valign", &menu.main.text.level_author.valign }, { "main.text.level_author.chars", &menu.main.text.level_author.size }, { "main.text.level_author.font", &menu.main.text.level_author.font }, { "main.text.level_year.x", &menu.main.text.level_year.x }, { "main.text.level_year.y", &menu.main.text.level_year.y }, { "main.text.level_year.align", &menu.main.text.level_year.align }, { "main.text.level_year.valign", &menu.main.text.level_year.valign }, { "main.text.level_year.digits", &menu.main.text.level_year.size }, { "main.text.level_year.font", &menu.main.text.level_year.font }, { "main.text.level_imported_from.x", &menu.main.text.level_imported_from.x }, { "main.text.level_imported_from.y", &menu.main.text.level_imported_from.y }, { "main.text.level_imported_from.align", &menu.main.text.level_imported_from.align }, { "main.text.level_imported_from.valign", &menu.main.text.level_imported_from.valign }, { "main.text.level_imported_from.chars", &menu.main.text.level_imported_from.size }, { "main.text.level_imported_from.font", &menu.main.text.level_imported_from.font }, { "main.text.level_imported_by.x", &menu.main.text.level_imported_by.x }, { "main.text.level_imported_by.y", &menu.main.text.level_imported_by.y }, { "main.text.level_imported_by.align", &menu.main.text.level_imported_by.align }, { "main.text.level_imported_by.valign", &menu.main.text.level_imported_by.valign }, { "main.text.level_imported_by.chars", &menu.main.text.level_imported_by.size }, { "main.text.level_imported_by.font", &menu.main.text.level_imported_by.font }, { "main.text.level_tested_by.x", &menu.main.text.level_tested_by.x }, { "main.text.level_tested_by.y", &menu.main.text.level_tested_by.y }, { "main.text.level_tested_by.align", &menu.main.text.level_tested_by.align }, { "main.text.level_tested_by.valign", &menu.main.text.level_tested_by.valign }, { "main.text.level_tested_by.chars", &menu.main.text.level_tested_by.size }, { "main.text.level_tested_by.font", &menu.main.text.level_tested_by.font }, { "main.text.title_1.x", &menu.main.text.title_1.x }, { "main.text.title_1.y", &menu.main.text.title_1.y }, { "main.text.title_1.align", &menu.main.text.title_1.align }, { "main.text.title_1.valign", &menu.main.text.title_1.valign }, { "main.text.title_1.font", &menu.main.text.title_1.font }, { "main.text.title_2.x", &menu.main.text.title_2.x }, { "main.text.title_2.y", &menu.main.text.title_2.y }, { "main.text.title_2.align", &menu.main.text.title_2.align }, { "main.text.title_2.valign", &menu.main.text.title_2.valign }, { "main.text.title_2.font", &menu.main.text.title_2.font }, { "main.text.title_3.x", &menu.main.text.title_3.x }, { "main.text.title_3.y", &menu.main.text.title_3.y }, { "main.text.title_3.align", &menu.main.text.title_3.align }, { "main.text.title_3.valign", &menu.main.text.title_3.valign }, { "main.text.title_3.font", &menu.main.text.title_3.font }, { "main.input.name.x", &menu.main.input.name.x }, { "main.input.name.y", &menu.main.input.name.y }, { "main.input.name.align", &menu.main.input.name.align }, { "main.input.name.valign", &menu.main.input.name.valign }, { "main.input.name.font", &menu.main.input.name.font }, { "preview.x", &preview.x }, { "preview.y", &preview.y }, { "preview.align", &preview.align }, { "preview.valign", &preview.valign }, { "preview.xsize", &preview.xsize }, { "preview.ysize", &preview.ysize }, { "preview.xoffset", &preview.xoffset }, { "preview.yoffset", &preview.yoffset }, { "preview.tile_size", &preview.tile_size }, { "preview.step_offset", &preview.step_offset }, { "preview.step_delay", &preview.step_delay }, { "preview.anim_mode", &preview.anim_mode }, { "door_1.width", &door_1.width }, { "door_1.height", &door_1.height }, { "door_1.step_offset", &door_1.step_offset }, { "door_1.step_delay", &door_1.step_delay }, { "door_1.anim_mode", &door_1.anim_mode }, { "door_2.width", &door_2.width }, { "door_2.height", &door_2.height }, { "door_2.step_offset", &door_2.step_offset }, { "door_2.step_delay", &door_2.step_delay }, { "door_2.anim_mode", &door_2.anim_mode }, { "game.panel.level_number.x", &game.panel.level_number.x }, { "game.panel.level_number.y", &game.panel.level_number.y }, { "game.panel.level_number.align", &game.panel.level_number.align }, { "game.panel.level_number.valign", &game.panel.level_number.valign }, { "game.panel.level_number.digits", &game.panel.level_number.size }, { "game.panel.level_number.font", &game.panel.level_number.font }, { "game.panel.level_number.font_narrow", &game.panel.level_number.font_alt }, { "game.panel.level_number.draw_masked", &game.panel.level_number.draw_masked }, { "game.panel.level_number.draw_order", &game.panel.level_number.sort_priority }, { "game.panel.gems.x", &game.panel.gems.x }, { "game.panel.gems.y", &game.panel.gems.y }, { "game.panel.gems.align", &game.panel.gems.align }, { "game.panel.gems.valign", &game.panel.gems.valign }, { "game.panel.gems.digits", &game.panel.gems.size }, { "game.panel.gems.font", &game.panel.gems.font }, { "game.panel.gems.draw_masked", &game.panel.gems.draw_masked }, { "game.panel.gems.draw_order", &game.panel.gems.sort_priority }, { "game.panel.inventory_count.x", &game.panel.inventory_count.x }, { "game.panel.inventory_count.y", &game.panel.inventory_count.y }, { "game.panel.inventory_count.align", &game.panel.inventory_count.align }, { "game.panel.inventory_count.valign", &game.panel.inventory_count.valign }, { "game.panel.inventory_count.digits", &game.panel.inventory_count.size }, { "game.panel.inventory_count.font", &game.panel.inventory_count.font }, { "game.panel.inventory_count.draw_masked", &game.panel.inventory_count.draw_masked }, { "game.panel.inventory_count.draw_order", &game.panel.inventory_count.sort_priority }, { "game.panel.inventory_first_1.x", &game.panel.inventory_first[0].x }, { "game.panel.inventory_first_1.y", &game.panel.inventory_first[0].y }, { "game.panel.inventory_first_1.tile_size", &game.panel.inventory_first[0].size }, { "game.panel.inventory_first_1.draw_masked", &game.panel.inventory_first[0].draw_masked }, { "game.panel.inventory_first_1.draw_order", &game.panel.inventory_first[0].sort_priority }, { "game.panel.inventory_first_2.x", &game.panel.inventory_first[1].x }, { "game.panel.inventory_first_2.y", &game.panel.inventory_first[1].y }, { "game.panel.inventory_first_2.tile_size", &game.panel.inventory_first[1].size }, { "game.panel.inventory_first_2.draw_masked", &game.panel.inventory_first[1].draw_masked }, { "game.panel.inventory_first_2.draw_order", &game.panel.inventory_first[1].sort_priority }, { "game.panel.inventory_first_3.x", &game.panel.inventory_first[2].x }, { "game.panel.inventory_first_3.y", &game.panel.inventory_first[2].y }, { "game.panel.inventory_first_3.tile_size", &game.panel.inventory_first[2].size }, { "game.panel.inventory_first_3.draw_masked", &game.panel.inventory_first[2].draw_masked }, { "game.panel.inventory_first_3.draw_order", &game.panel.inventory_first[2].sort_priority }, { "game.panel.inventory_first_4.x", &game.panel.inventory_first[3].x }, { "game.panel.inventory_first_4.y", &game.panel.inventory_first[3].y }, { "game.panel.inventory_first_4.tile_size", &game.panel.inventory_first[3].size }, { "game.panel.inventory_first_4.draw_masked", &game.panel.inventory_first[3].draw_masked }, { "game.panel.inventory_first_4.draw_order", &game.panel.inventory_first[3].sort_priority }, { "game.panel.inventory_first_5.x", &game.panel.inventory_first[4].x }, { "game.panel.inventory_first_5.y", &game.panel.inventory_first[4].y }, { "game.panel.inventory_first_5.tile_size", &game.panel.inventory_first[4].size }, { "game.panel.inventory_first_5.draw_masked", &game.panel.inventory_first[4].draw_masked }, { "game.panel.inventory_first_5.draw_order", &game.panel.inventory_first[4].sort_priority }, { "game.panel.inventory_first_6.x", &game.panel.inventory_first[5].x }, { "game.panel.inventory_first_6.y", &game.panel.inventory_first[5].y }, { "game.panel.inventory_first_6.tile_size", &game.panel.inventory_first[5].size }, { "game.panel.inventory_first_6.draw_masked", &game.panel.inventory_first[5].draw_masked }, { "game.panel.inventory_first_6.draw_order", &game.panel.inventory_first[5].sort_priority }, { "game.panel.inventory_first_7.x", &game.panel.inventory_first[6].x }, { "game.panel.inventory_first_7.y", &game.panel.inventory_first[6].y }, { "game.panel.inventory_first_7.tile_size", &game.panel.inventory_first[6].size }, { "game.panel.inventory_first_7.draw_masked", &game.panel.inventory_first[6].draw_masked }, { "game.panel.inventory_first_7.draw_order", &game.panel.inventory_first[6].sort_priority }, { "game.panel.inventory_first_8.x", &game.panel.inventory_first[7].x }, { "game.panel.inventory_first_8.y", &game.panel.inventory_first[7].y }, { "game.panel.inventory_first_8.tile_size", &game.panel.inventory_first[7].size }, { "game.panel.inventory_first_8.draw_masked", &game.panel.inventory_first[7].draw_masked }, { "game.panel.inventory_first_8.draw_order", &game.panel.inventory_first[7].sort_priority }, { "game.panel.inventory_last_1.x", &game.panel.inventory_last[0].x }, { "game.panel.inventory_last_1.y", &game.panel.inventory_last[0].y }, { "game.panel.inventory_last_1.tile_size", &game.panel.inventory_last[0].size }, { "game.panel.inventory_last_1.draw_masked", &game.panel.inventory_last[0].draw_masked }, { "game.panel.inventory_last_1.draw_order", &game.panel.inventory_last[0].sort_priority }, { "game.panel.inventory_last_2.x", &game.panel.inventory_last[1].x }, { "game.panel.inventory_last_2.y", &game.panel.inventory_last[1].y }, { "game.panel.inventory_last_2.tile_size", &game.panel.inventory_last[1].size }, { "game.panel.inventory_last_2.draw_masked", &game.panel.inventory_last[1].draw_masked }, { "game.panel.inventory_last_2.draw_order", &game.panel.inventory_last[1].sort_priority }, { "game.panel.inventory_last_3.x", &game.panel.inventory_last[2].x }, { "game.panel.inventory_last_3.y", &game.panel.inventory_last[2].y }, { "game.panel.inventory_last_3.tile_size", &game.panel.inventory_last[2].size }, { "game.panel.inventory_last_3.draw_masked", &game.panel.inventory_last[2].draw_masked }, { "game.panel.inventory_last_3.draw_order", &game.panel.inventory_last[2].sort_priority }, { "game.panel.inventory_last_4.x", &game.panel.inventory_last[3].x }, { "game.panel.inventory_last_4.y", &game.panel.inventory_last[3].y }, { "game.panel.inventory_last_4.tile_size", &game.panel.inventory_last[3].size }, { "game.panel.inventory_last_4.draw_masked", &game.panel.inventory_last[3].draw_masked }, { "game.panel.inventory_last_4.draw_order", &game.panel.inventory_last[3].sort_priority }, { "game.panel.inventory_last_5.x", &game.panel.inventory_last[4].x }, { "game.panel.inventory_last_5.y", &game.panel.inventory_last[4].y }, { "game.panel.inventory_last_5.tile_size", &game.panel.inventory_last[4].size }, { "game.panel.inventory_last_5.draw_masked", &game.panel.inventory_last[4].draw_masked }, { "game.panel.inventory_last_5.draw_order", &game.panel.inventory_last[4].sort_priority }, { "game.panel.inventory_last_6.x", &game.panel.inventory_last[5].x }, { "game.panel.inventory_last_6.y", &game.panel.inventory_last[5].y }, { "game.panel.inventory_last_6.tile_size", &game.panel.inventory_last[5].size }, { "game.panel.inventory_last_6.draw_masked", &game.panel.inventory_last[5].draw_masked }, { "game.panel.inventory_last_6.draw_order", &game.panel.inventory_last[5].sort_priority }, { "game.panel.inventory_last_7.x", &game.panel.inventory_last[6].x }, { "game.panel.inventory_last_7.y", &game.panel.inventory_last[6].y }, { "game.panel.inventory_last_7.tile_size", &game.panel.inventory_last[6].size }, { "game.panel.inventory_last_7.draw_masked", &game.panel.inventory_last[6].draw_masked }, { "game.panel.inventory_last_7.draw_order", &game.panel.inventory_last[6].sort_priority }, { "game.panel.inventory_last_8.x", &game.panel.inventory_last[7].x }, { "game.panel.inventory_last_8.y", &game.panel.inventory_last[7].y }, { "game.panel.inventory_last_8.tile_size", &game.panel.inventory_last[7].size }, { "game.panel.inventory_last_8.draw_masked", &game.panel.inventory_last[7].draw_masked }, { "game.panel.inventory_last_8.draw_order", &game.panel.inventory_last[7].sort_priority }, { "game.panel.key_1.x", &game.panel.key[0].x }, { "game.panel.key_1.y", &game.panel.key[0].y }, { "game.panel.key_1.tile_size", &game.panel.key[0].size }, { "game.panel.key_1.draw_masked", &game.panel.key[0].draw_masked }, { "game.panel.key_1.draw_order", &game.panel.key[0].sort_priority }, { "game.panel.key_2.x", &game.panel.key[1].x }, { "game.panel.key_2.y", &game.panel.key[1].y }, { "game.panel.key_2.tile_size", &game.panel.key[1].size }, { "game.panel.key_2.draw_masked", &game.panel.key[1].draw_masked }, { "game.panel.key_2.draw_order", &game.panel.key[1].sort_priority }, { "game.panel.key_3.x", &game.panel.key[2].x }, { "game.panel.key_3.y", &game.panel.key[2].y }, { "game.panel.key_3.tile_size", &game.panel.key[2].size }, { "game.panel.key_3.draw_masked", &game.panel.key[2].draw_masked }, { "game.panel.key_3.draw_order", &game.panel.key[2].sort_priority }, { "game.panel.key_4.x", &game.panel.key[3].x }, { "game.panel.key_4.y", &game.panel.key[3].y }, { "game.panel.key_4.tile_size", &game.panel.key[3].size }, { "game.panel.key_4.draw_masked", &game.panel.key[3].draw_masked }, { "game.panel.key_4.draw_order", &game.panel.key[3].sort_priority }, { "game.panel.key_5.x", &game.panel.key[4].x }, { "game.panel.key_5.y", &game.panel.key[4].y }, { "game.panel.key_5.tile_size", &game.panel.key[4].size }, { "game.panel.key_5.draw_masked", &game.panel.key[4].draw_masked }, { "game.panel.key_5.draw_order", &game.panel.key[4].sort_priority }, { "game.panel.key_6.x", &game.panel.key[5].x }, { "game.panel.key_6.y", &game.panel.key[5].y }, { "game.panel.key_6.tile_size", &game.panel.key[5].size }, { "game.panel.key_6.draw_masked", &game.panel.key[5].draw_masked }, { "game.panel.key_6.draw_order", &game.panel.key[5].sort_priority }, { "game.panel.key_7.x", &game.panel.key[6].x }, { "game.panel.key_7.y", &game.panel.key[6].y }, { "game.panel.key_7.tile_size", &game.panel.key[6].size }, { "game.panel.key_7.draw_masked", &game.panel.key[6].draw_masked }, { "game.panel.key_7.draw_order", &game.panel.key[6].sort_priority }, { "game.panel.key_8.x", &game.panel.key[7].x }, { "game.panel.key_8.y", &game.panel.key[7].y }, { "game.panel.key_8.tile_size", &game.panel.key[7].size }, { "game.panel.key_8.draw_masked", &game.panel.key[7].draw_masked }, { "game.panel.key_8.draw_order", &game.panel.key[7].sort_priority }, { "game.panel.key_white.x", &game.panel.key_white.x }, { "game.panel.key_white.y", &game.panel.key_white.y }, { "game.panel.key_white.tile_size", &game.panel.key_white.size }, { "game.panel.key_white.draw_masked", &game.panel.key_white.draw_masked }, { "game.panel.key_white.draw_order", &game.panel.key_white.sort_priority }, { "game.panel.key_white_count.x", &game.panel.key_white_count.x }, { "game.panel.key_white_count.y", &game.panel.key_white_count.y }, { "game.panel.key_white_count.align", &game.panel.key_white_count.align }, { "game.panel.key_white_count.valign", &game.panel.key_white_count.valign }, { "game.panel.key_white_count.digits", &game.panel.key_white_count.size }, { "game.panel.key_white_count.font", &game.panel.key_white_count.font }, { "game.panel.key_white_count.draw_masked", &game.panel.key_white_count.draw_masked }, { "game.panel.key_white_count.draw_order", &game.panel.key_white_count.sort_priority }, { "game.panel.score.x", &game.panel.score.x }, { "game.panel.score.y", &game.panel.score.y }, { "game.panel.score.align", &game.panel.score.align }, { "game.panel.score.valign", &game.panel.score.valign }, { "game.panel.score.digits", &game.panel.score.size }, { "game.panel.score.font", &game.panel.score.font }, { "game.panel.score.draw_masked", &game.panel.score.draw_masked }, { "game.panel.score.draw_order", &game.panel.score.sort_priority }, { "game.panel.highscore.x", &game.panel.highscore.x }, { "game.panel.highscore.y", &game.panel.highscore.y }, { "game.panel.highscore.align", &game.panel.highscore.align }, { "game.panel.highscore.valign", &game.panel.highscore.valign }, { "game.panel.highscore.digits", &game.panel.highscore.size }, { "game.panel.highscore.font", &game.panel.highscore.font }, { "game.panel.highscore.draw_masked", &game.panel.highscore.draw_masked }, { "game.panel.highscore.draw_order", &game.panel.highscore.sort_priority }, { "game.panel.time.x", &game.panel.time.x }, { "game.panel.time.y", &game.panel.time.y }, { "game.panel.time.align", &game.panel.time.align }, { "game.panel.time.valign", &game.panel.time.valign }, { "game.panel.time.digits", &game.panel.time.size }, { "game.panel.time.font", &game.panel.time.font }, { "game.panel.time.font_narrow", &game.panel.time.font_alt }, { "game.panel.time.draw_masked", &game.panel.time.draw_masked }, { "game.panel.time.draw_order", &game.panel.time.sort_priority }, { "game.panel.time_hh.x", &game.panel.time_hh.x }, { "game.panel.time_hh.y", &game.panel.time_hh.y }, { "game.panel.time_hh.align", &game.panel.time_hh.align }, { "game.panel.time_hh.valign", &game.panel.time_hh.valign }, { "game.panel.time_hh.digits", &game.panel.time_hh.size }, { "game.panel.time_hh.font", &game.panel.time_hh.font }, { "game.panel.time_hh.draw_masked", &game.panel.time_hh.draw_masked }, { "game.panel.time_hh.draw_order", &game.panel.time_hh.sort_priority }, { "game.panel.time_mm.x", &game.panel.time_mm.x }, { "game.panel.time_mm.y", &game.panel.time_mm.y }, { "game.panel.time_mm.align", &game.panel.time_mm.align }, { "game.panel.time_mm.valign", &game.panel.time_mm.valign }, { "game.panel.time_mm.digits", &game.panel.time_mm.size }, { "game.panel.time_mm.font", &game.panel.time_mm.font }, { "game.panel.time_mm.draw_masked", &game.panel.time_mm.draw_masked }, { "game.panel.time_mm.draw_order", &game.panel.time_mm.sort_priority }, { "game.panel.time_ss.x", &game.panel.time_ss.x }, { "game.panel.time_ss.y", &game.panel.time_ss.y }, { "game.panel.time_ss.align", &game.panel.time_ss.align }, { "game.panel.time_ss.valign", &game.panel.time_ss.valign }, { "game.panel.time_ss.digits", &game.panel.time_ss.size }, { "game.panel.time_ss.font", &game.panel.time_ss.font }, { "game.panel.time_ss.draw_masked", &game.panel.time_ss.draw_masked }, { "game.panel.time_ss.draw_order", &game.panel.time_ss.sort_priority }, { "game.panel.frame.x", &game.panel.frame.x }, { "game.panel.frame.y", &game.panel.frame.y }, { "game.panel.frame.align", &game.panel.frame.align }, { "game.panel.frame.valign", &game.panel.frame.valign }, { "game.panel.frame.digits", &game.panel.frame.size }, { "game.panel.frame.font", &game.panel.frame.font }, { "game.panel.frame.draw_masked", &game.panel.frame.draw_masked }, { "game.panel.frame.draw_order", &game.panel.frame.sort_priority }, { "game.panel.shield_normal.x", &game.panel.shield_normal.x }, { "game.panel.shield_normal.y", &game.panel.shield_normal.y }, { "game.panel.shield_normal.tile_size", &game.panel.shield_normal.size }, { "game.panel.shield_normal.draw_masked", &game.panel.shield_normal.draw_masked }, { "game.panel.shield_normal.draw_order", &game.panel.shield_normal.sort_priority }, { "game.panel.shield_normal_time.x", &game.panel.shield_normal_time.x }, { "game.panel.shield_normal_time.y", &game.panel.shield_normal_time.y }, { "game.panel.shield_normal_time.align", &game.panel.shield_normal_time.align }, { "game.panel.shield_normal_time.valign", &game.panel.shield_normal_time.valign }, { "game.panel.shield_normal_time.digits", &game.panel.shield_normal_time.size }, { "game.panel.shield_normal_time.font", &game.panel.shield_normal_time.font }, { "game.panel.shield_normal_time.draw_masked", &game.panel.shield_normal_time.draw_masked }, { "game.panel.shield_normal_time.draw_order", &game.panel.shield_normal_time.sort_priority }, { "game.panel.shield_deadly.x", &game.panel.shield_deadly.x }, { "game.panel.shield_deadly.y", &game.panel.shield_deadly.y }, { "game.panel.shield_deadly.tile_size", &game.panel.shield_deadly.size }, { "game.panel.shield_deadly.draw_masked", &game.panel.shield_deadly.draw_masked }, { "game.panel.shield_deadly.draw_order", &game.panel.shield_deadly.sort_priority }, { "game.panel.shield_deadly_time.x", &game.panel.shield_deadly_time.x }, { "game.panel.shield_deadly_time.y", &game.panel.shield_deadly_time.y }, { "game.panel.shield_deadly_time.align", &game.panel.shield_deadly_time.align }, { "game.panel.shield_deadly_time.valign", &game.panel.shield_deadly_time.valign }, { "game.panel.shield_deadly_time.digits", &game.panel.shield_deadly_time.size }, { "game.panel.shield_deadly_time.font", &game.panel.shield_deadly_time.font }, { "game.panel.shield_deadly_time.draw_masked", &game.panel.shield_deadly_time.draw_masked }, { "game.panel.shield_deadly_time.draw_order", &game.panel.shield_deadly_time.sort_priority }, { "game.panel.exit.x", &game.panel.exit.x }, { "game.panel.exit.y", &game.panel.exit.y }, { "game.panel.exit.tile_size", &game.panel.exit.size }, { "game.panel.exit.draw_masked", &game.panel.exit.draw_masked }, { "game.panel.exit.draw_order", &game.panel.exit.sort_priority }, { "game.panel.emc_magic_ball.x", &game.panel.emc_magic_ball.x }, { "game.panel.emc_magic_ball.y", &game.panel.emc_magic_ball.y }, { "game.panel.emc_magic_ball.tile_size", &game.panel.emc_magic_ball.size }, { "game.panel.emc_magic_ball.draw_masked", &game.panel.emc_magic_ball.draw_masked }, { "game.panel.emc_magic_ball.draw_order", &game.panel.emc_magic_ball.sort_priority }, { "game.panel.emc_magic_ball_switch.x", &game.panel.emc_magic_ball_switch.x }, { "game.panel.emc_magic_ball_switch.y", &game.panel.emc_magic_ball_switch.y }, { "game.panel.emc_magic_ball_switch.tile_size", &game.panel.emc_magic_ball_switch.size }, { "game.panel.emc_magic_ball_switch.draw_masked", &game.panel.emc_magic_ball_switch.draw_masked }, { "game.panel.emc_magic_ball_switch.draw_order", &game.panel.emc_magic_ball_switch.sort_priority }, { "game.panel.light_switch.x", &game.panel.light_switch.x }, { "game.panel.light_switch.y", &game.panel.light_switch.y }, { "game.panel.light_switch.tile_size", &game.panel.light_switch.size }, { "game.panel.light_switch.draw_masked", &game.panel.light_switch.draw_masked }, { "game.panel.light_switch.draw_order", &game.panel.light_switch.sort_priority }, { "game.panel.light_switch_time.x", &game.panel.light_switch_time.x }, { "game.panel.light_switch_time.y", &game.panel.light_switch_time.y }, { "game.panel.light_switch_time.align", &game.panel.light_switch_time.align }, { "game.panel.light_switch_time.valign", &game.panel.light_switch_time.valign }, { "game.panel.light_switch_time.digits", &game.panel.light_switch_time.size }, { "game.panel.light_switch_time.font", &game.panel.light_switch_time.font }, { "game.panel.light_switch_time.draw_masked", &game.panel.light_switch_time.draw_masked }, { "game.panel.light_switch_time.draw_order", &game.panel.light_switch_time.sort_priority }, { "game.panel.timegate_switch.x", &game.panel.timegate_switch.x }, { "game.panel.timegate_switch.y", &game.panel.timegate_switch.y }, { "game.panel.timegate_switch.tile_size", &game.panel.timegate_switch.size }, { "game.panel.timegate_switch.draw_masked", &game.panel.timegate_switch.draw_masked }, { "game.panel.timegate_switch.draw_order", &game.panel.timegate_switch.sort_priority }, { "game.panel.timegate_switch_time.x", &game.panel.timegate_switch_time.x }, { "game.panel.timegate_switch_time.y", &game.panel.timegate_switch_time.y }, { "game.panel.timegate_switch_time.align", &game.panel.timegate_switch_time.align }, { "game.panel.timegate_switch_time.valign", &game.panel.timegate_switch_time.valign }, { "game.panel.timegate_switch_time.digits", &game.panel.timegate_switch_time.size }, { "game.panel.timegate_switch_time.font", &game.panel.timegate_switch_time.font }, { "game.panel.timegate_switch_time.draw_masked", &game.panel.timegate_switch_time.draw_masked }, { "game.panel.timegate_switch_time.draw_order", &game.panel.timegate_switch_time.sort_priority }, { "game.panel.switchgate_switch.x", &game.panel.switchgate_switch.x }, { "game.panel.switchgate_switch.y", &game.panel.switchgate_switch.y }, { "game.panel.switchgate_switch.tile_size", &game.panel.switchgate_switch.size }, { "game.panel.switchgate_switch.draw_masked", &game.panel.switchgate_switch.draw_masked }, { "game.panel.switchgate_switch.draw_order", &game.panel.switchgate_switch.sort_priority }, { "game.panel.emc_lenses.x", &game.panel.emc_lenses.x }, { "game.panel.emc_lenses.y", &game.panel.emc_lenses.y }, { "game.panel.emc_lenses.tile_size", &game.panel.emc_lenses.size }, { "game.panel.emc_lenses.draw_masked", &game.panel.emc_lenses.draw_masked }, { "game.panel.emc_lenses.draw_order", &game.panel.emc_lenses.sort_priority }, { "game.panel.emc_lenses_time.x", &game.panel.emc_lenses_time.x }, { "game.panel.emc_lenses_time.y", &game.panel.emc_lenses_time.y }, { "game.panel.emc_lenses_time.align", &game.panel.emc_lenses_time.align }, { "game.panel.emc_lenses_time.valign", &game.panel.emc_lenses_time.valign }, { "game.panel.emc_lenses_time.digits", &game.panel.emc_lenses_time.size }, { "game.panel.emc_lenses_time.font", &game.panel.emc_lenses_time.font }, { "game.panel.emc_lenses_time.draw_masked", &game.panel.emc_lenses_time.draw_masked }, { "game.panel.emc_lenses_time.draw_order", &game.panel.emc_lenses_time.sort_priority }, { "game.panel.emc_magnifier.x", &game.panel.emc_magnifier.x }, { "game.panel.emc_magnifier.y", &game.panel.emc_magnifier.y }, { "game.panel.emc_magnifier.tile_size", &game.panel.emc_magnifier.size }, { "game.panel.emc_magnifier.draw_masked", &game.panel.emc_magnifier.draw_masked }, { "game.panel.emc_magnifier.draw_order", &game.panel.emc_magnifier.sort_priority }, { "game.panel.emc_magnifier_time.x", &game.panel.emc_magnifier_time.x }, { "game.panel.emc_magnifier_time.y", &game.panel.emc_magnifier_time.y }, { "game.panel.emc_magnifier_time.align", &game.panel.emc_magnifier_time.align }, { "game.panel.emc_magnifier_time.valign", &game.panel.emc_magnifier_time.valign }, { "game.panel.emc_magnifier_time.digits", &game.panel.emc_magnifier_time.size }, { "game.panel.emc_magnifier_time.font", &game.panel.emc_magnifier_time.font }, { "game.panel.emc_magnifier_time.draw_masked", &game.panel.emc_magnifier_time.draw_masked }, { "game.panel.emc_magnifier_time.draw_order", &game.panel.emc_magnifier_time.sort_priority }, { "game.panel.balloon_switch.x", &game.panel.balloon_switch.x }, { "game.panel.balloon_switch.y", &game.panel.balloon_switch.y }, { "game.panel.balloon_switch.tile_size", &game.panel.balloon_switch.size }, { "game.panel.balloon_switch.draw_masked", &game.panel.balloon_switch.draw_masked }, { "game.panel.balloon_switch.draw_order", &game.panel.balloon_switch.sort_priority }, { "game.panel.dynabomb_number.x", &game.panel.dynabomb_number.x }, { "game.panel.dynabomb_number.y", &game.panel.dynabomb_number.y }, { "game.panel.dynabomb_number.align", &game.panel.dynabomb_number.align }, { "game.panel.dynabomb_number.valign", &game.panel.dynabomb_number.valign }, { "game.panel.dynabomb_number.digits", &game.panel.dynabomb_number.size }, { "game.panel.dynabomb_number.font", &game.panel.dynabomb_number.font }, { "game.panel.dynabomb_number.draw_masked", &game.panel.dynabomb_number.draw_masked }, { "game.panel.dynabomb_number.draw_order", &game.panel.dynabomb_number.sort_priority }, { "game.panel.dynabomb_size.x", &game.panel.dynabomb_size.x }, { "game.panel.dynabomb_size.y", &game.panel.dynabomb_size.y }, { "game.panel.dynabomb_size.align", &game.panel.dynabomb_size.align }, { "game.panel.dynabomb_size.valign", &game.panel.dynabomb_size.valign }, { "game.panel.dynabomb_size.digits", &game.panel.dynabomb_size.size }, { "game.panel.dynabomb_size.font", &game.panel.dynabomb_size.font }, { "game.panel.dynabomb_size.draw_masked", &game.panel.dynabomb_size.draw_masked }, { "game.panel.dynabomb_size.draw_order", &game.panel.dynabomb_size.sort_priority }, { "game.panel.dynabomb_power.x", &game.panel.dynabomb_power.x }, { "game.panel.dynabomb_power.y", &game.panel.dynabomb_power.y }, { "game.panel.dynabomb_power.tile_size", &game.panel.dynabomb_power.size }, { "game.panel.dynabomb_power.draw_masked", &game.panel.dynabomb_power.draw_masked }, { "game.panel.dynabomb_power.draw_order", &game.panel.dynabomb_power.sort_priority }, { "game.panel.penguins.x", &game.panel.penguins.x }, { "game.panel.penguins.y", &game.panel.penguins.y }, { "game.panel.penguins.align", &game.panel.penguins.align }, { "game.panel.penguins.valign", &game.panel.penguins.valign }, { "game.panel.penguins.digits", &game.panel.penguins.size }, { "game.panel.penguins.font", &game.panel.penguins.font }, { "game.panel.penguins.draw_masked", &game.panel.penguins.draw_masked }, { "game.panel.penguins.draw_order", &game.panel.penguins.sort_priority }, { "game.panel.sokoban_objects.x", &game.panel.sokoban_objects.x }, { "game.panel.sokoban_objects.y", &game.panel.sokoban_objects.y }, { "game.panel.sokoban_objects.align", &game.panel.sokoban_objects.align }, { "game.panel.sokoban_objects.valign", &game.panel.sokoban_objects.valign }, { "game.panel.sokoban_objects.digits", &game.panel.sokoban_objects.size }, { "game.panel.sokoban_objects.font", &game.panel.sokoban_objects.font }, { "game.panel.sokoban_objects.draw_masked", &game.panel.sokoban_objects.draw_masked }, { "game.panel.sokoban_objects.draw_order", &game.panel.sokoban_objects.sort_priority }, { "game.panel.sokoban_fields.x", &game.panel.sokoban_fields.x }, { "game.panel.sokoban_fields.y", &game.panel.sokoban_fields.y }, { "game.panel.sokoban_fields.align", &game.panel.sokoban_fields.align }, { "game.panel.sokoban_fields.valign", &game.panel.sokoban_fields.valign }, { "game.panel.sokoban_fields.digits", &game.panel.sokoban_fields.size }, { "game.panel.sokoban_fields.font", &game.panel.sokoban_fields.font }, { "game.panel.sokoban_fields.draw_masked", &game.panel.sokoban_fields.draw_masked }, { "game.panel.sokoban_fields.draw_order", &game.panel.sokoban_fields.sort_priority }, { "game.panel.robot_wheel.x", &game.panel.robot_wheel.x }, { "game.panel.robot_wheel.y", &game.panel.robot_wheel.y }, { "game.panel.robot_wheel.tile_size", &game.panel.robot_wheel.size }, { "game.panel.robot_wheel.draw_masked", &game.panel.robot_wheel.draw_masked }, { "game.panel.robot_wheel.draw_order", &game.panel.robot_wheel.sort_priority }, { "game.panel.conveyor_belt_1.x", &game.panel.conveyor_belt[0].x }, { "game.panel.conveyor_belt_1.y", &game.panel.conveyor_belt[0].y }, { "game.panel.conveyor_belt_1.tile_size", &game.panel.conveyor_belt[0].size }, { "game.panel.conveyor_belt_1.draw_masked", &game.panel.conveyor_belt[0].draw_masked }, { "game.panel.conveyor_belt_1.draw_order", &game.panel.conveyor_belt[0].sort_priority }, { "game.panel.conveyor_belt_1_switch.x", &game.panel.conveyor_belt_switch[0].x }, { "game.panel.conveyor_belt_1_switch.y", &game.panel.conveyor_belt_switch[0].y }, { "game.panel.conveyor_belt_1_switch.tile_size", &game.panel.conveyor_belt_switch[0].size }, { "game.panel.conveyor_belt_1_switch.draw_masked", &game.panel.conveyor_belt_switch[0].draw_masked }, { "game.panel.conveyor_belt_1_switch.draw_order", &game.panel.conveyor_belt_switch[0].sort_priority }, { "game.panel.conveyor_belt_2.x", &game.panel.conveyor_belt[1].x }, { "game.panel.conveyor_belt_2.y", &game.panel.conveyor_belt[1].y }, { "game.panel.conveyor_belt_2.tile_size", &game.panel.conveyor_belt[1].size }, { "game.panel.conveyor_belt_2.draw_masked", &game.panel.conveyor_belt[1].draw_masked }, { "game.panel.conveyor_belt_2.draw_order", &game.panel.conveyor_belt[1].sort_priority }, { "game.panel.conveyor_belt_2_switch.x", &game.panel.conveyor_belt_switch[1].x }, { "game.panel.conveyor_belt_2_switch.y", &game.panel.conveyor_belt_switch[1].y }, { "game.panel.conveyor_belt_2_switch.tile_size", &game.panel.conveyor_belt_switch[1].size }, { "game.panel.conveyor_belt_2_switch.draw_masked", &game.panel.conveyor_belt_switch[1].draw_masked }, { "game.panel.conveyor_belt_2_switch.draw_order", &game.panel.conveyor_belt_switch[1].sort_priority }, { "game.panel.conveyor_belt_3.x", &game.panel.conveyor_belt[2].x }, { "game.panel.conveyor_belt_3.y", &game.panel.conveyor_belt[2].y }, { "game.panel.conveyor_belt_3.tile_size", &game.panel.conveyor_belt[2].size }, { "game.panel.conveyor_belt_3.draw_masked", &game.panel.conveyor_belt[2].draw_masked }, { "game.panel.conveyor_belt_3.draw_order", &game.panel.conveyor_belt[2].sort_priority }, { "game.panel.conveyor_belt_3_switch.x", &game.panel.conveyor_belt_switch[2].x }, { "game.panel.conveyor_belt_3_switch.y", &game.panel.conveyor_belt_switch[2].y }, { "game.panel.conveyor_belt_3_switch.tile_size", &game.panel.conveyor_belt_switch[2].size }, { "game.panel.conveyor_belt_3_switch.draw_masked", &game.panel.conveyor_belt_switch[2].draw_masked }, { "game.panel.conveyor_belt_3_switch.draw_order", &game.panel.conveyor_belt_switch[2].sort_priority }, { "game.panel.conveyor_belt_4.x", &game.panel.conveyor_belt[3].x }, { "game.panel.conveyor_belt_4.y", &game.panel.conveyor_belt[3].y }, { "game.panel.conveyor_belt_4.tile_size", &game.panel.conveyor_belt[3].size }, { "game.panel.conveyor_belt_4.draw_masked", &game.panel.conveyor_belt[3].draw_masked }, { "game.panel.conveyor_belt_4.draw_order", &game.panel.conveyor_belt[3].sort_priority }, { "game.panel.conveyor_belt_4_switch.x", &game.panel.conveyor_belt_switch[3].x }, { "game.panel.conveyor_belt_4_switch.y", &game.panel.conveyor_belt_switch[3].y }, { "game.panel.conveyor_belt_4_switch.tile_size", &game.panel.conveyor_belt_switch[3].size }, { "game.panel.conveyor_belt_4_switch.draw_masked", &game.panel.conveyor_belt_switch[3].draw_masked }, { "game.panel.conveyor_belt_4_switch.draw_order", &game.panel.conveyor_belt_switch[3].sort_priority }, { "game.panel.magic_wall.x", &game.panel.magic_wall.x }, { "game.panel.magic_wall.y", &game.panel.magic_wall.y }, { "game.panel.magic_wall.tile_size", &game.panel.magic_wall.size }, { "game.panel.magic_wall.draw_masked", &game.panel.magic_wall.draw_masked }, { "game.panel.magic_wall.draw_order", &game.panel.magic_wall.sort_priority }, { "game.panel.magic_wall_time.x", &game.panel.magic_wall_time.x }, { "game.panel.magic_wall_time.y", &game.panel.magic_wall_time.y }, { "game.panel.magic_wall_time.align", &game.panel.magic_wall_time.align }, { "game.panel.magic_wall_time.valign", &game.panel.magic_wall_time.valign }, { "game.panel.magic_wall_time.digits", &game.panel.magic_wall_time.size }, { "game.panel.magic_wall_time.font", &game.panel.magic_wall_time.font }, { "game.panel.magic_wall_time.draw_masked", &game.panel.magic_wall_time.draw_masked }, { "game.panel.magic_wall_time.draw_order", &game.panel.magic_wall_time.sort_priority }, { "game.panel.gravity_state.x", &game.panel.gravity_state.x }, { "game.panel.gravity_state.y", &game.panel.gravity_state.y }, { "game.panel.gravity_state.align", &game.panel.gravity_state.align }, { "game.panel.gravity_state.valign", &game.panel.gravity_state.valign }, { "game.panel.gravity_state.chars", &game.panel.gravity_state.size }, { "game.panel.gravity_state.font", &game.panel.gravity_state.font }, { "game.panel.gravity_state.font_active", &game.panel.gravity_state.font_alt }, { "game.panel.gravity_state.draw_masked", &game.panel.gravity_state.draw_masked }, { "game.panel.gravity_state.draw_order", &game.panel.gravity_state.sort_priority }, { "game.panel.graphic_1.x", &game.panel.graphic[0].x }, { "game.panel.graphic_1.y", &game.panel.graphic[0].y }, { "game.panel.graphic_1.draw_masked", &game.panel.graphic[0].draw_masked }, { "game.panel.graphic_1.draw_order", &game.panel.graphic[0].sort_priority }, { "game.panel.graphic_2.x", &game.panel.graphic[1].x }, { "game.panel.graphic_2.y", &game.panel.graphic[1].y }, { "game.panel.graphic_2.draw_masked", &game.panel.graphic[1].draw_masked }, { "game.panel.graphic_2.draw_order", &game.panel.graphic[1].sort_priority }, { "game.panel.graphic_3.x", &game.panel.graphic[2].x }, { "game.panel.graphic_3.y", &game.panel.graphic[2].y }, { "game.panel.graphic_3.draw_masked", &game.panel.graphic[2].draw_masked }, { "game.panel.graphic_3.draw_order", &game.panel.graphic[2].sort_priority }, { "game.panel.graphic_4.x", &game.panel.graphic[3].x }, { "game.panel.graphic_4.y", &game.panel.graphic[3].y }, { "game.panel.graphic_4.draw_masked", &game.panel.graphic[3].draw_masked }, { "game.panel.graphic_4.draw_order", &game.panel.graphic[3].sort_priority }, { "game.panel.graphic_5.x", &game.panel.graphic[4].x }, { "game.panel.graphic_5.y", &game.panel.graphic[4].y }, { "game.panel.graphic_5.draw_masked", &game.panel.graphic[4].draw_masked }, { "game.panel.graphic_5.draw_order", &game.panel.graphic[4].sort_priority }, { "game.panel.graphic_6.x", &game.panel.graphic[5].x }, { "game.panel.graphic_6.y", &game.panel.graphic[5].y }, { "game.panel.graphic_6.draw_masked", &game.panel.graphic[5].draw_masked }, { "game.panel.graphic_6.draw_order", &game.panel.graphic[5].sort_priority }, { "game.panel.graphic_7.x", &game.panel.graphic[6].x }, { "game.panel.graphic_7.y", &game.panel.graphic[6].y }, { "game.panel.graphic_7.draw_masked", &game.panel.graphic[6].draw_masked }, { "game.panel.graphic_7.draw_order", &game.panel.graphic[6].sort_priority }, { "game.panel.graphic_8.x", &game.panel.graphic[7].x }, { "game.panel.graphic_8.y", &game.panel.graphic[7].y }, { "game.panel.graphic_8.draw_masked", &game.panel.graphic[7].draw_masked }, { "game.panel.graphic_8.draw_order", &game.panel.graphic[7].sort_priority }, { "game.panel.element_1.x", &game.panel.element[0].x }, { "game.panel.element_1.y", &game.panel.element[0].y }, { "game.panel.element_1.tile_size", &game.panel.element[0].size }, { "game.panel.element_1.element", &game.panel.element[0].id }, { "game.panel.element_1.draw_masked", &game.panel.element[0].draw_masked }, { "game.panel.element_1.draw_order", &game.panel.element[0].sort_priority }, { "game.panel.element_1_count.x", &game.panel.element_count[0].x }, { "game.panel.element_1_count.y", &game.panel.element_count[0].y }, { "game.panel.element_1_count.align", &game.panel.element_count[0].align }, { "game.panel.element_1_count.valign", &game.panel.element_count[0].valign }, { "game.panel.element_1_count.digits", &game.panel.element_count[0].size }, { "game.panel.element_1_count.font", &game.panel.element_count[0].font }, { "game.panel.element_1_count.element", &game.panel.element_count[0].id }, { "game.panel.element_1_count.draw_masked", &game.panel.element_count[0].draw_masked }, { "game.panel.element_1_count.draw_order", &game.panel.element_count[0].sort_priority }, { "game.panel.element_2.x", &game.panel.element[1].x }, { "game.panel.element_2.y", &game.panel.element[1].y }, { "game.panel.element_2.tile_size", &game.panel.element[1].size }, { "game.panel.element_2.element", &game.panel.element[1].id }, { "game.panel.element_2.draw_masked", &game.panel.element[1].draw_masked }, { "game.panel.element_2.draw_order", &game.panel.element[1].sort_priority }, { "game.panel.element_2_count.x", &game.panel.element_count[1].x }, { "game.panel.element_2_count.y", &game.panel.element_count[1].y }, { "game.panel.element_2_count.align", &game.panel.element_count[1].align }, { "game.panel.element_2_count.valign", &game.panel.element_count[1].valign }, { "game.panel.element_2_count.digits", &game.panel.element_count[1].size }, { "game.panel.element_2_count.font", &game.panel.element_count[1].font }, { "game.panel.element_2_count.element", &game.panel.element_count[1].id }, { "game.panel.element_2_count.draw_masked", &game.panel.element_count[1].draw_masked }, { "game.panel.element_2_count.draw_order", &game.panel.element_count[1].sort_priority }, { "game.panel.element_3.x", &game.panel.element[2].x }, { "game.panel.element_3.y", &game.panel.element[2].y }, { "game.panel.element_3.tile_size", &game.panel.element[2].size }, { "game.panel.element_3.element", &game.panel.element[2].id }, { "game.panel.element_3.draw_masked", &game.panel.element[2].draw_masked }, { "game.panel.element_3.draw_order", &game.panel.element[2].sort_priority }, { "game.panel.element_3_count.x", &game.panel.element_count[2].x }, { "game.panel.element_3_count.y", &game.panel.element_count[2].y }, { "game.panel.element_3_count.align", &game.panel.element_count[2].align }, { "game.panel.element_3_count.valign", &game.panel.element_count[2].valign }, { "game.panel.element_3_count.digits", &game.panel.element_count[2].size }, { "game.panel.element_3_count.font", &game.panel.element_count[2].font }, { "game.panel.element_3_count.element", &game.panel.element_count[2].id }, { "game.panel.element_3_count.draw_masked", &game.panel.element_count[2].draw_masked }, { "game.panel.element_3_count.draw_order", &game.panel.element_count[2].sort_priority }, { "game.panel.element_4.x", &game.panel.element[3].x }, { "game.panel.element_4.y", &game.panel.element[3].y }, { "game.panel.element_4.tile_size", &game.panel.element[3].size }, { "game.panel.element_4.element", &game.panel.element[3].id }, { "game.panel.element_4.draw_masked", &game.panel.element[3].draw_masked }, { "game.panel.element_4.draw_order", &game.panel.element[3].sort_priority }, { "game.panel.element_4_count.x", &game.panel.element_count[3].x }, { "game.panel.element_4_count.y", &game.panel.element_count[3].y }, { "game.panel.element_4_count.align", &game.panel.element_count[3].align }, { "game.panel.element_4_count.valign", &game.panel.element_count[3].valign }, { "game.panel.element_4_count.digits", &game.panel.element_count[3].size }, { "game.panel.element_4_count.font", &game.panel.element_count[3].font }, { "game.panel.element_4_count.element", &game.panel.element_count[3].id }, { "game.panel.element_4_count.draw_masked", &game.panel.element_count[3].draw_masked }, { "game.panel.element_4_count.draw_order", &game.panel.element_count[3].sort_priority }, { "game.panel.element_5.x", &game.panel.element[4].x }, { "game.panel.element_5.y", &game.panel.element[4].y }, { "game.panel.element_5.tile_size", &game.panel.element[4].size }, { "game.panel.element_5.element", &game.panel.element[4].id }, { "game.panel.element_5.draw_masked", &game.panel.element[4].draw_masked }, { "game.panel.element_5.draw_order", &game.panel.element[4].sort_priority }, { "game.panel.element_5_count.x", &game.panel.element_count[4].x }, { "game.panel.element_5_count.y", &game.panel.element_count[4].y }, { "game.panel.element_5_count.align", &game.panel.element_count[4].align }, { "game.panel.element_5_count.valign", &game.panel.element_count[4].valign }, { "game.panel.element_5_count.digits", &game.panel.element_count[4].size }, { "game.panel.element_5_count.font", &game.panel.element_count[4].font }, { "game.panel.element_5_count.element", &game.panel.element_count[4].id }, { "game.panel.element_5_count.draw_masked", &game.panel.element_count[4].draw_masked }, { "game.panel.element_5_count.draw_order", &game.panel.element_count[4].sort_priority }, { "game.panel.element_6.x", &game.panel.element[5].x }, { "game.panel.element_6.y", &game.panel.element[5].y }, { "game.panel.element_6.tile_size", &game.panel.element[5].size }, { "game.panel.element_6.element", &game.panel.element[5].id }, { "game.panel.element_6.draw_masked", &game.panel.element[5].draw_masked }, { "game.panel.element_6.draw_order", &game.panel.element[5].sort_priority }, { "game.panel.element_6_count.x", &game.panel.element_count[5].x }, { "game.panel.element_6_count.y", &game.panel.element_count[5].y }, { "game.panel.element_6_count.align", &game.panel.element_count[5].align }, { "game.panel.element_6_count.valign", &game.panel.element_count[5].valign }, { "game.panel.element_6_count.digits", &game.panel.element_count[5].size }, { "game.panel.element_6_count.font", &game.panel.element_count[5].font }, { "game.panel.element_6_count.element", &game.panel.element_count[5].id }, { "game.panel.element_6_count.draw_masked", &game.panel.element_count[5].draw_masked }, { "game.panel.element_6_count.draw_order", &game.panel.element_count[5].sort_priority }, { "game.panel.element_7.x", &game.panel.element[6].x }, { "game.panel.element_7.y", &game.panel.element[6].y }, { "game.panel.element_7.tile_size", &game.panel.element[6].size }, { "game.panel.element_7.element", &game.panel.element[6].id }, { "game.panel.element_7.draw_masked", &game.panel.element[6].draw_masked }, { "game.panel.element_7.draw_order", &game.panel.element[6].sort_priority }, { "game.panel.element_7_count.x", &game.panel.element_count[6].x }, { "game.panel.element_7_count.y", &game.panel.element_count[6].y }, { "game.panel.element_7_count.align", &game.panel.element_count[6].align }, { "game.panel.element_7_count.valign", &game.panel.element_count[6].valign }, { "game.panel.element_7_count.digits", &game.panel.element_count[6].size }, { "game.panel.element_7_count.font", &game.panel.element_count[6].font }, { "game.panel.element_7_count.element", &game.panel.element_count[6].id }, { "game.panel.element_7_count.draw_masked", &game.panel.element_count[6].draw_masked }, { "game.panel.element_7_count.draw_order", &game.panel.element_count[6].sort_priority }, { "game.panel.element_8.x", &game.panel.element[7].x }, { "game.panel.element_8.y", &game.panel.element[7].y }, { "game.panel.element_8.tile_size", &game.panel.element[7].size }, { "game.panel.element_8.element", &game.panel.element[7].id }, { "game.panel.element_8.draw_masked", &game.panel.element[7].draw_masked }, { "game.panel.element_8.draw_order", &game.panel.element[7].sort_priority }, { "game.panel.element_8_count.x", &game.panel.element_count[7].x }, { "game.panel.element_8_count.y", &game.panel.element_count[7].y }, { "game.panel.element_8_count.align", &game.panel.element_count[7].align }, { "game.panel.element_8_count.valign", &game.panel.element_count[7].valign }, { "game.panel.element_8_count.digits", &game.panel.element_count[7].size }, { "game.panel.element_8_count.font", &game.panel.element_count[7].font }, { "game.panel.element_8_count.element", &game.panel.element_count[7].id }, { "game.panel.element_8_count.draw_masked", &game.panel.element_count[7].draw_masked }, { "game.panel.element_8_count.draw_order", &game.panel.element_count[7].sort_priority }, { "game.panel.ce_score_1.x", &game.panel.ce_score[0].x }, { "game.panel.ce_score_1.y", &game.panel.ce_score[0].y }, { "game.panel.ce_score_1.align", &game.panel.ce_score[0].align }, { "game.panel.ce_score_1.valign", &game.panel.ce_score[0].valign }, { "game.panel.ce_score_1.digits", &game.panel.ce_score[0].size }, { "game.panel.ce_score_1.font", &game.panel.ce_score[0].font }, { "game.panel.ce_score_1.element", &game.panel.ce_score[0].id }, { "game.panel.ce_score_1.draw_masked", &game.panel.ce_score[0].draw_masked }, { "game.panel.ce_score_1.draw_order", &game.panel.ce_score[0].sort_priority }, { "game.panel.ce_score_1_element.x", &game.panel.ce_score_element[0].x }, { "game.panel.ce_score_1_element.y", &game.panel.ce_score_element[0].y }, { "game.panel.ce_score_1_element.tile_size", &game.panel.ce_score_element[0].size }, { "game.panel.ce_score_1_element.element", &game.panel.ce_score_element[0].id }, { "game.panel.ce_score_1_element.draw_masked", &game.panel.ce_score_element[0].draw_masked }, { "game.panel.ce_score_1_element.draw_order", &game.panel.ce_score_element[0].sort_priority }, { "game.panel.ce_score_2.x", &game.panel.ce_score[1].x }, { "game.panel.ce_score_2.y", &game.panel.ce_score[1].y }, { "game.panel.ce_score_2.align", &game.panel.ce_score[1].align }, { "game.panel.ce_score_2.valign", &game.panel.ce_score[1].valign }, { "game.panel.ce_score_2.digits", &game.panel.ce_score[1].size }, { "game.panel.ce_score_2.font", &game.panel.ce_score[1].font }, { "game.panel.ce_score_2.element", &game.panel.ce_score[1].id }, { "game.panel.ce_score_2.draw_masked", &game.panel.ce_score[1].draw_masked }, { "game.panel.ce_score_2.draw_order", &game.panel.ce_score[1].sort_priority }, { "game.panel.ce_score_2_element.x", &game.panel.ce_score_element[1].x }, { "game.panel.ce_score_2_element.y", &game.panel.ce_score_element[1].y }, { "game.panel.ce_score_2_element.tile_size", &game.panel.ce_score_element[1].size }, { "game.panel.ce_score_2_element.element", &game.panel.ce_score_element[1].id }, { "game.panel.ce_score_2_element.draw_masked", &game.panel.ce_score_element[1].draw_masked }, { "game.panel.ce_score_2_element.draw_order", &game.panel.ce_score_element[1].sort_priority }, { "game.panel.ce_score_3.x", &game.panel.ce_score[2].x }, { "game.panel.ce_score_3.y", &game.panel.ce_score[2].y }, { "game.panel.ce_score_3.align", &game.panel.ce_score[2].align }, { "game.panel.ce_score_3.valign", &game.panel.ce_score[2].valign }, { "game.panel.ce_score_3.digits", &game.panel.ce_score[2].size }, { "game.panel.ce_score_3.font", &game.panel.ce_score[2].font }, { "game.panel.ce_score_3.element", &game.panel.ce_score[2].id }, { "game.panel.ce_score_3.draw_masked", &game.panel.ce_score[2].draw_masked }, { "game.panel.ce_score_3.draw_order", &game.panel.ce_score[2].sort_priority }, { "game.panel.ce_score_3_element.x", &game.panel.ce_score_element[2].x }, { "game.panel.ce_score_3_element.y", &game.panel.ce_score_element[2].y }, { "game.panel.ce_score_3_element.tile_size", &game.panel.ce_score_element[2].size }, { "game.panel.ce_score_3_element.element", &game.panel.ce_score_element[2].id }, { "game.panel.ce_score_3_element.draw_masked", &game.panel.ce_score_element[2].draw_masked }, { "game.panel.ce_score_3_element.draw_order", &game.panel.ce_score_element[2].sort_priority }, { "game.panel.ce_score_4.x", &game.panel.ce_score[3].x }, { "game.panel.ce_score_4.y", &game.panel.ce_score[3].y }, { "game.panel.ce_score_4.align", &game.panel.ce_score[3].align }, { "game.panel.ce_score_4.valign", &game.panel.ce_score[3].valign }, { "game.panel.ce_score_4.digits", &game.panel.ce_score[3].size }, { "game.panel.ce_score_4.font", &game.panel.ce_score[3].font }, { "game.panel.ce_score_4.element", &game.panel.ce_score[3].id }, { "game.panel.ce_score_4.draw_masked", &game.panel.ce_score[3].draw_masked }, { "game.panel.ce_score_4.draw_order", &game.panel.ce_score[3].sort_priority }, { "game.panel.ce_score_4_element.x", &game.panel.ce_score_element[3].x }, { "game.panel.ce_score_4_element.y", &game.panel.ce_score_element[3].y }, { "game.panel.ce_score_4_element.tile_size", &game.panel.ce_score_element[3].size }, { "game.panel.ce_score_4_element.element", &game.panel.ce_score_element[3].id }, { "game.panel.ce_score_4_element.draw_masked", &game.panel.ce_score_element[3].draw_masked }, { "game.panel.ce_score_4_element.draw_order", &game.panel.ce_score_element[3].sort_priority }, { "game.panel.ce_score_5.x", &game.panel.ce_score[4].x }, { "game.panel.ce_score_5.y", &game.panel.ce_score[4].y }, { "game.panel.ce_score_5.align", &game.panel.ce_score[4].align }, { "game.panel.ce_score_5.valign", &game.panel.ce_score[4].valign }, { "game.panel.ce_score_5.digits", &game.panel.ce_score[4].size }, { "game.panel.ce_score_5.font", &game.panel.ce_score[4].font }, { "game.panel.ce_score_5.element", &game.panel.ce_score[4].id }, { "game.panel.ce_score_5.draw_masked", &game.panel.ce_score[4].draw_masked }, { "game.panel.ce_score_5.draw_order", &game.panel.ce_score[4].sort_priority }, { "game.panel.ce_score_5_element.x", &game.panel.ce_score_element[4].x }, { "game.panel.ce_score_5_element.y", &game.panel.ce_score_element[4].y }, { "game.panel.ce_score_5_element.tile_size", &game.panel.ce_score_element[4].size }, { "game.panel.ce_score_5_element.element", &game.panel.ce_score_element[4].id }, { "game.panel.ce_score_5_element.draw_masked", &game.panel.ce_score_element[4].draw_masked }, { "game.panel.ce_score_5_element.draw_order", &game.panel.ce_score_element[4].sort_priority }, { "game.panel.ce_score_6.x", &game.panel.ce_score[5].x }, { "game.panel.ce_score_6.y", &game.panel.ce_score[5].y }, { "game.panel.ce_score_6.align", &game.panel.ce_score[5].align }, { "game.panel.ce_score_6.valign", &game.panel.ce_score[5].valign }, { "game.panel.ce_score_6.digits", &game.panel.ce_score[5].size }, { "game.panel.ce_score_6.font", &game.panel.ce_score[5].font }, { "game.panel.ce_score_6.element", &game.panel.ce_score[5].id }, { "game.panel.ce_score_6.draw_masked", &game.panel.ce_score[5].draw_masked }, { "game.panel.ce_score_6.draw_order", &game.panel.ce_score[5].sort_priority }, { "game.panel.ce_score_6_element.x", &game.panel.ce_score_element[5].x }, { "game.panel.ce_score_6_element.y", &game.panel.ce_score_element[5].y }, { "game.panel.ce_score_6_element.tile_size", &game.panel.ce_score_element[5].size }, { "game.panel.ce_score_6_element.element", &game.panel.ce_score_element[5].id }, { "game.panel.ce_score_6_element.draw_masked", &game.panel.ce_score_element[5].draw_masked }, { "game.panel.ce_score_6_element.draw_order", &game.panel.ce_score_element[5].sort_priority }, { "game.panel.ce_score_7.x", &game.panel.ce_score[6].x }, { "game.panel.ce_score_7.y", &game.panel.ce_score[6].y }, { "game.panel.ce_score_7.align", &game.panel.ce_score[6].align }, { "game.panel.ce_score_7.valign", &game.panel.ce_score[6].valign }, { "game.panel.ce_score_7.digits", &game.panel.ce_score[6].size }, { "game.panel.ce_score_7.font", &game.panel.ce_score[6].font }, { "game.panel.ce_score_7.element", &game.panel.ce_score[6].id }, { "game.panel.ce_score_7.draw_masked", &game.panel.ce_score[6].draw_masked }, { "game.panel.ce_score_7.draw_order", &game.panel.ce_score[6].sort_priority }, { "game.panel.ce_score_7_element.x", &game.panel.ce_score_element[6].x }, { "game.panel.ce_score_7_element.y", &game.panel.ce_score_element[6].y }, { "game.panel.ce_score_7_element.tile_size", &game.panel.ce_score_element[6].size }, { "game.panel.ce_score_7_element.element", &game.panel.ce_score_element[6].id }, { "game.panel.ce_score_7_element.draw_masked", &game.panel.ce_score_element[6].draw_masked }, { "game.panel.ce_score_7_element.draw_order", &game.panel.ce_score_element[6].sort_priority }, { "game.panel.ce_score_8.x", &game.panel.ce_score[7].x }, { "game.panel.ce_score_8.y", &game.panel.ce_score[7].y }, { "game.panel.ce_score_8.align", &game.panel.ce_score[7].align }, { "game.panel.ce_score_8.valign", &game.panel.ce_score[7].valign }, { "game.panel.ce_score_8.digits", &game.panel.ce_score[7].size }, { "game.panel.ce_score_8.font", &game.panel.ce_score[7].font }, { "game.panel.ce_score_8.element", &game.panel.ce_score[7].id }, { "game.panel.ce_score_8.draw_masked", &game.panel.ce_score[7].draw_masked }, { "game.panel.ce_score_8.draw_order", &game.panel.ce_score[7].sort_priority }, { "game.panel.ce_score_8_element.x", &game.panel.ce_score_element[7].x }, { "game.panel.ce_score_8_element.y", &game.panel.ce_score_element[7].y }, { "game.panel.ce_score_8_element.tile_size", &game.panel.ce_score_element[7].size }, { "game.panel.ce_score_8_element.element", &game.panel.ce_score_element[7].id }, { "game.panel.ce_score_8_element.draw_masked", &game.panel.ce_score_element[7].draw_masked }, { "game.panel.ce_score_8_element.draw_order", &game.panel.ce_score_element[7].sort_priority }, { "game.panel.player_name.x", &game.panel.player_name.x }, { "game.panel.player_name.y", &game.panel.player_name.y }, { "game.panel.player_name.align", &game.panel.player_name.align }, { "game.panel.player_name.valign", &game.panel.player_name.valign }, { "game.panel.player_name.chars", &game.panel.player_name.size }, { "game.panel.player_name.font", &game.panel.player_name.font }, { "game.panel.player_name.draw_masked", &game.panel.player_name.draw_masked }, { "game.panel.player_name.draw_order", &game.panel.player_name.sort_priority }, { "game.panel.level_name.x", &game.panel.level_name.x }, { "game.panel.level_name.y", &game.panel.level_name.y }, { "game.panel.level_name.align", &game.panel.level_name.align }, { "game.panel.level_name.valign", &game.panel.level_name.valign }, { "game.panel.level_name.chars", &game.panel.level_name.size }, { "game.panel.level_name.font", &game.panel.level_name.font }, { "game.panel.level_name.draw_masked", &game.panel.level_name.draw_masked }, { "game.panel.level_name.draw_order", &game.panel.level_name.sort_priority }, { "game.panel.level_author.x", &game.panel.level_author.x }, { "game.panel.level_author.y", &game.panel.level_author.y }, { "game.panel.level_author.align", &game.panel.level_author.align }, { "game.panel.level_author.valign", &game.panel.level_author.valign }, { "game.panel.level_author.chars", &game.panel.level_author.size }, { "game.panel.level_author.font", &game.panel.level_author.font }, { "game.panel.level_author.draw_masked", &game.panel.level_author.draw_masked }, { "game.panel.level_author.draw_order", &game.panel.level_author.sort_priority }, { "game.button.stop.x", &game.button.stop.x }, { "game.button.stop.y", &game.button.stop.y }, { "game.button.pause.x", &game.button.pause.x }, { "game.button.pause.y", &game.button.pause.y }, { "game.button.play.x", &game.button.play.x }, { "game.button.play.y", &game.button.play.y }, { "game.button.sound_music.x", &game.button.sound_music.x }, { "game.button.sound_music.y", &game.button.sound_music.y }, { "game.button.sound_loops.x", &game.button.sound_loops.x }, { "game.button.sound_loops.y", &game.button.sound_loops.y }, { "game.button.sound_simple.x", &game.button.sound_simple.x }, { "game.button.sound_simple.y", &game.button.sound_simple.y }, { "game.forced_scroll_delay_value", &game.forced_scroll_delay_value }, { "game.use_native_emc_graphics_engine", &game.use_native_emc_graphics_engine }, { "game.use_native_sp_graphics_engine", &game.use_native_sp_graphics_engine }, { "game.use_masked_pushing", &game.use_masked_pushing }, { "[player].boring_delay_fixed", &game.player_boring_delay_fixed }, { "[player].boring_delay_random", &game.player_boring_delay_random }, { "[player].sleeping_delay_fixed", &game.player_sleeping_delay_fixed }, { "[player].sleeping_delay_random", &game.player_sleeping_delay_random }, { "viewport.window.width", &viewport.window.width }, { "viewport.window.height", &viewport.window.height }, { "viewport.playfield.x", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.playfield.y", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.playfield.width", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].width }, { "viewport.playfield.height", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].height }, { "viewport.playfield.border_size", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].border_size }, { "viewport.playfield.MAIN.x", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.playfield.MAIN.y", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.playfield.MAIN.width", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].width }, { "viewport.playfield.MAIN.height", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].height }, { "viewport.playfield.MAIN.border_size", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].border_size }, { "viewport.playfield.PLAYING.x", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.playfield.PLAYING.y", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.playfield.PLAYING.width", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].width }, { "viewport.playfield.PLAYING.height", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].height }, { "viewport.playfield.PLAYING.border_size", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].border_size }, { "viewport.playfield.EDITOR.x", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.playfield.EDITOR.y", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].y }, { "viewport.playfield.EDITOR.width", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].width }, { "viewport.playfield.EDITOR.height", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].height }, { "viewport.playfield.EDITOR.border_size", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].border_size }, { "viewport.door_1.x", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.door_1.y", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.door_1.MAIN.x", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.door_1.MAIN.y", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.door_1.PLAYING.x", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.door_1.PLAYING.y", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.door_1.EDITOR.x", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.door_1.EDITOR.y", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].y }, { "viewport.door_2.x", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.door_2.y", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.door_2.MAIN.x", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.door_2.MAIN.y", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.door_2.PLAYING.x", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.door_2.PLAYING.y", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.door_2.EDITOR.x", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.door_2.EDITOR.y", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].y }, { NULL, NULL }, }; #endif /* CONF_VAR_C */ rocksndiamonds-3.3.0.1+dfsg1/src/netserv.h0000644000175000017500000000262110471550161017255 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * netserv.h * ***********************************************************/ #ifndef NETSERV_H #define NETSERV_H #include "main.h" #define DEFAULT_SERVER_PORT 19504 #define PROTOCOL_VERSION_1 1 #define PROTOCOL_VERSION_2 2 #define PROTOCOL_VERSION_3 0 #define OP_PROTOCOL_VERSION 1 #define OP_BAD_PROTOCOL_VERSION 2 #define OP_YOUR_NUMBER 3 #define OP_NUMBER_WANTED 4 #define OP_PLAYER_NAME 5 #define OP_PLAYER_CONNECTED 6 #define OP_PLAYER_DISCONNECTED 7 #define OP_START_PLAYING 8 #define OP_PAUSE_PLAYING 9 #define OP_CONTINUE_PLAYING 10 #define OP_STOP_PLAYING 11 #define OP_MOVE_PLAYER 12 #define OP_BROADCAST_MESSAGE 13 #define MAX_BUFFER_SIZE 4096 #if defined(TARGET_SDL) int NetworkServerThread(void *); #endif void NetworkServer(int, int); #endif rocksndiamonds-3.3.0.1+dfsg1/src/game_em/0000755000175000017500000000000011403523060017001 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/src/game_em/synchro_1.c0000644000175000017500000006756110521137006021072 0ustar dimkadimka/* first part of synchro. * * game logic for players. * * large switch statement for tiles the player interacts with. */ #include "main_em.h" #if 0 extern int centered_player_nr; #endif #define USE_CHANGED_ACID_STUFF 1 extern boolean checkIfAllPlayersFitToScreen(); static void check_player(struct PLAYER *); static void kill_player(struct PLAYER *); static boolean player_digfield(struct PLAYER *, int, int); static boolean player_killed(struct PLAYER *); void synchro_1(void) { #if 1 int start_check_nr; int i; game_em.any_player_moving = FALSE; /* must test for death and actually kill separately */ for (i = 0; i < MAX_PLAYERS; i++) { boolean ply_kill = player_killed(&ply[i]); if (ply[i].alive && ply_kill) kill_player(&ply[i]); } #else /* must test for death and actually kill separately */ boolean ply1_kill = player_killed(&ply1); boolean ply2_kill = player_killed(&ply2); if (ply1.alive && ply1_kill) kill_player(&ply1); if (ply2.alive && ply2_kill) kill_player(&ply2); #endif #if 0 ply1.alive = 1; /* debugging */ #endif #if 1 for (i = 0; i < MAX_PLAYERS; i++) { ply[i].oldx = ply[i].x; ply[i].oldy = ply[i].y; ply[i].anim = SPR_still; } start_check_nr = (RandomEM & 128 ? 0 : 1) * 2 + (RandomEM & 256 ? 0 : 1); for (i = 0; i < MAX_PLAYERS; i++) { int check_nr = (start_check_nr + i) % MAX_PLAYERS; if (ply[check_nr].alive) check_player(&ply[check_nr]); } for (i = 0; i < MAX_PLAYERS; i++) { if (!ply[i].alive) continue; if (Cave[ply[i].oldy][ply[i].oldx] == Zplayer) { Cave[ply[i].oldy][ply[i].oldx] = Xblank; Next[ply[i].oldy][ply[i].oldx] = Xblank; } if (Cave[ply[i].y][ply[i].x] == Xblank) { Cave[ply[i].y][ply[i].x] = Zplayer; Next[ply[i].y][ply[i].x] = Zplayer; } } #else ply1.oldx = ply1.x; ply1.oldy = ply1.y; ply1.anim = SPR_still; ply2.oldx = ply2.x; ply2.oldy = ply2.y; ply2.anim = SPR_still; if (RandomEM & 256) { if (ply1.alive) check_player(&ply1); if (ply2.alive) check_player(&ply2); } else { if (ply2.alive) check_player(&ply2); if (ply1.alive) check_player(&ply1); } if (ply1.alive) { if (Cave[ply1.oldy][ply1.oldx] == Zplayer) { Cave[ply1.oldy][ply1.oldx] = Xblank; Next[ply1.oldy][ply1.oldx] = Xblank; } if (Cave[ply1.y][ply1.x] == Xblank) { Cave[ply1.y][ply1.x] = Zplayer; Next[ply1.y][ply1.x] = Zplayer; } } if (ply2.alive) { if (Cave[ply2.oldy][ply2.oldx] == Zplayer) { Cave[ply2.oldy][ply2.oldx] = Xblank; Next[ply2.oldy][ply2.oldx] = Xblank; } if (Cave[ply2.y][ply2.x] == Xblank) { Cave[ply2.y][ply2.x] = Zplayer; Next[ply2.y][ply2.x] = Zplayer; } } #endif } static boolean player_killed(struct PLAYER *ply) { int x = ply->x; int y = ply->y; #if 0 printf("::: %d: %d, %d\n", ply->num, x, y); #endif if (!ply->alive) return FALSE; #if 1 if (lev.killed_out_of_time && setup.time_limit) return TRUE; #else if (lev.time_initial > 0 && lev.time == 0 && setup.time_limit) return TRUE; #endif switch(Cave[y-1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x+1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y+1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x-1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: case Xdynamite_1: case Xdynamite_2: case Xdynamite_3: case Xdynamite_4: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif return FALSE; } return TRUE; } static void kill_player(struct PLAYER *ply) { int x = ply->x; int y = ply->y; ply->alive = 0; switch(Cave[y-1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y-1][x] = Xboom_bug; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y-1][x] = Xboom_bomb; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; } switch(Cave[y][x+1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x+1] = Xboom_bug; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x+1] = Xboom_bomb; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; } switch(Cave[y+1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y+1][x] = Xboom_bug; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y+1][x] = Xboom_bomb; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; } switch(Cave[y][x-1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x-1] = Xboom_bug; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x-1] = Xboom_bomb; #if 0 #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif #endif break; } switch(Cave[y][x]) { case Xexit_1: case Xexit_2: case Xexit_3: lev.exit_x = x; lev.exit_y = y; play_element_sound(x, y, SAMPLE_exit_leave, Xexit_1); break; default: #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Zplayer); #endif play_element_sound(x, y, SAMPLE_die, Zplayer); break; } switch(Cave[y][x]) { #if USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: break; #endif default: Cave[y][x] = Xboom_1; Boom[y][x] = Xblank; break; } } static void check_player(struct PLAYER *ply) { int oldx = ply->x; int oldy = ply->y; int x = oldx; int y = oldy; int anim = 0; int dx = 0, dy = 0; game_em.last_player_direction[ply->num] = MV_NONE; #if 0 printf("::: up == %d, down == %d, left == %d, right == %d, fire == %d [spin == %d, stick == %d]\n", ply->joy_n, ply->joy_s, ply->joy_w, ply->joy_e, ply->joy_fire, ply->joy_spin, ply->joy_stick); #endif #if 1 if (ply->joy_w) /* west */ { x--; dx = -1; anim = 3; } else if (ply->joy_e) /* east */ { x++; dx = 1; anim = 1; } if (ply->joy_n) /* north */ { y--; dy = -1; anim = 0; } else if (ply->joy_s) /* south */ { y++; dy = 1; anim = 2; } #else if ((ply->joy_spin = !ply->joy_spin)) { if (ply->joy_n) /* north */ { y--; dy = -1; anim = 0; } else if (ply->joy_e) /* east */ { x++; dx = 1; anim = 1; } else if (ply->joy_s) /* south */ { y++; dy = 1; anim = 2; } else if (ply->joy_w) /* west */ { x--; dx = -1; anim = 3; } } else { if (ply->joy_w) /* west */ { x--; dx = -1; anim = 3; } else if (ply->joy_s) /* south */ { y++; dy = 1; anim = 2; } else if (ply->joy_e) /* east */ { x++; dx = 1; anim = 1; } else if (ply->joy_n) /* north */ { y--; dy = -1; anim = 0; } } #endif if (dx || dy) { int oldx = ply->x; int oldy = ply->y; int x = oldx + dx; int y = oldy + dy; boolean players_visible_before_move; boolean players_visible_after_move; boolean can_move; players_visible_before_move = checkIfAllPlayersFitToScreen(); ply->x = x; ply->y = y; players_visible_after_move = checkIfAllPlayersFitToScreen(); /* player is allowed to move only in the following cases: - it is not needed to display all players (not focussed to all players) - all players are (still or again) visible after the move - some players were already outside visible screen area before the move */ can_move = (game.centered_player_nr != -1 || players_visible_after_move || !players_visible_before_move); ply->x = oldx; ply->y = oldy; if (!can_move) { ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0; return; } } if (dx == 0 && dy == 0) { ply->joy_stick = 0; if (ply->joy_drop) { if (++ply->dynamite_cnt == 5 && ply->dynamite) { Cave[y][x] = Xdynamite_1; play_element_sound(x, y, SAMPLE_dynamite, Xdynamite_1); ply->dynamite--; } } else { ply->dynamite_cnt = 0; } RandomEM += 7; /* be a bit more random if the player doesn't move */ return; } ply->joy_stick = 1; ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0; ply->dynamite_cnt = 0; /* reset dynamite timer if we move */ ply->joy_spin = !ply->joy_spin; if (ply->joy_snap == 0) /* player wants to move */ { boolean moved = FALSE; if (ply->last_move_dir & MV_HORIZONTAL) { if (!(moved = player_digfield(ply, 0, dy))) moved = player_digfield(ply, dx, 0); } else { if (!(moved = player_digfield(ply, dx, 0))) moved = player_digfield(ply, 0, dy); } if (moved) { if (oldx != ply->x) ply->last_move_dir = (dx < 0 ? MV_LEFT : MV_RIGHT); else if (oldy != ply->y) ply->last_move_dir = (dy < 0 ? MV_UP : MV_DOWN); game_em.any_player_moving = TRUE; game_em.last_moving_player = ply->num; game_em.last_player_direction[ply->num] = ply->last_move_dir; } } else /* player wants to snap */ { player_digfield(ply, dx, dy); } } static boolean player_digfield(struct PLAYER *ply, int dx, int dy) { int anim = (dx < 0 ? 3 : dx > 0 ? 1 : dy < 0 ? 0 : dy > 0 ? 2 : 2); int oldx = ply->x; int oldy = ply->y; int x = oldx + dx; int y = oldy + dy; boolean result = TRUE; if (!dx && !dy) /* no direction specified */ return FALSE; if (dx && dy && ply->joy_snap) /* more than one direction specified */ return FALSE; if (ply->joy_snap == 0) /* player wants to move */ { int element = Cave[y][x]; switch(Cave[y][x]) { /* fire is released */ case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Zplayer; Next[y][x] = Zplayer; #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif play_element_sound(x, y, SAMPLE_blank, Xblank); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; #if USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+1] == Xblank) Cave[y-1][x+1] = Yacid_splash_eB; if (Cave[y-1][x-1] == Xblank) Cave[y-1][x-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); #endif case Xboom_android: case Xboom_1: case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: #if !USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: #endif ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xgrass: Cave[y][x] = (dy ? (dy < 0 ? Ygrass_nB : Ygrass_sB) : (dx > 0 ? Ygrass_eB : Ygrass_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_dirt, Xgrass); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdirt: Cave[y][x] = (dy ? (dy < 0 ? Ydirt_nB : Ydirt_sB) : (dx > 0 ? Ydirt_eB : Ydirt_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_dirt, Xdirt); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdiamond: case Xdiamond_pause: Cave[y][x] = Ydiamond_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.diamond_score; lev.required = lev.required < 3 ? 0 : lev.required - 3; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xemerald: case Xemerald_pause: Cave[y][x] = Yemerald_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.emerald_score; lev.required = lev.required < 1 ? 0 : lev.required - 1; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdynamite: Cave[y][x] = Ydynamite_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.dynamite_score; ply->dynamite = ply->dynamite > 9998 ? 9999 : ply->dynamite + 1; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xkey_1: ply->keys |= 0x01; Cave[y][x] = Ykey_1_eat; goto key_walk; case Xkey_2: ply->keys |= 0x02; Cave[y][x] = Ykey_2_eat; goto key_walk; case Xkey_3: ply->keys |= 0x04; Cave[y][x] = Ykey_3_eat; goto key_walk; case Xkey_4: ply->keys |= 0x08; Cave[y][x] = Ykey_4_eat; goto key_walk; case Xkey_5: ply->keys |= 0x10; Cave[y][x] = Ykey_5_eat; goto key_walk; case Xkey_6: ply->keys |= 0x20; Cave[y][x] = Ykey_6_eat; goto key_walk; case Xkey_7: ply->keys |= 0x40; Cave[y][x] = Ykey_7_eat; goto key_walk; case Xkey_8: ply->keys |= 0x80; Cave[y][x] = Ykey_8_eat; goto key_walk; key_walk: Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.key_score; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xlenses: Cave[y][x] = Ylenses_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.lenses_score; lev.lenses_cnt = lev.lenses_time; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xmagnify: Cave[y][x] = Ymagnify_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.magnify_score; lev.magnify_cnt = lev.magnify_time; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xstone: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto stone_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ystone_e : Ystone_w; Next[y][x+dx] = Xstone_pause; stone_walk: Cave[y][x] = dx > 0 ? Ystone_eB : Ystone_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xstone); ply->x = x; } ply->anim = SPR_push + anim; break; case Xbomb: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto bomb_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ybomb_e : Ybomb_w; Next[y][x+dx] = Xbomb_pause; bomb_walk: Cave[y][x] = dx > 0 ? Ybomb_eB : Ybomb_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xbomb); ply->x = x; } ply->anim = SPR_push + anim; break; case Xnut: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto nut_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ynut_e : Ynut_w; Next[y][x+dx] = Xnut_pause; nut_walk: Cave[y][x] = dx > 0 ? Ynut_eB : Ynut_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xnut); ply->x = x; } ply->anim = SPR_push + anim; break; case Xspring: if (dy) break; switch(Cave[y][x+dx]) { case Xalien: case Xalien_pause: Cave[y][x] = dx > 0 ? Yspring_kill_eB : Yspring_kill_wB; Cave[y][x+dx] = dx > 0 ? Yspring_kill_e : Yspring_kill_w; Next[y][x] = Zplayer; Next[y][x+dx] = dx > 0 ? Xspring_e : Xspring_w; play_element_sound(x, y, SAMPLE_slurp, Xalien); lev.score += lev.slurp_score; ply->x = x; break; case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto spring_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Yspring_e : Yspring_w; Next[y][x+dx] = dx > 0 ? Xspring_e : Xspring_w; spring_walk: Cave[y][x] = dx > 0 ? Yspring_eB : Yspring_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xspring); ply->x = x; } ply->anim = SPR_push + anim; break; case Xspring_pause: case Xstone_pause: case Xbomb_pause: case Xnut_pause: case Xsand_stonein_1: case Xsand_stonein_2: case Xsand_stonein_3: case Xsand_stonein_4: if (dy) break; ply->anim = SPR_push + anim; break; case Xballoon: switch(Cave[y+dy][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y+dy-1][x+dx+1] == Xblank) Cave[y+dy-1][x+dx+1] = Yacid_splash_eB; if (Cave[y+dy-1][x+dx-1] == Xblank) Cave[y+dy-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto balloon_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y+dy][x+dx] = (dy ? (dy < 0 ? Yballoon_n : Yballoon_s) : (dx > 0 ? Yballoon_e : Yballoon_w)); Next[y+dy][x+dx] = Xballoon; balloon_walk: Cave[y][x] = (dy ? (dy < 0 ? Yballoon_nB : Yballoon_sB) : (dx > 0 ? Yballoon_eB : Yballoon_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_push, Xballoon); ply->x = x; ply->y = y; } ply->anim = SPR_push + anim; break; case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: switch(Cave[y+dy][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y+dy-1][x+dx+1] == Xblank) Cave[y+dy-1][x+dx+1] = Yacid_splash_eB; if (Cave[y+dy-1][x+dx-1] == Xblank) Cave[y+dy-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto android_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y+dy][x+dx] = (dy ? (dy < 0 ? Yandroid_n : Yandroid_s) : (dx > 0 ? Yandroid_e : Yandroid_w)); Next[y+dy][x+dx] = (dy ? (dy < 0 ? Xandroid_2_n : Xandroid_2_s) : (dx > 0 ? Xandroid_2_e : Xandroid_2_w)); android_walk: Cave[y][x] = (dy ? (dy < 0 ? Yandroid_nB : Yandroid_sB) : (dx > 0 ? Yandroid_eB : Yandroid_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_push, Xandroid); ply->x = x; ply->y = y; } ply->anim = SPR_push + anim; break; case Xdoor_1: case Xfake_door_1: if (ply->keys & 0x01) goto door_walk; else break; case Xdoor_2: case Xfake_door_2: if (ply->keys & 0x02) goto door_walk; else break; case Xdoor_3: case Xfake_door_3: if (ply->keys & 0x04) goto door_walk; else break; case Xdoor_4: case Xfake_door_4: if (ply->keys & 0x08) goto door_walk; else break; case Xdoor_5: case Xfake_door_5: if (ply->keys & 0x10) goto door_walk; else break; case Xdoor_6: case Xfake_door_6: if (ply->keys & 0x20) goto door_walk; else break; case Xdoor_7: case Xfake_door_7: if (ply->keys & 0x40) goto door_walk; else break; case Xdoor_8: case Xfake_door_8: if (ply->keys & 0x80) goto door_walk; else break; door_walk: if (!tab_blank[Cave[y+dy][x+dx]]) break; Cave[y+dy][x+dx] = Zplayer; Next[y+dy][x+dx] = Zplayer; play_element_sound(x, y, SAMPLE_door, element); ply->anim = SPR_walk + anim; ply->x = x + dx; ply->y = y + dy; break; case Xwheel: play_element_sound(x, y, SAMPLE_press, element); lev.wheel_cnt = lev.wheel_time; lev.wheel_x = x; lev.wheel_y = y; break; case Xwind_n: lev.wind_direction = 0; goto wind_walk; case Xwind_e: lev.wind_direction = 1; goto wind_walk; case Xwind_s: lev.wind_direction = 2; goto wind_walk; case Xwind_w: lev.wind_direction = 3; goto wind_walk; case Xwind_nesw: lev.wind_direction = dy ? (dy < 0 ? 0 : 2) : (dx > 0 ? 1 : 3); goto wind_walk; wind_walk: play_element_sound(x, y, SAMPLE_press, element); lev.wind_cnt = lev.wind_time; break; case Xwind_stop: play_element_sound(x, y, SAMPLE_press, element); lev.wind_cnt = 0; break; case Xswitch: play_element_sound(x, y, SAMPLE_press, element); lev.ball_cnt = lev.ball_time; lev.ball_state = !lev.ball_state; break; case Xplant: Cave[y][x] = Yplant; Next[y][x] = Xplant; play_element_sound(x, y, SAMPLE_blank, Xplant); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xexit_1: case Xexit_2: case Xexit_3: #if 0 /* !!! already played in kill_player !!! */ play_element_sound(x, y, SAMPLE_exit_leave, Xexit_1); #endif lev.home--; #if 0 /* !!! CHECK SCORE CALCULATION !!! */ if (lev.home == 0 && lev.time_initial > 0) /* game won */ lev.score += lev.time * lev.exit_score / 100; #endif ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; } if (ply->x == oldx && ply->y == oldy) /* no movement */ result = FALSE; } else /* player wants to snap */ { int element = Cave[y][x]; switch(Cave[y][x]) { /* fire is pressed */ case Xgrass: Cave[y][x] = Ygrass_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_dirt, element); ply->anim = SPR_spray + anim; break; case Xdirt: Cave[y][x] = Ydirt_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_dirt, element); ply->anim = SPR_spray + anim; break; case Xdiamond: case Xdiamond_pause: Cave[y][x] = Ydiamond_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.diamond_score; lev.required = lev.required < 3 ? 0 : lev.required - 3; ply->anim = SPR_walk + anim; break; case Xemerald: case Xemerald_pause: Cave[y][x] = Yemerald_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.emerald_score; lev.required = lev.required < 1 ? 0 : lev.required - 1; ply->anim = SPR_walk + anim; break; case Xdynamite: Cave[y][x] = Ydynamite_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.dynamite_score; ply->dynamite = ply->dynamite > 9998 ? 9999 : ply->dynamite + 1; ply->anim = SPR_walk + anim; break; case Xkey_1: ply->keys |= 0x01; Cave[y][x] = Ykey_1_eat; goto key_shoot; case Xkey_2: ply->keys |= 0x02; Cave[y][x] = Ykey_2_eat; goto key_shoot; case Xkey_3: ply->keys |= 0x04; Cave[y][x] = Ykey_3_eat; goto key_shoot; case Xkey_4: ply->keys |= 0x08; Cave[y][x] = Ykey_4_eat; goto key_shoot; case Xkey_5: ply->keys |= 0x10; Cave[y][x] = Ykey_5_eat; goto key_shoot; case Xkey_6: ply->keys |= 0x20; Cave[y][x] = Ykey_6_eat; goto key_shoot; case Xkey_7: ply->keys |= 0x40; Cave[y][x] = Ykey_7_eat; goto key_shoot; case Xkey_8: ply->keys |= 0x80; Cave[y][x] = Ykey_8_eat; goto key_shoot; key_shoot: Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.key_score; ply->anim = SPR_walk + anim; break; case Xlenses: Cave[y][x] = Ylenses_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.lenses_score; lev.lenses_cnt = lev.lenses_time; ply->anim = SPR_walk + anim; break; case Xmagnify: Cave[y][x] = Ymagnify_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.magnify_score; lev.magnify_cnt = lev.magnify_time; ply->anim = SPR_walk + anim; break; default: result = FALSE; } } return result; } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/synchro_2.c0000644000175000017500000034347010673341257021104 0ustar dimkadimka/* second part of synchro. * * game logic for monsters. * * one giant switch statement to process everything. * * this whole thing is a major bottleneck. the compiler must use registers. * compilers suck. */ #include "main_em.h" #define RANDOM (random = random << 31 | random >> 1) static void set_nearest_player_xy(int x, int y, int *dx, int *dy) { int distance, distance_shortest = EM_MAX_CAVE_WIDTH + EM_MAX_CAVE_HEIGHT; int i; /* default values if no players are alive anymore */ *dx = 0; *dy = 0; for (i = 0; i < MAX_PLAYERS; i++) { if (!ply[i].alive) continue; distance = ABS(ply[i].x - x) + ABS(ply[i].y - y); if (distance < distance_shortest) { *dx = ply[i].x; *dy = ply[i].y; distance_shortest = distance; } } } void synchro_2(void) { int x = 0; int y = 1; unsigned long random = RandomEM; short *cave_cache = Cave[y]; /* might be a win */ int score = 0; int temp = 0; /* initialized to make compilers happy */ int dx; /* only needed to find closest player */ int dy; int element; loop: element = cave_cache[++x]; switch (element) { default: goto loop; /* --------------------------------------------------------------------- */ #ifdef BAD_ROLL case Xstone_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; default: Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } case Xstone_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; default: Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } case Xnut_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; default: Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } case Xnut_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; default: Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } case Xspring_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; default: Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } case Xspring_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; default: Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } case Xemerald_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; default: Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } case Xemerald_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; default: Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } case Xdiamond_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; default: Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } case Xdiamond_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; default: Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } case Xbomb_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; default: Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } case Xbomb_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; default: Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } #endif /* BAD_ROLL */ /* --------------------------------------------------------------------- */ case Xstone: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; case Xsand: Cave[y][x] = Xsand_stonein_1; Cave[y+1][x] = Xsand_sandstone_1; Next[y][x] = Xsand_stonein_2; Next[y+1][x] = Xsand_sandstone_2; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xlenses: case Xmagnify: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xstone_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; default: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; } /* --------------------------------------------------------------------- */ case Xstone_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; case Xnut: case Xnut_pause: Cave[y+1][x] = Yemerald_stone; Next[y][x] = Xstone; Next[y+1][x] = Xemerald; play_element_sound(x, y, SAMPLE_crack, Xnut); score += lev.nut_score; goto loop; case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ybug_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xemerald; Boom[y][x] = Xemerald; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xdiamond; Boom[y+1][x+1] = Xemerald; Boom[y+2][x-1] = Xemerald; Boom[y+2][x] = Xemerald; Boom[y+2][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.bug_score; goto loop; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ytank_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.tank_score; goto loop; case Xspring: if (RANDOM & 1) { switch (Cave[y+1][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xalien: case Xalien_pause: Cave[y+1][x] = Xspring_e; break; default: Cave[y+1][x] = Xspring_w; break; } } else { switch (Cave[y+1][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xalien: case Xalien_pause: Cave[y+1][x] = Xspring_w; break; default: Cave[y+1][x] = Xspring_e; break; } } Next[y][x] = Xstone; goto loop; case Xeater_n: case Xeater_e: case Xeater_s: case Xeater_w: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Yeater_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = lev.eater_array[lev.eater_pos][0]; Boom[y][x] = lev.eater_array[lev.eater_pos][1]; Boom[y][x+1] = lev.eater_array[lev.eater_pos][2]; Boom[y+1][x-1] = lev.eater_array[lev.eater_pos][3]; Boom[y+1][x] = lev.eater_array[lev.eater_pos][4]; Boom[y+1][x+1] = lev.eater_array[lev.eater_pos][5]; Boom[y+2][x-1] = lev.eater_array[lev.eater_pos][6]; Boom[y+2][x] = lev.eater_array[lev.eater_pos][7]; Boom[y+2][x+1] = lev.eater_array[lev.eater_pos][8]; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif lev.eater_pos = (lev.eater_pos + 1) & 7; score += lev.eater_score; goto loop; case Xalien: case Xalien_pause: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Yalien_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.alien_score; goto loop; case Xdiamond: case Xdiamond_pause: switch (Cave[y+2][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: case Xspring_fall: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone_fall: case Xemerald_fall: case Xdiamond_fall: case Xbomb_fall: case Xacid_s: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Xnut_fall: case Xplant: case Yplant: Next[y][x] = Xstone; play_element_sound(x, y, SAMPLE_stone, Xstone); goto loop; } Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ydiamond_stone; Next[y][x] = Xblank; Next[y+1][x] = Xstone_pause; play_element_sound(x, y, SAMPLE_squash, Xdiamond); goto loop; case Xbomb: case Xbomb_pause: Cave[y+1][x] = Ybomb_eat; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Ystone_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Yemerald_s; Next[y+2][x] = Xemerald_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xstone; Next[y][x] = Xstone; play_element_sound(x, y, SAMPLE_stone, Xstone); goto loop; } /* --------------------------------------------------------------------- */ case Xnut: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xnut_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; default: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; } /* --------------------------------------------------------------------- */ case Xnut_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; default: Cave[y][x] = Xnut; Next[y][x] = Xnut; play_element_sound(x, y, SAMPLE_nut, Xnut); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_n: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_n_e; Next[y][x] = Xbug_goe; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gon; } case Xbug_gon: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gon: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_nB; Cave[y-1][x] = Ybug_n; Next[y][x] = Xblank; Next[y-1][x] = Xbug_n; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_n_w; Next[y][x] = Xbug_gow; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_e: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y+1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_e_s; Next[y][x] = Xbug_gos; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_goe; } case Xbug_goe: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_goe: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_eB; Cave[y][x+1] = Ybug_e; Next[y][x] = Xblank; Next[y][x+1] = Xbug_e; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_e_n; Next[y][x] = Xbug_gon; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_s: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_s_w; Next[y][x] = Xbug_gow; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gos; } case Xbug_gos: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gos: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_sB; Cave[y+1][x] = Ybug_s; Next[y][x] = Xblank; Next[y+1][x] = Xbug_s; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_s_e; Next[y][x] = Xbug_goe; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_w: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y-1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_w_n; Next[y][x] = Xbug_gon; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gow; } case Xbug_gow: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gow: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_wB; Cave[y][x-1] = Ybug_w; Next[y][x] = Xblank; Next[y][x-1] = Xbug_w; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_w_s; Next[y][x] = Xbug_gos; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_n: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_n_w; Next[y][x] = Xtank_gow; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gon; } case Xtank_gon: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gon: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_nB; Cave[y-1][x] = Ytank_n; Next[y][x] = Xblank; Next[y-1][x] = Xtank_n; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_n_e; Next[y][x] = Xtank_goe; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_e: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y-1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_e_n; Next[y][x] = Xtank_gon; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_goe; } case Xtank_goe: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_goe: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_eB; Cave[y][x+1] = Ytank_e; Next[y][x] = Xblank; Next[y][x+1] = Xtank_e; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_e_s; Next[y][x] = Xtank_gos; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_s: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_s_e; Next[y][x] = Xtank_goe; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gos; } case Xtank_gos: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gos: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_sB; Cave[y+1][x] = Ytank_s; Next[y][x] = Xblank; Next[y+1][x] = Xtank_s; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_s_w; Next[y][x] = Xtank_gow; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_w: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y+1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_w_s; Next[y][x] = Xtank_gos; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gow; } case Xtank_gow: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gow: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_wB; Cave[y][x-1] = Ytank_w; Next[y][x] = Xblank; Next[y][x-1] = Xtank_w; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_w_n; Next[y][x] = Xtank_gon; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xandroid: android: if (lev.android_clone_cnt == 0) { if (Cave[y-1][x-1] != Xblank && Cave[y-1][x] != Xblank && Cave[y-1][x+1] != Xblank && Cave[y][x-1] != Xblank && Cave[y][x+1] != Xblank && Cave[y+1][x-1] != Xblank && Cave[y+1][x] != Xblank && Cave[y+1][x+1] != Xblank) goto android_move; switch (RANDOM & 7) { /* randomly find an object to clone */ case 0: /* S,NE,W,NW,SE,E,SW,N */ temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; goto android_move; case 1: /* NW,SE,N,S,NE,SW,E,W */ temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; goto android_move; case 2: /* SW,E,S,W,N,NW,SE,NE */ temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; goto android_move; case 3: /* N,SE,NE,E,W,S,NW,SW */ temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; goto android_move; case 4: /* SE,NW,E,NE,SW,W,N,S */ temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; goto android_move; case 5: /* NE,W,SE,SW,S,N,E,NW */ temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; goto android_move; case 6: /* E,N,SW,S,NW,NE,SE,W */ temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; goto android_move; case 7: /* W,SW,NW,N,E,SE,NE,S */ temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; goto android_move; } Next[y][x] = temp; /* the item we chose to clone */ play_element_sound(x, y, SAMPLE_android_clone, temp); switch (RANDOM & 7) { /* randomly find a direction to move */ case 0: /* S,NE,W,NW,SE,E,SW,N */ if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y-1][x] == Xblank) goto android_n; goto android_move; case 1: /* NW,SE,N,S,NE,SW,E,W */ if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y][x-1] == Xblank) goto android_w; goto android_move; case 2: /* SW,E,S,W,N,NW,SE,NE */ if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; goto android_move; case 3: /* N,SE,NE,E,W,S,NW,SW */ if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x-1] == Xblank) goto android_sw; goto android_move; case 4: /* SE,NW,E,NE,SW,W,N,S */ if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x] == Xblank) goto android_s; goto android_move; case 5: /* NE,W,SE,SW,S,N,E,NW */ if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x-1] == Xblank) goto android_nw; goto android_move; case 6: /* E,N,SW,S,NW,NE,SE,W */ if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y][x-1] == Xblank) goto android_w; goto android_move; case 7: /* W,SW,NW,N,E,SE,NE,S */ if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x] == Xblank) goto android_s; goto android_move; } } android_move: if (lev.android_move_cnt == 0) { if (Cave[y-1][x-1] == Zplayer || Cave[y-1][x] == Zplayer || Cave[y-1][x+1] == Zplayer || Cave[y][x-1] == Zplayer || Cave[y][x+1] == Zplayer || Cave[y+1][x-1] == Zplayer || Cave[y+1][x] == Zplayer || Cave[y+1][x+1] == Zplayer) goto android_still; #if 1 set_nearest_player_xy(x, y, &dx, &dy); #else if (ply1.alive && ply2.alive) { if ((ply1.x > x ? ply1.x - x : x - ply1.x) + (ply1.y > y ? ply1.y - y : y - ply1.y) < (ply2.x > x ? ply2.x - x : x - ply2.x) + (ply2.y > y ? ply2.y - y : y - ply2.y)) { dx = ply1.x; dy = ply1.y; } else { dx = ply2.x; dy = ply2.y; } } else if (ply1.alive) { dx = ply1.x; dy = ply1.y; } else if (ply2.alive) { dx = ply2.x; dy = ply2.y; } else { dx = 0; dy = 0; } #endif Next[y][x] = Xblank; /* assume we will move */ temp = ((x < dx) + 1 - (x > dx)) + ((y < dy) + 1 - (y > dy)) * 3; if (RANDOM & 1) { switch (temp) { /* attempt clockwise move first if direct path is blocked */ case 0: /* north west */ if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y][x-1]]) goto android_w; break; case 1: /* north */ if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; break; case 2: /* north east */ if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y-1][x]]) goto android_n; break; case 3: /* west */ if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; break; case 4: /* nowhere */ break; case 5: /* east */ if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; break; case 6: /* south west */ if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y+1][x]]) goto android_s; break; case 7: /* south */ if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; break; case 8: /* south east */ if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y][x+1]]) goto android_e; break; } } else { switch (temp) { /* attempt counterclockwise move first if direct path is blocked */ case 0: /* north west */ if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y-1][x]]) goto android_n; break; case 1: /* north */ if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; break; case 2: /* north east */ if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y][x+1]]) goto android_e; break; case 3: /* west */ if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; break; case 4: /* nowhere */ break; case 5: /* east */ if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; break; case 6: /* south west */ if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y][x-1]]) goto android_w; break; case 7: /* south */ if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; break; case 8: /* south east */ if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y+1][x]]) goto android_s; break; } } } android_still: Next[y][x] = Xandroid; goto loop; android_n: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y-1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_ne: Cave[y][x] = Yandroid_neB; Cave[y-1][x+1] = Yandroid_ne; Next[y-1][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_e: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_se: Cave[y][x] = Yandroid_seB; Cave[y+1][x+1] = Yandroid_se; Next[y+1][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_s: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y+1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_sw: Cave[y][x] = Yandroid_swB; Cave[y+1][x-1] = Yandroid_sw; Next[y+1][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_w: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_nw: Cave[y][x] = Yandroid_nwB; Cave[y-1][x-1] = Yandroid_nw; Next[y-1][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; /* --------------------------------------------------------------------- */ case Xandroid_1_n: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y][x] = Xblank; Next[y-1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_n: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y][x] = Xblank; Next[y-1][x] = Xandroid_1_n; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_e: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x] = Xblank; Next[y][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_e: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x] = Xblank; Next[y][x+1] = Xandroid_1_e; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_s: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y][x] = Xblank; Next[y+1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_s: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y][x] = Xblank; Next[y+1][x] = Xandroid_1_s; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_w: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x] = Xblank; Next[y][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_w: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x] = Xblank; Next[y][x-1] = Xandroid_1_w; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xspring: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xspring_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; } /* --------------------------------------------------------------------- */ case Xspring_e: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbumper: Cave[y+1][x] = XbumperB; } switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Yalien_nB: case Yalien_eB: case Yalien_sB: case Yalien_wB: Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; Next[y][x] = Xblank; Next[y][x+1] = Xspring_e; goto loop; case Xalien: case Xalien_pause: case Yalien_n: case Yalien_e: case Yalien_s: case Yalien_w: Cave[y][x] = Yspring_kill_eB; Cave[y][x+1] = Yspring_kill_e; Next[y][x] = Xblank; Next[y][x+1] = Xspring_e; play_element_sound(x, y, SAMPLE_slurp, Xalien); score += lev.slurp_score; goto loop; case Xbumper: case XbumperB: Cave[y][x+1] = XbumperB; Next[y][x] = Xspring_w; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xspring_w: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbumper: Cave[y+1][x] = XbumperB; } switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Yalien_nB: case Yalien_eB: case Yalien_sB: case Yalien_wB: Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; Next[y][x] = Xblank; Next[y][x-1] = Xspring_w; goto loop; case Xalien: case Xalien_pause: case Yalien_n: case Yalien_e: case Yalien_s: case Yalien_w: Cave[y][x] = Yspring_kill_wB; Cave[y][x-1] = Yspring_kill_w; Next[y][x] = Xblank; Next[y][x-1] = Xspring_w; play_element_sound(x, y, SAMPLE_slurp, Xalien); score += lev.slurp_score; goto loop; case Xbumper: case XbumperB: Cave[y][x-1] = XbumperB; Next[y][x] = Xspring_e; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xspring_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbomb: case Xbomb_pause: Cave[y+1][x] = Ybomb_eat; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Ybug_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xemerald; Boom[y][x] = Xemerald; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xdiamond; Boom[y+1][x+1] = Xemerald; Boom[y+2][x-1] = Xemerald; Boom[y+2][x] = Xemerald; Boom[y+2][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.bug_score; goto loop; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Ytank_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.tank_score; goto loop; case Xeater_n: case Xeater_e: case Xeater_s: case Xeater_w: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yeater_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = lev.eater_array[lev.eater_pos][0]; Boom[y][x] = lev.eater_array[lev.eater_pos][1]; Boom[y][x+1] = lev.eater_array[lev.eater_pos][2]; Boom[y+1][x-1] = lev.eater_array[lev.eater_pos][3]; Boom[y+1][x] = lev.eater_array[lev.eater_pos][4]; Boom[y+1][x+1] = lev.eater_array[lev.eater_pos][5]; Boom[y+2][x-1] = lev.eater_array[lev.eater_pos][6]; Boom[y+2][x] = lev.eater_array[lev.eater_pos][7]; Boom[y+2][x+1] = lev.eater_array[lev.eater_pos][8]; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif lev.eater_pos = (lev.eater_pos + 1) & 7; score += lev.eater_score; goto loop; case Xalien: case Xalien_pause: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yalien_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.alien_score; goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_n: if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_nB; Cave[y-1][x] = Yeater_n; Next[y][x] = Xblank; Next[y-1][x] = Xeater_n; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_e : Xeater_w; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_e: if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_eB; Cave[y][x+1] = Yeater_e; Next[y][x] = Xblank; Next[y][x+1] = Xeater_e; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_n : Xeater_s; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_s: if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_sB; Cave[y+1][x] = Yeater_s; Next[y][x] = Xblank; Next[y+1][x] = Xeater_s; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_e : Xeater_w; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_w: if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_wB; Cave[y][x-1] = Yeater_w; Next[y][x] = Xblank; Next[y][x-1] = Xeater_w; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_n : Xeater_s; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xalien: #if 1 if (lev.wheel_cnt) { dx = lev.wheel_x; dy = lev.wheel_y; } else { set_nearest_player_xy(x, y, &dx, &dy); } #else if (lev.wheel_cnt) { dx = lev.wheel_x; dy = lev.wheel_y; } else if (ply1.alive && ply2.alive) { if ((ply1.x > x ? ply1.x - x : x - ply1.x) + (ply1.y > y ? ply1.y - y : y - ply1.y) < (ply2.x > x ? ply2.x - x : x - ply2.x) + (ply2.y > y ? ply2.y - y : y - ply2.y)) { dx = ply1.x; dy = ply1.y; } else { dx = ply2.x; dy = ply2.y; } } else if (ply1.alive) { dx = ply1.x; dy = ply1.y; } else if (ply2.alive) { dx = ply2.x; dy = ply2.y; } else { dx = 0; dy = 0; } #endif if (RANDOM & 1) { if (y > dy) { switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_nB; Cave[y-1][x] = Yalien_n; Next[y][x] = Xblank; Next[y-1][x] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } else if (y < dy) { switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_sB; Next[y][x] = Xblank; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_sB; Cave[y+1][x] = Yalien_s; Next[y][x] = Xblank; Next[y+1][x] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } } else { if (x < dx) { switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_eB; Cave[y][x+1] = Yalien_e; Next[y][x] = Xblank; Next[y][x+1] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } else if (x > dx) { switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_wB; Cave[y][x-1] = Yalien_w; Next[y][x] = Xblank; Next[y][x-1] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } } goto loop; case Xalien_pause: Next[y][x] = Xalien; goto loop; /* --------------------------------------------------------------------- */ case Xemerald: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xwonderwall: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xsteel_1: case Xsteel_2: case Xsteel_3: case Xsteel_4: case Xwall_1: case Xwall_2: case Xwall_3: case Xwall_4: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } } default: if (++lev.shine_cnt > 50) { lev.shine_cnt = RANDOM & 7; Cave[y][x] = Xemerald_shine; } goto loop; } /* --------------------------------------------------------------------- */ case Xemerald_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; default: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; } /* --------------------------------------------------------------------- */ case Xemerald_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Yemerald_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Ydiamond_s; Next[y+2][x] = Xdiamond_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; play_element_sound(x, y, SAMPLE_diamond, Xemerald); goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xwonderwall: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xsteel_1: case Xsteel_2: case Xsteel_3: case Xsteel_4: case Xwall_1: case Xwall_2: case Xwall_3: case Xwall_4: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } } default: if (++lev.shine_cnt > 50) { lev.shine_cnt = RANDOM & 7; Cave[y][x] = Xdiamond_shine; } goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; default: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Ydiamond_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Ystone_s; Next[y+2][x] = Xstone_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; play_element_sound(x, y, SAMPLE_diamond, Xdiamond); goto loop; } /* --------------------------------------------------------------------- */ case Xdrip_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydrip_s1B; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xdrip_stretchB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ydrip_s1B; Cave[y+1][x] = Ydrip_s1; Next[y][x] = Xdrip_stretchB; Next[y+1][x] = Xdrip_stretch; goto loop; default: switch (RANDOM & 7) { case 0: temp = Xamoeba_1; break; case 1: temp = Xamoeba_2; break; case 2: temp = Xamoeba_3; break; case 3: temp = Xamoeba_4; break; case 4: temp = Xamoeba_5; break; case 5: temp = Xamoeba_6; break; case 6: temp = Xamoeba_7; break; case 7: temp = Xamoeba_8; break; } Cave[y][x] = temp; Next[y][x] = temp; play_element_sound(x, y, SAMPLE_drip, Xdrip_fall); goto loop; } /* --------------------------------------------------------------------- */ case Xdrip_stretch: Cave[y][x] = Ydrip_s2; Next[y][x] = Xdrip_fall; goto loop; case Xdrip_stretchB: Cave[y][x] = Ydrip_s2B; Next[y][x] = Xblank; goto loop; case Xdrip_eat: Next[y][x] = Xdrip_fall; goto loop; /* --------------------------------------------------------------------- */ case Xbomb: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xbomb_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; default: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; } /* --------------------------------------------------------------------- */ case Xbomb_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; default: Cave[y][x] = Ybomb_eat; Next[y][x] = Znormal; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; } /* --------------------------------------------------------------------- */ case Xballoon: if (lev.wind_cnt == 0) goto loop; switch (lev.wind_direction) { case 0: /* north */ switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_nB; Cave[y-1][x] = Yballoon_n; Next[y][x] = Xblank; Next[y-1][x] = Xballoon; goto loop; default: goto loop; } case 1: /* east */ switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_eB; Cave[y][x+1] = Yballoon_e; Next[y][x] = Xblank; Next[y][x+1] = Xballoon; goto loop; default: goto loop; } case 2: /* south */ switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_sB; Cave[y+1][x] = Yballoon_s; Next[y][x] = Xblank; Next[y+1][x] = Xballoon; goto loop; default: goto loop; } case 3: /* west */ switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_wB; Cave[y][x-1] = Yballoon_w; Next[y][x] = Xblank; Next[y][x-1] = Xballoon; goto loop; default: goto loop; } } /* --------------------------------------------------------------------- */ case Xacid_1: Next[y][x] = Xacid_2; goto loop; case Xacid_2: Next[y][x] = Xacid_3; goto loop; case Xacid_3: Next[y][x] = Xacid_4; goto loop; case Xacid_4: Next[y][x] = Xacid_5; goto loop; case Xacid_5: Next[y][x] = Xacid_6; goto loop; case Xacid_6: Next[y][x] = Xacid_7; goto loop; case Xacid_7: Next[y][x] = Xacid_8; goto loop; case Xacid_8: Next[y][x] = Xacid_1; goto loop; case Xfake_acid_1: Next[y][x] = Xfake_acid_2; goto loop; case Xfake_acid_2: Next[y][x] = Xfake_acid_3; goto loop; case Xfake_acid_3: Next[y][x] = Xfake_acid_4; goto loop; case Xfake_acid_4: Next[y][x] = Xfake_acid_5; goto loop; case Xfake_acid_5: Next[y][x] = Xfake_acid_6; goto loop; case Xfake_acid_6: Next[y][x] = Xfake_acid_7; goto loop; case Xfake_acid_7: Next[y][x] = Xfake_acid_8; goto loop; case Xfake_acid_8: Next[y][x] = Xfake_acid_1; goto loop; /* --------------------------------------------------------------------- */ case Xball_1: if (lev.ball_state == 0) goto loop; Cave[y][x] = Xball_1B; Next[y][x] = Xball_2; if (lev.ball_cnt) goto loop; goto ball_common; case Xball_2: if (lev.ball_state == 0) goto loop; Cave[y][x] = Xball_2B; Next[y][x] = Xball_1; if (lev.ball_cnt) goto loop; goto ball_common; ball_common: play_element_sound(x, y, SAMPLE_ball, element); if (lev.ball_random) { switch (RANDOM & 7) { case 0: if (lev.ball_array[lev.ball_pos][0] != Xblank && tab_blank[Cave[y-1][x-1]]) { Cave[y-1][x-1] = Yball_eat; Next[y-1][x-1] = lev.ball_array[lev.ball_pos][0]; } break; case 1: if (lev.ball_array[lev.ball_pos][1] != Xblank && tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Yball_eat; Next[y-1][x] = lev.ball_array[lev.ball_pos][1]; } break; case 2: if (lev.ball_array[lev.ball_pos][2] != Xblank && tab_blank[Cave[y-1][x+1]]) { Cave[y-1][x+1] = Yball_eat; Next[y-1][x+1] = lev.ball_array[lev.ball_pos][2]; } break; case 3: if (lev.ball_array[lev.ball_pos][3] != Xblank && tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Yball_eat; Next[y][x-1] = lev.ball_array[lev.ball_pos][3]; } break; case 4: if (lev.ball_array[lev.ball_pos][4] != Xblank && tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Yball_eat; Next[y][x+1] = lev.ball_array[lev.ball_pos][4]; } break; case 5: if (lev.ball_array[lev.ball_pos][5] != Xblank && tab_blank[Cave[y+1][x-1]]) { Cave[y+1][x-1] = Yball_eat; Next[y+1][x-1] = lev.ball_array[lev.ball_pos][5]; } break; case 6: if (lev.ball_array[lev.ball_pos][6] != Xblank && tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Yball_eat; Next[y+1][x] = lev.ball_array[lev.ball_pos][6]; } break; case 7: if (lev.ball_array[lev.ball_pos][7] != Xblank && tab_blank[Cave[y+1][x+1]]) { Cave[y+1][x+1] = Yball_eat; Next[y+1][x+1] = lev.ball_array[lev.ball_pos][7]; } break; } } else { if (lev.ball_array[lev.ball_pos][0] != Xblank && tab_blank[Cave[y-1][x-1]]) { Cave[y-1][x-1] = Yball_eat; Next[y-1][x-1] = lev.ball_array[lev.ball_pos][0]; } if (lev.ball_array[lev.ball_pos][1] != Xblank && tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Yball_eat; Next[y-1][x] = lev.ball_array[lev.ball_pos][1]; } if (lev.ball_array[lev.ball_pos][2] != Xblank && tab_blank[Cave[y-1][x+1]]) { Cave[y-1][x+1] = Yball_eat; Next[y-1][x+1] = lev.ball_array[lev.ball_pos][2]; } if (lev.ball_array[lev.ball_pos][3] != Xblank && tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Yball_eat; Next[y][x-1] = lev.ball_array[lev.ball_pos][3]; } if (lev.ball_array[lev.ball_pos][4] != Xblank && tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Yball_eat; Next[y][x+1] = lev.ball_array[lev.ball_pos][4]; } if (lev.ball_array[lev.ball_pos][5] != Xblank && tab_blank[Cave[y+1][x-1]]) { Cave[y+1][x-1] = Yball_eat; Next[y+1][x-1] = lev.ball_array[lev.ball_pos][5]; } if (lev.ball_array[lev.ball_pos][6] != Xblank && tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Yball_eat; Next[y+1][x] = lev.ball_array[lev.ball_pos][6]; } if (lev.ball_array[lev.ball_pos][7] != Xblank && tab_blank[Cave[y+1][x+1]]) { Cave[y+1][x+1] = Yball_eat; Next[y+1][x+1] = lev.ball_array[lev.ball_pos][7]; } } #if 1 lev.ball_pos = (lev.ball_pos + 1) % lev.num_ball_arrays; #else lev.ball_pos = (lev.ball_pos + 1) & 7; #endif goto loop; /* --------------------------------------------------------------------- */ case Xgrow_ns: if (tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Ygrow_ns_eat; Next[y-1][x] = Xgrow_ns; play_element_sound(x, y, SAMPLE_grow, Xgrow_ns); } if (tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Ygrow_ns_eat; Next[y+1][x] = Xgrow_ns; play_element_sound(x, y, SAMPLE_grow, Xgrow_ns); } goto loop; case Xgrow_ew: if (tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Ygrow_ew_eat; Next[y][x+1] = Xgrow_ew; play_element_sound(x, y, SAMPLE_grow, Xgrow_ew); } if (tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Ygrow_ew_eat; Next[y][x-1] = Xgrow_ew; play_element_sound(x, y, SAMPLE_grow, Xgrow_ew); } goto loop; /* --------------------------------------------------------------------- */ case Xwonderwall: if (lev.wonderwall_time && lev.wonderwall_state) { Cave[y][x] = XwonderwallB; play_element_sound(x, y, SAMPLE_wonder, Xwonderwall); } goto loop; /* --------------------------------------------------------------------- */ case Xexit: if (lev.required > 0) goto loop; temp = RANDOM & 63; if (temp < 21) { Cave[y][x] = Xexit_1; Next[y][x] = Xexit_2; } else if (temp < 42) { Cave[y][x] = Xexit_2; Next[y][x] = Xexit_3; } else { Cave[y][x] = Xexit_3; Next[y][x] = Xexit_1; } play_element_sound(x, y, SAMPLE_exit_open, Xexit); goto loop; case Xexit_1: Next[y][x] = Xexit_2; goto loop; case Xexit_2: Next[y][x] = Xexit_3; goto loop; case Xexit_3: Next[y][x] = Xexit_1; goto loop; /* --------------------------------------------------------------------- */ case Xdynamite_1: play_element_sound(x, y, SAMPLE_tick, Xdynamite_1); Next[y][x] = Xdynamite_2; goto loop; case Xdynamite_2: play_element_sound(x, y, SAMPLE_tick, Xdynamite_2); Next[y][x] = Xdynamite_3; goto loop; case Xdynamite_3: play_element_sound(x, y, SAMPLE_tick, Xdynamite_3); Next[y][x] = Xdynamite_4; goto loop; case Xdynamite_4: play_element_sound(x, y, SAMPLE_tick, Xdynamite_4); Next[y][x] = Zdynamite; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; goto loop; /* --------------------------------------------------------------------- */ case Xwheel: if (lev.wheel_cnt && x == lev.wheel_x && y == lev.wheel_y) Cave[y][x] = XwheelB; goto loop; /* --------------------------------------------------------------------- */ case Xswitch: if (lev.ball_state) Cave[y][x] = XswitchB; goto loop; /* --------------------------------------------------------------------- */ case Xsand_stone: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: #if 1 Cave[y][x] = Xsand_stonesand_quickout_1; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xsand_stonesand_quickout_2; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; #else Cave[y][x] = Xsand_stonesand_3; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xsand_stonesand_4; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; #endif case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: #if 1 Cave[y][x] = Xsand_stonesand_quickout_1; Cave[y+1][x] = Xsand_stoneout_1; Next[y][x] = Xsand_stonesand_quickout_2; Next[y+1][x] = Xsand_stoneout_2; goto loop; #else Cave[y][x] = Xsand_stonesand_3; Cave[y+1][x] = Xsand_stoneout_1; Next[y][x] = Xsand_stonesand_4; Next[y+1][x] = Xsand_stoneout_2; goto loop; #endif case Xsand: Cave[y][x] = Xsand_stonesand_1; Cave[y+1][x] = Xsand_sandstone_1; Next[y][x] = Xsand_stonesand_2; Next[y+1][x] = Xsand_sandstone_2; goto loop; default: goto loop; } case Xsand_stonein_1: Next[y][x] = Xsand_stonein_2; goto loop; case Xsand_stonein_2: Next[y][x] = Xsand_stonein_3; goto loop; case Xsand_stonein_3: Next[y][x] = Xsand_stonein_4; goto loop; case Xsand_stonein_4: Next[y][x] = Xblank; goto loop; case Xsand_stonesand_1: Next[y][x] = Xsand_stonesand_2; goto loop; case Xsand_stonesand_2: Next[y][x] = Xsand_stonesand_3; goto loop; case Xsand_stonesand_3: Next[y][x] = Xsand_stonesand_4; goto loop; case Xsand_stonesand_4: Next[y][x] = Xsand; goto loop; #if 1 case Xsand_stonesand_quickout_1: Next[y][x] = Xsand_stonesand_quickout_2; goto loop; case Xsand_stonesand_quickout_2: Next[y][x] = Xsand; goto loop; #endif case Xsand_stoneout_1: Next[y][x] = Xsand_stoneout_2; goto loop; case Xsand_stoneout_2: Next[y][x] = Xstone_fall; goto loop; case Xsand_sandstone_1: Next[y][x] = Xsand_sandstone_2; goto loop; case Xsand_sandstone_2: Next[y][x] = Xsand_sandstone_3; goto loop; case Xsand_sandstone_3: Next[y][x] = Xsand_sandstone_4; goto loop; case Xsand_sandstone_4: Next[y][x] = Xsand_stone; goto loop; /* --------------------------------------------------------------------- */ case Xdripper: if (lev.lenses_cnt) Cave[y][x] = XdripperB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_blank: if (lev.lenses_cnt) Cave[y][x] = Xfake_blankB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_grass: if (lev.magnify_cnt) Cave[y][x] = Xfake_grassB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_door_1: if (lev.magnify_cnt) Cave[y][x] = Xdoor_1; goto loop; case Xfake_door_2: if (lev.magnify_cnt) Cave[y][x] = Xdoor_2; goto loop; case Xfake_door_3: if (lev.magnify_cnt) Cave[y][x] = Xdoor_3; goto loop; case Xfake_door_4: if (lev.magnify_cnt) Cave[y][x] = Xdoor_4; goto loop; case Xfake_door_5: if (lev.magnify_cnt) Cave[y][x] = Xdoor_5; goto loop; case Xfake_door_6: if (lev.magnify_cnt) Cave[y][x] = Xdoor_6; goto loop; case Xfake_door_7: if (lev.magnify_cnt) Cave[y][x] = Xdoor_7; goto loop; case Xfake_door_8: if (lev.magnify_cnt) Cave[y][x] = Xdoor_8; goto loop; /* --------------------------------------------------------------------- */ case Xboom_bug: bug_boom: Next[y][x] = Znormal; Boom[y-1][x-1] = Xemerald; Boom[y-1][x] = Xemerald; Boom[y-1][x+1] = Xemerald; Boom[y][x-1] = Xemerald; Boom[y][x] = Xdiamond; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xemerald; Boom[y+1][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xboom_bomb: tank_boom: Next[y][x] = Znormal; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xboom_android: #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Xandroid); #endif case Xboom_1: Next[y][x] = Xboom_2; #if !PLAY_ELEMENT_SOUND if (x != lev.exit_x && y != lev.exit_y) play_sound(x, y, SAMPLE_boom); else lev.exit_x = lev.exit_y = -1; #endif goto loop; case Xboom_2: Next[y][x] = Boom[y][x]; goto loop; /* --------------------------------------------------------------------- */ case ZBORDER: if (++y < HEIGHT - 1) { x = 0; cave_cache = Cave[y]; goto loop; } goto done; } #undef RANDOM #undef PLAY #undef PLAY_FORCE done: if (ply[0].alive || ply[1].alive || ply[2].alive || ply[3].alive) lev.score += score; /* only add a score if someone is alive */ RandomEM = random; { void *temp = Cave; /* triple buffering */ Cave = Next; Next = Draw; Draw = temp; } } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/tile.h0000644000175000017500000001525110374703773020134 0ustar dimkadimka#ifndef TILE_H #define TILE_H #include "main_em.h" #ifdef EM_ENGINE_BAD_ROLL #define BAD_ROLL #endif #ifdef EM_ENGINE_BAD_SPRING #define BAD_SPRING #endif #if 0 /* 2000-07-30T11:06:03Z */ /* define these for backwards compatibility */ #define BAD_ROLL #define BAD_SPRING enum { Xblank = 0, /* still */ Yacid_splash_eB, /* hmm */ Yacid_splash_wB, /* hmm */ #ifdef BAD_ROLL Xstone_force_e, /* only use these in eater */ Xstone_force_w, Xnut_force_e, Xnut_force_w, Xspring_force_e, Xspring_force_w, Xemerald_force_e, Xemerald_force_w, Xdiamond_force_e, Xdiamond_force_w, Xbomb_force_e, Xbomb_force_w, #endif Xstone, Xstone_pause, Xstone_fall, Ystone_s, Ystone_sB, Ystone_e, Ystone_eB, Ystone_w, Ystone_wB, Xnut, Xnut_pause, Xnut_fall, Ynut_s, Ynut_sB, Ynut_e, Ynut_eB, Ynut_w, Ynut_wB, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Ybug_n, Ybug_nB, Ybug_e, Ybug_eB, Ybug_s, Ybug_sB, Ybug_w, Ybug_wB, Ybug_w_n, Ybug_n_e, Ybug_e_s, Ybug_s_w, Ybug_e_n, Ybug_s_e, Ybug_w_s, Ybug_n_w, Ybug_stone, Ybug_spring, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Ytank_n, Ytank_nB, Ytank_e, Ytank_eB, Ytank_s, Ytank_sB, Ytank_w, Ytank_wB, Ytank_w_n, Ytank_n_e, Ytank_e_s, Ytank_s_w, Ytank_e_n, Ytank_s_e, Ytank_w_s, Ytank_n_w, Ytank_stone, Ytank_spring, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_w, Xandroid_2_w, Xandroid_1_s, Xandroid_2_s, Yandroid_n, Yandroid_nB, Yandroid_ne, Yandroid_neB, Yandroid_e, Yandroid_eB, Yandroid_se, Yandroid_seB, Yandroid_s, Yandroid_sB, Yandroid_sw, Yandroid_swB, Yandroid_w, Yandroid_wB, Yandroid_nw, Yandroid_nwB, Xspring, Xspring_pause, Xspring_e, Xspring_w, Xspring_fall, Yspring_s, Yspring_sB, Yspring_e, Yspring_eB, Yspring_w, Yspring_wB, Yspring_kill_e, Yspring_kill_eB, Yspring_kill_w, Yspring_kill_wB, Xeater_n, Xeater_e, Xeater_w, Xeater_s, Yeater_n, Yeater_nB, Yeater_e, Yeater_eB, Yeater_s, Yeater_sB, Yeater_w, Yeater_wB, Yeater_stone, Yeater_spring, Xalien, Xalien_pause, Yalien_n, Yalien_nB, Yalien_e, Yalien_eB, Yalien_s, Yalien_sB, Yalien_w, Yalien_wB, Yalien_stone, Yalien_spring, Xemerald, Xemerald_pause, Xemerald_fall, Xemerald_shine, Yemerald_s, Yemerald_sB, Yemerald_e, Yemerald_eB, Yemerald_w, Yemerald_wB, Yemerald_eat, Yemerald_stone, Xdiamond, Xdiamond_pause, Xdiamond_fall, Xdiamond_shine, Ydiamond_s, Ydiamond_sB, Ydiamond_e, Ydiamond_eB, Ydiamond_w, Ydiamond_wB, Ydiamond_eat, Ydiamond_stone, Xdrip_fall, Xdrip_stretch, Xdrip_stretchB, Xdrip_eat, Ydrip_s1, Ydrip_s1B, Ydrip_s2, Ydrip_s2B, Xbomb, Xbomb_pause, Xbomb_fall, Ybomb_s, Ybomb_sB, Ybomb_e, Ybomb_eB, Ybomb_w, Ybomb_wB, Ybomb_eat, Xballoon, Yballoon_n, Yballoon_nB, Yballoon_e, Yballoon_eB, Yballoon_s, Yballoon_sB, Yballoon_w, Yballoon_wB, Xgrass, Ygrass_nB, Ygrass_eB, Ygrass_sB, Ygrass_wB, Xdirt, Ydirt_nB, Ydirt_eB, Ydirt_sB, Ydirt_wB, Xacid_ne, Xacid_se, Xacid_s, Xacid_sw, Xacid_nw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xball_1, Xball_1B, Xball_2, Xball_2B, Yball_eat, Xgrow_ns, Ygrow_ns_eat, Xgrow_ew, Ygrow_ew_eat, Xwonderwall, XwonderwallB, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xamoeba_5, Xamoeba_6, Xamoeba_7, Xamoeba_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xwind_n, Xwind_e, Xwind_s, Xwind_w, Xwind_nesw, Xwind_stop, Xexit, Xexit_1, Xexit_2, Xexit_3, Xdynamite, Ydynamite_eat, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xbumper, XbumperB, Xwheel, XwheelB, Xswitch, XswitchB, Xsand, Xsand_stone, Xsand_stonein_1, Xsand_stonein_2, Xsand_stonein_3, Xsand_stonein_4, Xsand_stonesand_1, Xsand_stonesand_2, Xsand_stonesand_3, Xsand_stonesand_4, Xsand_stoneout_1, Xsand_stoneout_2, Xsand_sandstone_1, Xsand_sandstone_2, Xsand_sandstone_3, Xsand_sandstone_4, Xplant, Yplant, Xlenses, Xmagnify, Xdripper, XdripperB, Xfake_blank, Xfake_blankB, Xfake_grass, Xfake_grassB, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, Xwall_1, Xwall_2, Xwall_3, Xwall_4, Xround_wall_1, Xround_wall_2, Xround_wall_3, Xround_wall_4, Xdecor_1, Xdecor_2, Xdecor_3, Xdecor_4, Xdecor_5, Xdecor_6, Xdecor_7, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_11, Xdecor_12, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_excla, Xalpha_quote, Xalpha_comma, Xalpha_minus, Xalpha_perio, Xalpha_colon, Xalpha_quest, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_arrow_e, Xalpha_arrow_w, Xalpha_copyr, Xboom_bug, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_bomb, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_android, /* passed from explode to synchro; transition to boom_2 */ Xboom_1, /* passed from explode to synchro; transition to boom_2 */ Xboom_2, /* transition to boom[] */ Znormal, /* no picture */ /* this tile is passed from synchro to explode, only in next[] */ Zdynamite, /* no picture */ /* this tile is passed from synchro to explode, only in next[] */ Zplayer, /* no picture */ /* special code to indicate player */ ZBORDER, /* no picture */ /* special code to indicate border */ TILE_MAX }; enum { SPR_still = 0, SPR_walk = 1, SPR_push = 5, SPR_spray = 9, SPR_MAX = 13 }; #endif extern unsigned char tab_blank[TILE_MAX]; extern unsigned char tab_acid[TILE_MAX]; extern unsigned char tab_amoeba[TILE_MAX]; extern unsigned char tab_android_move[TILE_MAX]; extern unsigned short tab_explode_normal[TILE_MAX]; extern unsigned short tab_explode_dynamite[TILE_MAX]; extern unsigned short map_obj[8][TILE_MAX]; extern unsigned short map_spr[2][8][SPR_MAX]; extern unsigned short map_ttl[128]; #endif rocksndiamonds-3.3.0.1+dfsg1/src/game_em/level.h0000644000175000017500000000007610407325712020273 0ustar dimkadimka#ifndef LEVEL_H #define LEVEL_H #include "main_em.h" #endif rocksndiamonds-3.3.0.1+dfsg1/src/game_em/main_em.h0000644000175000017500000001233511363372151020573 0ustar dimkadimka#ifndef MAIN_EM_H #define MAIN_EM_H /* ========================================================================= */ /* external functions and definitions imported from main program to game_em */ /* ========================================================================= */ #include "../engines.h" /* ========================================================================= */ /* functions and definitions that are exported from game_em to main program */ /* ========================================================================= */ #include "export.h" /* ========================================================================= */ /* internal functions and definitions that are not exported to main program */ /* ========================================================================= */ #include "global.h" #include "sample.h" /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* values for native Emerald Mine game version */ #define FILE_VERSION_EM_UNKNOWN 0 #define FILE_VERSION_EM_V1 1 #define FILE_VERSION_EM_V2 2 #define FILE_VERSION_EM_V3 3 #define FILE_VERSION_EM_V4 4 /* (there really was no version 4) */ #define FILE_VERSION_EM_V5 5 #define FILE_VERSION_EM_V6 6 #define FILE_VERSION_EM_ACTUAL FILE_VERSION_EM_V6 /* level sizes and positions for EM engine */ #define WIDTH EM_MAX_CAVE_WIDTH #define HEIGHT EM_MAX_CAVE_HEIGHT /* screen sizes and positions for EM engine */ #define ORIG_TILEX 16 #define ORIG_TILEY 16 #define ORIG_SCOREX 8 #define ORIG_SCOREY 9 #define ORIG_GFXMENUFONTX 14 #define ORIG_GFXMENUFONTY 16 #define ORIG_MENUFONTX 12 #define ORIG_MENUFONTY 16 #define ZOOM_FACTOR 2 #define TILEX (ORIG_TILEX * ZOOM_FACTOR) #define TILEY (ORIG_TILEY * ZOOM_FACTOR) #define SCOREX (ORIG_SCOREX * ZOOM_FACTOR) #define SCOREY (ORIG_SCOREY * ZOOM_FACTOR) #define GFXMENUFONTX (ORIG_GFXMENUFONTX * ZOOM_FACTOR) #define GFXMENUFONTY (ORIG_GFXMENUFONTY * ZOOM_FACTOR) #define MENUFONTX (ORIG_MENUFONTX * ZOOM_FACTOR) #define MENUFONTY (ORIG_MENUFONTY * ZOOM_FACTOR) #define ORIG_SCR_MENUX 20 #define ORIG_SCR_MENUY 12 #define SCR_MENUX 17 #define SCR_MENUY 12 #if 1 extern int SCR_FIELDX, SCR_FIELDY; #else #define SCR_FIELDX 17 #define SCR_FIELDY 17 #endif #define MAX_BUF_XSIZE (SCR_FIELDX + 2) #define MAX_BUF_YSIZE (SCR_FIELDY + 2) /* often used screen positions */ #define ORIG_MENU_SX ((ORIG_SCR_MENUX - SCR_MENUX) * TILEX / 2) #define ORIG_MENU_SY 0 #if 1 extern int SX, SY; #else #define SX 8 #define SY 8 #endif #define SXSIZE (SCR_FIELDX * TILEX) #define SYSIZE (SCR_FIELDY * TILEY) /* other settings */ #define PLAY_ELEMENT_SOUND FALSE /* ------------------------------------------------------------------------- */ /* macro function definitions */ /* ------------------------------------------------------------------------- */ #define ROUNDED_DIVIDE(x, y) (((x) + (y) - 1) / (y)) #define SECONDS_TO_FRAMES(x) ((x) * FRAMES_PER_SECOND) #define FRAMES_TO_SECONDS(x) ((x) / FRAMES_PER_SECOND) #define SECONDS_TO_CYCLES(x) ROUNDED_DIVIDE((x) * FRAMES_PER_SECOND, 8) #define CYCLES_TO_SECONDS(x) ROUNDED_DIVIDE((x) * 8, FRAMES_PER_SECOND) #define DISPLAY_TIME(x) ROUNDED_DIVIDE(x, FRAMES_PER_SECOND) /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* exported variables */ /* ------------------------------------------------------------------------- */ extern unsigned long RandomEM; extern struct LEVEL lev; extern struct PLAYER ply[MAX_PLAYERS]; extern struct LevelInfo_EM native_em_level; extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; extern short **Boom; extern short **Cave; extern short **Next; extern short **Draw; extern struct GameInfo_EM game_em; extern unsigned char tab_blank[TILE_MAX]; extern unsigned char tab_acid[TILE_MAX]; extern unsigned char tab_amoeba[TILE_MAX]; extern unsigned char tab_android_move[TILE_MAX]; extern unsigned short tab_explode_normal[TILE_MAX]; extern unsigned short tab_explode_dynamite[TILE_MAX]; extern unsigned short map_obj[8][TILE_MAX]; extern unsigned short map_spr[2][8][SPR_MAX]; extern unsigned short map_ttl[128]; extern Bitmap *screenBitmap; extern Bitmap *scoreBitmap; extern Bitmap *objBitmap; extern Bitmap *sprBitmap; extern Bitmap *ttlBitmap; extern Bitmap *botBitmap; extern Pixmap screenPixmap; extern Pixmap scorePixmap; extern Pixmap spriteBitmap; extern Pixmap objmaskBitmap; extern Pixmap sprmaskBitmap; extern GC spriteGC; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ #endif /* MAIN_EM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/cave.c0000644000175000017500000000442410460435546020104 0ustar dimkadimka/* 2000-08-10T16:43:50Z * * cave data structures */ #include "main_em.h" struct LevelInfo_EM native_em_level; void setLevelInfoToDefaults_EM(void) { int i; native_em_level.file_version = FILE_VERSION_EM_ACTUAL; native_em_level.lev = &lev; for (i = 0; i < MAX_PLAYERS; i++) native_em_level.ply[i] = &ply[i]; lev.width = 64; lev.height = 32; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].x_initial = 0; ply[i].y_initial = 0; } lev.lenses_cnt_initial = 0; lev.magnify_cnt_initial = 0; lev.wheel_cnt_initial = 0; lev.wheel_x_initial = 1; lev.wheel_y_initial = 1; lev.wind_time = 9999; lev.wind_cnt_initial = 0; lev.wonderwall_state_initial = 0; lev.wonderwall_time_initial = 0; lev.num_ball_arrays = 8; for (i = 0; i < TILE_MAX; i++) lev.android_array[i] = Xblank; #if 1 /* initial number of players in this level */ lev.home_initial = 0; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].exists = 0; ply[i].alive_initial = FALSE; } #else /* initial number of players in this level */ lev.home_initial = (setup.team_mode ? 2 : 1); for (i = 0; i < MAX_PLAYERS; i++) { ply[i].exists = 0; ply[i].alive_initial = (lev.home_initial > i ? TRUE : FALSE); } #endif } /* load cave * * completely initializes the level structure, ready for a game */ #define MAX_EM_LEVEL_SIZE 16384 boolean LoadNativeLevel_EM(char *filename) { unsigned char raw_leveldata[MAX_EM_LEVEL_SIZE]; int raw_leveldata_length; int file_version; FILE *file; /* always start with reliable default values */ setLevelInfoToDefaults_EM(); if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot open level '%s' -- using empty level", filename); return FALSE; } raw_leveldata_length = fread(raw_leveldata, 1, MAX_EM_LEVEL_SIZE, file); fclose(file); if (raw_leveldata_length <= 0) { Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return FALSE; } file_version = cleanup_em_level(raw_leveldata, raw_leveldata_length,filename); if (file_version == FILE_VERSION_EM_UNKNOWN) { Error(ERR_WARN, "unknown EM level '%s' -- using empty level", filename); return FALSE; } convert_em_level(raw_leveldata, file_version); prepare_em_level(); return TRUE; } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/graphics.c0000644000175000017500000007627611375261452021003 0ustar dimkadimka/* 2000-08-13T14:36:17Z * * graphics manipulation crap */ #include "main_em.h" #define MIN_SCREEN_XPOS 1 #define MIN_SCREEN_YPOS 1 #define MAX_SCREEN_XPOS MAX(1, lev.width - (SCR_FIELDX - 1)) #define MAX_SCREEN_YPOS MAX(1, lev.height - (SCR_FIELDY - 1)) #define MIN_SCREEN_X (MIN_SCREEN_XPOS * TILEX) #define MIN_SCREEN_Y (MIN_SCREEN_YPOS * TILEY) #define MAX_SCREEN_X (MAX_SCREEN_XPOS * TILEX) #define MAX_SCREEN_Y (MAX_SCREEN_YPOS * TILEY) #define VALID_SCREEN_X(x) ((x) < MIN_SCREEN_X ? MIN_SCREEN_X : \ (x) > MAX_SCREEN_X ? MAX_SCREEN_X : (x)) #define VALID_SCREEN_Y(y) ((y) < MIN_SCREEN_Y ? MIN_SCREEN_Y : \ (y) > MAX_SCREEN_Y ? MAX_SCREEN_Y : (y)) #define PLAYER_SCREEN_X(p) ((( frame) * ply[p].oldx + \ (8 - frame) * ply[p].x) * TILEX / 8 \ - ((SCR_FIELDX - 1) * TILEX) / 2) #define PLAYER_SCREEN_Y(p) ((( frame) * ply[p].oldy + \ (8 - frame) * ply[p].y) * TILEY / 8 \ - ((SCR_FIELDY - 1) * TILEY) / 2) #define USE_EXTENDED_GRAPHICS_ENGINE 1 int frame; /* current screen frame */ int screen_x, screen_y; /* current scroll position */ /* tiles currently on screen */ #if 1 static int screentiles[MAX_PLAYFIELD_HEIGHT + 2][MAX_PLAYFIELD_WIDTH + 2]; static int crumbled_state[MAX_PLAYFIELD_HEIGHT + 2][MAX_PLAYFIELD_WIDTH + 2]; static boolean redraw[MAX_PLAYFIELD_WIDTH + 2][MAX_PLAYFIELD_HEIGHT + 2]; #else static int screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE]; static int crumbled_state[MAX_BUF_YSIZE][MAX_BUF_XSIZE]; static boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; #endif #if 0 #if 1 int centered_player_nr; #else static int centered_player_nr; #endif #endif /* copy the entire screen to the window at the scroll position */ void BlitScreenToBitmap_EM(Bitmap *target_bitmap) { int x = screen_x % (MAX_BUF_XSIZE * TILEX); int y = screen_y % (MAX_BUF_YSIZE * TILEY); if (x < 2 * TILEX && y < 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY); } else if (x < 2 * TILEX && y >= 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, SCR_FIELDX * TILEX, MAX_BUF_YSIZE * TILEY - y, SX, SY); BlitBitmap(screenBitmap, target_bitmap, x, 0, SCR_FIELDX * TILEX, y - 2 * TILEY, SX, SY + MAX_BUF_YSIZE * TILEY - y); } else if (x >= 2 * TILEX && y < 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, MAX_BUF_XSIZE * TILEX - x, SCR_FIELDY * TILEY, SX, SY); BlitBitmap(screenBitmap, target_bitmap, 0, y, x - 2 * TILEX, SCR_FIELDY * TILEY, SX + MAX_BUF_XSIZE * TILEX - x, SY); } else { BlitBitmap(screenBitmap, target_bitmap, x, y, MAX_BUF_XSIZE * TILEX - x, MAX_BUF_YSIZE * TILEY - y, SX, SY); BlitBitmap(screenBitmap, target_bitmap, 0, y, x - 2 * TILEX, MAX_BUF_YSIZE * TILEY - y, SX + MAX_BUF_XSIZE * TILEX - x, SY); BlitBitmap(screenBitmap, target_bitmap, x, 0, MAX_BUF_XSIZE * TILEX - x, y - 2 * TILEY, SX, SY + MAX_BUF_YSIZE * TILEY - y); BlitBitmap(screenBitmap, target_bitmap, 0, 0, x - 2 * TILEX, y - 2 * TILEY, SX + MAX_BUF_XSIZE * TILEX - x, SY + MAX_BUF_YSIZE * TILEY - y); } } void BackToFront_EM(void) { static int screen_x_last = -1, screen_y_last = -1; static boolean scrolling_last = FALSE; int left = screen_x / TILEX; int top = screen_y / TILEY; #if 1 boolean scrolling = (screen_x != screen_x_last || screen_y != screen_y_last); #else boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0); #endif int x, y; #if 0 printf("::: %d, %d\n", screen_x, screen_y); #endif SyncDisplay(); if (redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last) { /* blit all (up to four) parts of the scroll buffer to the backbuffer */ BlitScreenToBitmap_EM(backbuffer); /* blit the completely updated backbuffer to the window (in one blit) */ BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY); } else { #if 1 #if 1 boolean half_shifted_x = (screen_x % TILEX != 0); boolean half_shifted_y = (screen_y % TILEY != 0); #else boolean half_shifted_x = (EVEN(SCR_FIELDX) && screen_x % TILEX != 0); boolean half_shifted_y = (EVEN(SCR_FIELDY) && screen_y % TILEY != 0); #endif #if 0 #if 1 printf("::: %d, %d\n", EVEN(SCR_FIELDX), screen_x); #else half_shifted_x = TRUE; half_shifted_y = FALSE; #endif #endif int x1 = 0, x2 = SCR_FIELDX - (half_shifted_x ? 0 : 1); int y1 = 0, y2 = SCR_FIELDY - (half_shifted_y ? 0 : 1); int scroll_xoffset = (half_shifted_x ? TILEX / 2 : 0); int scroll_yoffset = (half_shifted_y ? TILEY / 2 : 0); InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE); for (x = x1; x <= x2; x++) { for (y = y1; y <= y2; y++) { int xx = (left + x) % MAX_BUF_XSIZE; int yy = (top + y) % MAX_BUF_YSIZE; if (redraw[xx][yy]) BlitBitmap(screenBitmap, window, xx * TILEX, yy * TILEY, TILEX, TILEY, SX + x * TILEX - scroll_xoffset, SY + y * TILEY - scroll_yoffset); } } InitGfxClipRegion(FALSE, -1, -1, -1, -1); #else for (x = 0; x < SCR_FIELDX; x++) { for (y = 0; y < SCR_FIELDY; y++) { int xx = (left + x) % MAX_BUF_XSIZE; int yy = (top + y) % MAX_BUF_YSIZE; if (redraw[xx][yy]) BlitBitmap(screenBitmap, window, xx * TILEX, yy * TILEY, TILEX, TILEY, SX + x * TILEX, SY + y * TILEY); } } #endif } FlushDisplay(); for (x = 0; x < MAX_BUF_XSIZE; x++) for (y = 0; y < MAX_BUF_YSIZE; y++) redraw[x][y] = FALSE; redraw_tiles = 0; screen_x_last = screen_x; screen_y_last = screen_y; scrolling_last = scrolling; } void blitscreen(void) { BackToFront_EM(); } static struct GraphicInfo_EM *getObjectGraphic(int x, int y) { int tile = Draw[y][x]; struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame]; if (!game.use_native_emc_graphics_engine) getGraphicSourceObjectExt_EM(g, tile, 7 - frame, x - 2, y - 2); return g; } static struct GraphicInfo_EM *getPlayerGraphic(int player_nr, int anim) { struct GraphicInfo_EM *g = &graphic_info_em_player[player_nr][anim][frame]; if (!game.use_native_emc_graphics_engine) getGraphicSourcePlayerExt_EM(g, player_nr, anim, 7 - frame); return g; } static void DrawLevelField_EM(int x, int y, int sx, int sy, boolean draw_masked) { struct GraphicInfo_EM *g = getObjectGraphic(x, y); int src_x = g->src_x + g->src_offset_x; int src_y = g->src_y + g->src_offset_y; int dst_x = sx * TILEX + g->dst_offset_x; int dst_y = sy * TILEY + g->dst_offset_y; int width = g->width; int height = g->height; int left = screen_x / TILEX; int top = screen_y / TILEY; /* do not draw fields that are outside the visible screen area */ if (x < left || x >= left + MAX_BUF_XSIZE || y < top || y >= top + MAX_BUF_YSIZE) return; if (draw_masked) { if (width > 0 && height > 0) { SetClipOrigin(g->bitmap, g->bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(g->bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } } else { if ((width != TILEX || height != TILEY) && !g->preserve_background) ClearRectangle(screenBitmap, sx * TILEX, sy * TILEY, TILEX, TILEY); if (width > 0 && height > 0) BlitBitmap(g->bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } } static void DrawLevelFieldCrumbled_EM(int x, int y, int sx, int sy, int crm, boolean draw_masked) { #if 1 struct GraphicInfo_EM *g; #else struct GraphicInfo_EM *g = getObjectGraphic(x, y); #endif int left = screen_x / TILEX; int top = screen_y / TILEY; int i; /* do not draw fields that are outside the visible screen area */ if (x < left || x >= left + MAX_BUF_XSIZE || y < top || y >= top + MAX_BUF_YSIZE) return; if (crm == 0) /* no crumbled edges for this tile */ return; #if 1 g = getObjectGraphic(x, y); #endif #if 0 if (x == 3 && y == 3 && frame == 0) printf("::: %d, %d\n", graphic_info_em_object[207][0].crumbled_src_x, graphic_info_em_object[207][0].crumbled_src_y); #endif for (i = 0; i < 4; i++) { if (crm & (1 << i)) { int width, height, cx, cy; if (i == 1 || i == 2) { width = g->crumbled_border_size; height = TILEY; cx = (i == 2 ? TILEX - g->crumbled_border_size : 0); cy = 0; } else { width = TILEX; height = g->crumbled_border_size; cx = 0; cy = (i == 3 ? TILEY - g->crumbled_border_size : 0); } if (width > 0 && height > 0) { int src_x = g->crumbled_src_x + cx; int src_y = g->crumbled_src_y + cy; int dst_x = sx * TILEX + cx; int dst_y = sy * TILEY + cy; if (draw_masked) { SetClipOrigin(g->crumbled_bitmap, g->crumbled_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(g->crumbled_bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(g->crumbled_bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } } } } static void DrawLevelPlayer_EM(int x1, int y1, int player_nr, int anim, boolean draw_masked) { struct GraphicInfo_EM *g = getPlayerGraphic(player_nr, anim); int src_x = g->src_x, src_y = g->src_y; int dst_x, dst_y; /* do not draw fields that are outside the visible screen area */ if (x1 < screen_x - TILEX || x1 >= screen_x + MAX_BUF_XSIZE * TILEX || y1 < screen_y - TILEY || y1 >= screen_y + MAX_BUF_YSIZE * TILEY) return; x1 %= MAX_BUF_XSIZE * TILEX; y1 %= MAX_BUF_YSIZE * TILEY; if (draw_masked) { /* draw the player to current location */ dst_x = x1; dst_y = y1; SetClipOrigin(g->bitmap, g->bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(g->bitmap, screenBitmap, src_x, src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around column */ dst_x = x1 - MAX_BUF_XSIZE * TILEX; dst_y = y1; SetClipOrigin(g->bitmap, g->bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around row */ dst_x = x1; dst_y = y1 - MAX_BUF_YSIZE * TILEY; SetClipOrigin(g->bitmap, g->bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); } else { /* draw the player to current location */ dst_x = x1; dst_y = y1; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around column */ dst_x = x1 - MAX_BUF_XSIZE * TILEX; dst_y = y1; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around row */ dst_x = x1; dst_y = y1 - MAX_BUF_YSIZE * TILEY; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); } } /* draw differences between game tiles and screen tiles * * implicitly handles scrolling and restoring background under the sprites */ static void animscreen(void) { int x, y, i; int left = screen_x / TILEX; int top = screen_y / TILEY; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!game.use_native_emc_graphics_engine) for (y = 2; y < EM_MAX_CAVE_HEIGHT - 2; y++) for (x = 2; x < EM_MAX_CAVE_WIDTH - 2; x++) SetGfxAnimation_EM(&graphic_info_em_object[Draw[y][x]][frame], Draw[y][x], 7 - frame, x - 2, y - 2); for (y = top; y < top + MAX_BUF_YSIZE; y++) { for (x = left; x < left + MAX_BUF_XSIZE; x++) { int sx = x % MAX_BUF_XSIZE; int sy = y % MAX_BUF_YSIZE; int tile = Draw[y][x]; struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame]; int obj = g->unique_identifier; int crm = 0; boolean redraw_screen_tile = FALSE; /* re-calculate crumbled state of this tile */ if (g->has_crumbled_graphics) { for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int tile_next; if (xx < 0 || xx >= EM_MAX_CAVE_WIDTH || yy < 0 || yy >= EM_MAX_CAVE_HEIGHT) continue; tile_next = Draw[yy][xx]; if (!graphic_info_em_object[tile_next][frame].has_crumbled_graphics) crm |= (1 << i); } } redraw_screen_tile = (screentiles[sy][sx] != obj || crumbled_state[sy][sx] != crm); #if 0 /* !!! TEST ONLY -- CHANGE THIS !!! */ if (!game.use_native_emc_graphics_engine) redraw_screen_tile = TRUE; #endif /* only redraw screen tiles if they (or their crumbled state) changed */ if (redraw_screen_tile) { DrawLevelField_EM(x, y, sx, sy, FALSE); DrawLevelFieldCrumbled_EM(x, y, sx, sy, crm, FALSE); screentiles[sy][sx] = obj; crumbled_state[sy][sx] = crm; redraw[sx][sy] = TRUE; redraw_tiles++; } } } } /* blit players to the screen * * handles transparency and movement */ static void blitplayer(struct PLAYER *ply) { int x1, y1, x2, y2; if (!ply->alive) return; /* x1/y1 are left/top and x2/y2 are right/down part of the player movement */ x1 = (frame * ply->oldx + (8 - frame) * ply->x) * TILEX / 8; y1 = (frame * ply->oldy + (8 - frame) * ply->y) * TILEY / 8; x2 = x1 + TILEX - 1; y2 = y1 + TILEY - 1; #if 0 printf("::: %d, %d\n", x1, y1); #endif if ((int)(x2 - screen_x) < ((MAX_BUF_XSIZE - 1) * TILEX - 1) && (int)(y2 - screen_y) < ((MAX_BUF_YSIZE - 1) * TILEY - 1)) { /* some casts to "int" are needed because of negative calculation values */ int dx = (int)ply->x - (int)ply->oldx; int dy = (int)ply->y - (int)ply->oldy; int old_x = (int)ply->oldx + (7 - (int)frame) * dx / 8; int old_y = (int)ply->oldy + (7 - (int)frame) * dy / 8; int new_x = old_x + SIGN(dx); int new_y = old_y + SIGN(dy); int old_sx = old_x % MAX_BUF_XSIZE; int old_sy = old_y % MAX_BUF_XSIZE; int new_sx = new_x % MAX_BUF_XSIZE; int new_sy = new_y % MAX_BUF_XSIZE; #if 0 int old_crm = crumbled_state[old_sy][old_sx]; #endif int new_crm = crumbled_state[new_sy][new_sx]; /* only diggable elements can be crumbled in the classic EM engine */ boolean player_is_digging = (new_crm != 0); #if 0 x1 %= MAX_BUF_XSIZE * TILEX; y1 %= MAX_BUF_YSIZE * TILEY; x2 %= MAX_BUF_XSIZE * TILEX; y2 %= MAX_BUF_YSIZE * TILEY; #endif if (player_is_digging) { #if 0 /* draw the field the player is moving from (under the player) */ DrawLevelField_EM(old_x, old_y, old_sx, old_sy, FALSE); DrawLevelFieldCrumbled_EM(old_x, old_y, old_sx, old_sy, old_crm, FALSE); #endif /* draw the field the player is moving to (under the player) */ DrawLevelField_EM(new_x, new_y, new_sx, new_sy, FALSE); DrawLevelFieldCrumbled_EM(new_x, new_y, new_sx, new_sy, new_crm, FALSE); /* draw the player (masked) over the element he is just digging away */ DrawLevelPlayer_EM(x1, y1, ply->num, ply->anim, TRUE); #if 1 /* draw the field the player is moving from (masked over the player) */ DrawLevelField_EM(old_x, old_y, old_sx, old_sy, TRUE); #endif } else { /* draw the player under the element which is on the same field */ DrawLevelPlayer_EM(x1, y1, ply->num, ply->anim, FALSE); /* draw the field the player is moving from (masked over the player) */ DrawLevelField_EM(old_x, old_y, old_sx, old_sy, TRUE); /* draw the field the player is moving to (masked over the player) */ DrawLevelField_EM(new_x, new_y, new_sx, new_sy, TRUE); } /* redraw screen tiles in the next frame (player may have left the tiles) */ screentiles[old_sy][old_sx] = -1; screentiles[new_sy][new_sx] = -1; /* mark screen tiles as dirty (force screen refresh with changed content) */ redraw[old_sx][old_sy] = TRUE; redraw[new_sx][new_sy] = TRUE; redraw_tiles += 2; } } void game_initscreen(void) { int x,y; int dynamite_state = ply[0].dynamite; /* !!! ONLY PLAYER 1 !!! */ int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys; int player_nr; frame = 6; #if 0 game.centered_player_nr = getCenteredPlayerNr_EM(); #endif player_nr = (game.centered_player_nr != -1 ? game.centered_player_nr : 0); screen_x = VALID_SCREEN_X(PLAYER_SCREEN_X(player_nr)); screen_y = VALID_SCREEN_Y(PLAYER_SCREEN_Y(player_nr)); for (y = 0; y < MAX_BUF_YSIZE; y++) { for (x = 0; x < MAX_BUF_XSIZE; x++) { screentiles[y][x] = -1; crumbled_state[y][x] = 0; } } DrawAllGameValues(lev.required, dynamite_state, lev.score, lev.time, all_keys_state); } #if 0 void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation) { boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); int jx = player->jx; int jy = player->jy; if (quick_relocation) { int offset = game.scroll_delay_value; if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) { scroll_x = (player->jx < SBX_Left + MIDPOSX ? SBX_Left : player->jx > SBX_Right + MIDPOSX ? SBX_Right : player->jx - MIDPOSX); scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : player->jy - MIDPOSY); } else { if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) || (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset)) scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset); if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) || (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset)) scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset); /* don't scroll over playfield boundaries */ if (scroll_x < SBX_Left || scroll_x > SBX_Right) scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); /* don't scroll over playfield boundaries */ if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); } RedrawPlayfield(TRUE, 0,0,0,0); } else { int scroll_xx = -999, scroll_yy = -999; ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ while (scroll_xx != scroll_x || scroll_yy != scroll_y) { int dx = 0, dy = 0; int fx = FX, fy = FY; scroll_xx = (player->jx < SBX_Left + MIDPOSX ? SBX_Left : player->jx > SBX_Right + MIDPOSX ? SBX_Right : player->jx - MIDPOSX); scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : player->jy - MIDPOSY); dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; scroll_x -= dx; scroll_y -= dy; fx += dx * TILEX / 2; fy += dy * TILEY / 2; ScrollLevel(dx, dy); DrawAllPlayers(); /* scroll in two steps of half tile size to make things smoother */ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); FlushDisplay(); Delay(wait_delay_value); /* scroll second step to align at full tile size */ BackToFront(); Delay(wait_delay_value); } DrawPlayer(player); BackToFront(); Delay(wait_delay_value); } } #endif static int getMaxCenterDistancePlayerNr(int center_x, int center_y) { int max_dx = 0, max_dy = 0; int player_nr = game_em.last_moving_player; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].alive) { int sx = PLAYER_SCREEN_X(i); int sy = PLAYER_SCREEN_Y(i); if (game_em.last_player_direction[i] != MV_NONE && (ABS(sx - center_x) > max_dx || ABS(sy - center_y) > max_dy)) { max_dx = MAX(max_dx, ABS(sx - center_x)); max_dy = MAX(max_dy, ABS(sy - center_y)); player_nr = i; } } } return player_nr; } static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2) { boolean num_checked_players = 0; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].alive) { int sx = PLAYER_SCREEN_X(i); int sy = PLAYER_SCREEN_Y(i); if (num_checked_players == 0) { *sx1 = *sx2 = sx; *sy1 = *sy2 = sy; } else { *sx1 = MIN(*sx1, sx); *sy1 = MIN(*sy1, sy); *sx2 = MAX(*sx2, sx); *sy2 = MAX(*sy2, sy); } num_checked_players++; } } } boolean checkIfAllPlayersFitToScreen() { int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); return (sx2 - sx1 <= SCR_FIELDX * TILEX && sy2 - sy1 <= SCR_FIELDY * TILEY); } static void setScreenCenteredToAllPlayers(int *sx, int *sy) { int sx1 = screen_x, sy1 = screen_y, sx2 = screen_x, sy2 = screen_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *sx = (sx1 + sx2) / 2; *sy = (sy1 + sy2) / 2; } static void setMaxCenterDistanceForAllPlayers(int *max_dx, int *max_dy, int center_x, int center_y) { int sx1 = center_x, sy1 = center_y, sx2 = center_x, sy2 = center_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *max_dx = MAX(ABS(sx1 - center_x), ABS(sx2 - center_x)); *max_dy = MAX(ABS(sy1 - center_y), ABS(sy2 - center_y)); } static boolean checkIfAllPlayersAreVisible(int center_x, int center_y) { int max_dx, max_dy; setMaxCenterDistanceForAllPlayers(&max_dx, &max_dy, center_x, center_y); return (max_dx <= SCR_FIELDX * TILEX / 2 && max_dy <= SCR_FIELDY * TILEY / 2); } void RedrawPlayfield_EM(boolean force_redraw) { #if 0 boolean all_players_visible = checkIfAllPlayersAreVisible(); #endif boolean draw_new_player_location = FALSE; boolean quick_relocation = setup.quick_switch; #if 0 boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0); #endif #if 0 boolean game.set_centered_player = getSetCenteredPlayer_EM(); int game.centered_player_nr_next = getCenteredPlayerNr_EM(); #endif #if 1 int max_center_distance_player_nr = getMaxCenterDistancePlayerNr(screen_x, screen_y); #else int player_nr = game_em.last_moving_player; #endif int stepsize = TILEX / 8; int offset = game.scroll_delay_value * TILEX; int offset_x = offset; int offset_y = offset; int screen_x_old = screen_x; int screen_y_old = screen_y; int x, y, sx, sy; int i; if (game.set_centered_player) { boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen(); /* switching to "all players" only possible if all players fit to screen */ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } /* do not switch focus to non-existing (or non-active) player */ if (game.centered_player_nr_next >= 0 && !ply[game.centered_player_nr_next].alive) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } } #if 1 /* also allow focus switching when screen is scrolled to half tile */ #else if (!scrolling) /* screen currently aligned at tile position */ #endif { #if 1 if (game.set_centered_player) #else if (game.centered_player_nr != game.centered_player_nr_next) #endif { game.centered_player_nr = game.centered_player_nr_next; draw_new_player_location = TRUE; force_redraw = TRUE; game.set_centered_player = FALSE; } } if (game.centered_player_nr == -1) { #if 1 if (draw_new_player_location || offset == 0) #else if (draw_new_player_location) #endif { setScreenCenteredToAllPlayers(&sx, &sy); } else { #if 1 sx = PLAYER_SCREEN_X(max_center_distance_player_nr); sy = PLAYER_SCREEN_Y(max_center_distance_player_nr); #else sx = PLAYER_SCREEN_X(game_em.last_moving_player); sy = PLAYER_SCREEN_Y(game_em.last_moving_player); #endif } } else { sx = PLAYER_SCREEN_X(game.centered_player_nr); sy = PLAYER_SCREEN_Y(game.centered_player_nr); } if (draw_new_player_location && quick_relocation) { screen_x = VALID_SCREEN_X(sx); screen_y = VALID_SCREEN_Y(sy); screen_x_old = screen_x; screen_y_old = screen_y; #if 0 offset_x = 0; offset_y = 0; #endif } if (draw_new_player_location && !quick_relocation) { #if 1 unsigned long game_frame_delay_value = getGameFrameDelay_EM(20); #else unsigned long game_frame_delay_value = getGameFrameDelay_EM(25); #endif int wait_delay_value = game_frame_delay_value; int screen_xx = VALID_SCREEN_X(sx); int screen_yy = VALID_SCREEN_Y(sy); while (screen_x != screen_xx || screen_y != screen_yy) { int dx = (screen_xx < screen_x ? +1 : screen_xx > screen_x ? -1 : 0); int dy = (screen_yy < screen_y ? +1 : screen_yy > screen_y ? -1 : 0); int dxx = 0, dyy = 0; if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; #if 1 if (ABS(screen_xx - screen_x) >= TILEX) { screen_x -= dx * TILEX; dxx = dx * TILEX / 2; } else { screen_x = screen_xx; dxx = 0; } if (ABS(screen_yy - screen_y) >= TILEY) { screen_y -= dy * TILEY; dyy = dy * TILEY / 2; } else { screen_y = screen_yy; dyy = 0; } #else #if 1 if (ABS(screen_xx - screen_x) >= TILEX || ABS(screen_yy - screen_y) >= TILEY) { screen_x -= dx * TILEX; screen_y -= dy * TILEY; dxx = dx * TILEX / 2; dyy = dy * TILEY / 2; } else { screen_x = screen_xx; screen_y = screen_yy; dxx = 0; dyy = 0; } #else screen_x -= dx * TILEX; screen_y -= dy * TILEY; dxx += dx * TILEX / 2; dyy += dy * TILEY / 2; #endif #endif /* scroll in two steps of half tile size to make things smoother */ screen_x += dxx; screen_y += dyy; animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); blitscreen(); Delay(wait_delay_value); /* scroll second step to align at full tile size */ screen_x -= dxx; screen_y -= dyy; #if 0 SyncDisplay(); #endif animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); blitscreen(); Delay(wait_delay_value); } screen_x_old = screen_x; screen_y_old = screen_y; } if (force_redraw) { for (y = 0; y < MAX_BUF_YSIZE; y++) { for (x = 0; x < MAX_BUF_XSIZE; x++) { screentiles[y][x] = -1; crumbled_state[y][x] = 0; } } } /* calculate new screen scrolling position, with regard to scroll delay */ screen_x = VALID_SCREEN_X(sx + offset_x < screen_x ? sx + offset_x : sx - offset_x > screen_x ? sx - offset_x : screen_x); screen_y = VALID_SCREEN_Y(sy + offset_y < screen_y ? sy + offset_y : sy - offset_y > screen_y ? sy - offset_y : screen_y); #if 0 printf("::: (%d, %d) => (%d, %d) [(%d, %d), (%d, %d)] [%d, %d] [%d / %d]\n", screen_x_old, screen_y_old, screen_x, screen_y, ply[max_center_distance_player_nr].oldx, ply[max_center_distance_player_nr].x, ply[max_center_distance_player_nr].oldy, ply[max_center_distance_player_nr].y, sx, sy, ABS(screen_x - screen_x_old), ABS(screen_y - screen_y_old)); #endif #if 1 #if 1 /* prevent scrolling further than double player step size when scrolling */ if (ABS(screen_x - screen_x_old) > 2 * stepsize) { int dx = SIGN(screen_x - screen_x_old); screen_x = screen_x_old + dx * 2 * stepsize; } if (ABS(screen_y - screen_y_old) > 2 * stepsize) { int dy = SIGN(screen_y - screen_y_old); screen_y = screen_y_old + dy * 2 * stepsize; } #else /* prevent scrolling further than double player step size when scrolling */ if (ABS(screen_x - screen_x_old) > 2 * stepsize || ABS(screen_y - screen_y_old) > 2 * stepsize) { int dx = SIGN(screen_x - screen_x_old); int dy = SIGN(screen_y - screen_y_old); screen_x = screen_x_old + dx * 2 * stepsize; screen_y = screen_y_old + dy * 2 * stepsize; } #endif #else /* prevent scrolling further than player step size when scrolling */ if (ABS(screen_x - screen_x_old) > stepsize || ABS(screen_y - screen_y_old) > stepsize) { int dx = SIGN(screen_x - screen_x_old); int dy = SIGN(screen_y - screen_y_old); screen_x = screen_x_old + dx * stepsize; screen_y = screen_y_old + dy * stepsize; } #endif /* prevent scrolling away from the other players when focus on all players */ if (game.centered_player_nr == -1) { #if 1 /* check if all players are still visible with new scrolling position */ if (checkIfAllPlayersAreVisible(screen_x_old, screen_y_old) && !checkIfAllPlayersAreVisible(screen_x, screen_y)) { /* reset horizontal scroll position to last value, if needed */ if (!checkIfAllPlayersAreVisible(screen_x, screen_y_old)) screen_x = screen_x_old; /* reset vertical scroll position to last value, if needed */ if (!checkIfAllPlayersAreVisible(screen_x_old, screen_y)) screen_y = screen_y_old; } #else boolean all_players_visible = checkIfAllPlayersAreVisible(); if (!all_players_visible) { printf("::: not all players visible\n"); screen_x = screen_x_old; screen_y = screen_y_old; } #endif } /* prevent scrolling (for screen correcting) if no player is moving */ if (!game_em.any_player_moving) { screen_x = screen_x_old; screen_y = screen_y_old; } else { /* prevent scrolling against the players move direction */ #if 0 int player_nr = game_em.last_moving_player; #endif int player_nr = (game.centered_player_nr == -1 ? max_center_distance_player_nr : game.centered_player_nr); int player_move_dir = game_em.last_player_direction[player_nr]; int dx = SIGN(screen_x - screen_x_old); int dy = SIGN(screen_y - screen_y_old); if ((dx < 0 && player_move_dir != MV_LEFT) || (dx > 0 && player_move_dir != MV_RIGHT)) screen_x = screen_x_old; if ((dy < 0 && player_move_dir != MV_UP) || (dy > 0 && player_move_dir != MV_DOWN)) screen_y = screen_y_old; } animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); #if 0 #if 0 SyncDisplay(); #endif blitscreen(); #endif } void game_animscreen(void) { RedrawPlayfield_EM(FALSE); } void DrawGameDoorValues_EM() { #if 1 int dynamite_state; int key_state; #else int dynamite_state = ply[0].dynamite; /* !!! ONLY PLAYER 1 !!! */ int key_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys; #endif #if 1 if (game.centered_player_nr == -1) { #if 1 int i; dynamite_state = 0; key_state = 0; for (i = 0; i < MAX_PLAYERS; i++) { dynamite_state += ply[i].dynamite; key_state |= ply[i].keys; } #else dynamite_state = ply[0].dynamite; /* !!! ONLY PLAYER 1 !!! */ key_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys; #endif } else { int player_nr = game.centered_player_nr; dynamite_state = ply[player_nr].dynamite; key_state = ply[player_nr].keys; } #endif #if 1 DrawAllGameValues(lev.required, dynamite_state, lev.score, lev.time, key_state); #else DrawAllGameValues(lev.required, ply1.dynamite, lev.score, DISPLAY_TIME(lev.time), ply1.keys | ply2.keys); #endif } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/ulaw_generate.c0000644000175000017500000000715410151747552022013 0ustar dimkadimka/* 2000-08-10T04:29:10Z * * generate ulaw<->linear conversion tables to be included * directly in emerald mine source */ #include "main_em.h" #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) int calc_ulaw_to_linear(unsigned char); unsigned char calc_linear_to_ulaw(int); int buffer[65536]; /* convert from 8 bit ulaw to signed 16 bit linear */ short ulaw_to_linear[256]; /* convert from signed 16 bit linear to 8 bit ulaw */ unsigned char linear_to_ulaw[65536]; void ulaw_generate() { int i; for(i = 0; i < 256; i++) ulaw_to_linear[i] = calc_ulaw_to_linear(i); for(i = -32768; i < 32768; i++) linear_to_ulaw[i + 32768] = calc_linear_to_ulaw(i); } /* ** This routine converts from ulaw to 16 bit linear. ** ** Craig Reese: IDA/Supercomputing Research Center ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: 8 bit ulaw sample ** Output: signed 16 bit linear sample */ int calc_ulaw_to_linear(unsigned char ulawbyte) { static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; int sign, exponent, mantissa, sample; ulawbyte = ~ ulawbyte; sign = ( ulawbyte & 0x80 ); exponent = ( ulawbyte >> 4 ) & 0x07; mantissa = ulawbyte & 0x0F; sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) ); if (sign != 0) sample = -sample; return(sample); } /* ** This routine converts from linear to ulaw. ** ** Craig Reese: IDA/Supercomputing Research Center ** Joe Campbell: Department of Defense ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) "A New Digital Technique for Implementation of Any ** Continuous PCM Companding Law," Villeret, Michel, ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, ** 1973, pg. 11.12-11.17 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: Signed 16 bit linear sample ** Output: 8 bit ulaw sample */ #define ZEROTRAP /* turn on the trap as per the MIL-STD */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 unsigned char calc_linear_to_ulaw(int sample) { static int exp_lut[256] = { 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; int sign, exponent, mantissa; unsigned char ulawbyte; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if (sign != 0) sample = -sample; /* get magnitude */ if (sample > CLIP) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = sample + BIAS; exponent = exp_lut[( sample >> 7 ) & 0xFF]; mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F; ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa ); #ifdef ZEROTRAP if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ #endif return(ulawbyte); } #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/global.h0000644000175000017500000000231210460423312020411 0ustar dimkadimka#ifndef GLOBAL_H #define GLOBAL_H #include "main_em.h" #define EM_GFX_DIR "graphics.EM" #define EM_SND_DIR "sounds.EM" #define EM_LVL_DIR "levels.EM" /* arbitrary maximum length of filenames (cos i am lazy) */ #define MAXNAME 1024 extern int debug; extern char *progname; extern char *arg_basedir; extern int frame; extern short ulaw_to_linear[256]; extern unsigned char linear_to_ulaw[65536]; /* all global function prototypes */ int open_all(void); void close_all(void); #if 1 void readjoy(byte, struct PLAYER *); #else void readjoy(byte); #endif void input_eventloop(void); void blitscreen(void); void game_initscreen(void); void game_animscreen(void); void DrawGameDoorValues_EM(); void play_sound(int, int, int); void sound_play(void); int cave_convert(char *); boolean LoadNativeLevel_EM(char *); void game_init_vars(void); void game_play_init(int, char *); void game_loop(byte); void synchro_1(void); void synchro_2(void); void synchro_3(void); int cleanup_em_level(unsigned char *, int, char *); void convert_em_level(unsigned char *, int); void prepare_em_level(void); int sound_thread(void); int read_sample(char *, short **, long *); void read_cave_list(void); void free_cave_list(void); #endif rocksndiamonds-3.3.0.1+dfsg1/src/game_em/convert.c0000644000175000017500000010461210473153345020644 0ustar dimkadimka/* 2000-08-20T09:41:18Z * * identify all emerald mine caves and turn them into v6 format. * fixes illegal tiles, acid, wheel, limits times, cleans flags. * * these tables weed out bad tiles for older caves (eg. wheel on -> wheel off) * and clean up v6 caves (acid, number limits) which should(!) be * inconsequential, but no doubt it will break some caves. */ #include "main_em.h" #define ALLOW_ROLLING_SPRING static unsigned char remap_v6[256] = { /* filter crap for v6 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 40,41,42,43, 44,45,128,128, 128,148,148, 148,45,45,45, 148,0,57,58, 59,60,61,62,63, #ifdef ALLOW_ROLLING_SPRING 64,65,66,67, 68,69,69,71, 72,73,74,75, 118,75,75,75, #else 64,65,66,67, 68,69,69,69, 69,73,74,75, 118,75,75,75, #endif 75,75,75,75, 75,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,99, 100,68,68,68, 68,68,68,68, 68,118,118,118, 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, 160,161,162,163, 164,165,165,118, 168,169,170,171, 172,173,174,175, 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,191, 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,242,243, 244,245,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v5[256] = { /* filter crap for v5 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128, 128,148,148,148, 45,45,45,148, 0,57,58,59, 60,61,62,63, 64,65,66,67, 68,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,68,68,68,68, 68,68,68,68,118, 118,118, 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, 160,153,153,153, 153,153,153,118, 168,169,170,171, 172,173,174,175, 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,153, 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v4[256] = { /* filter crap for v4 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128, 128,148,148,148, 45,45,45,148, 0,153,153,59, 60,61,62,63, 64,65,66,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,68,154,155, 156,157,158,160, 160,160,160,160, 160,160,160,160, 160,160,160,160, 160,160,160,175, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,68,153, 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v4eater[28] = { /* filter crap for v4 */ 128,18,2,0,4,8,16,20,28,37, 41,45,130,129,131,132,133,134,135,136, 146,147,175,65,66,64,2,18 }; static boolean filename_has_v1_format(char *filename) { char *basename = getBaseNamePtr(filename); return (strlen(basename) == 3 && basename[0] == 'a' && basename[1] >= 'a' && basename[1] <= 'k' && basename[2] >= '0' && basename[2] <= '9'); } int cleanup_em_level(unsigned char *src, int length, char *filename) { int file_version = FILE_VERSION_EM_UNKNOWN; int i; if (length >= 2172 && src[2106] == 255 && /* version id: */ src[2107] == 54 && /* '6' */ src[2108] == 48 && /* '0' */ src[2109] == 48) /* '0' */ { /* ---------- this cave has V6 file format ---------- */ file_version = FILE_VERSION_EM_V6; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v6[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v6[src[i]]; for (i = 2112; i < 2148; i++) src[i] = remap_v6[src[i]]; } else if (length >= 2110 && src[2106] == 255 && /* version id: */ src[2107] == 53 && /* '5' */ src[2108] == 48 && /* '0' */ src[2109] == 48) /* '0' */ { /* ---------- this cave has V5 file format ---------- */ file_version = FILE_VERSION_EM_V5; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v5[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v5[src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; } #if 1 /* ================================================================== */ else if (length >= 2106 && (src[1983] == 27 || /* encrypted (only EM I/II/III) */ src[1983] == 116 || /* unencrypted (usual case) */ src[1983] == 131)) /* unencrypted (rare case) */ { /* ---------- this cave has V1, V2 or V3 file format ---------- */ boolean fix_copyright = FALSE; /* byte at position 1983 (0x07bf) is used as "magic byte": - 27 (0x1b) => encrypted level (V3 only / Kingsoft original games) - 116 (0x74) => unencrypted level (byte is corrected to 131 (0x83)) - 131 (0x83) => unencrypted level (happens only in very rare cases) */ if (src[1983] == 27) /* (0x1b) -- after decryption: 116 (0x74) */ { /* this is original (encrypted) Emerald Mine I, II or III level file */ int first_byte = src[0]; unsigned char code0 = 0x65; unsigned char code1 = 0x11; /* decode encrypted level data */ for (i = 0; i < 2106; i++) { src[i] ^= code0; src[i] -= code1; code0 = (code0 + 7) & 0xff; } src[1] = 131; /* needed for all Emerald Mine levels */ /* first byte is either 0xf1 (EM I and III) or 0xf5 (EM II) */ if (first_byte == 0xf5) { src[0] = 131; /* only needed for Emerald Mine II levels */ fix_copyright = TRUE; } /* ---------- this cave has V3 file format ---------- */ file_version = FILE_VERSION_EM_V3; } else if (filename_has_v1_format(filename)) { /* ---------- this cave has V1 file format ---------- */ file_version = FILE_VERSION_EM_V1; } else { /* ---------- this cave has V2 file format ---------- */ file_version = FILE_VERSION_EM_V2; } /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v4[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; if (fix_copyright) /* fix "(c)" sign in Emerald Mine II levels */ { for (i = 0; i < 2048; i++) if (src[i] == 241) src[i] = 254; /* replace 'Xdecor_1' with 'Xalpha_copyr' */ } } else { /* ---------- this cave has unknown file format ---------- */ /* if file has length of old-style level file, print (wrong) magic byte */ if (length < 2110) Error(ERR_WARN, "unknown magic byte 0x%02x at position 0x%04x", src[1983], 1983); return FILE_VERSION_EM_UNKNOWN; } #else /* ================================================================== */ #if 0 else if (length >= 2106) /* !!! TEST ONLY: SHOW BROKEN LEVELS !!! */ #else else if (length >= 2106 && src[1983] == 116) #endif { /* ---------- this cave has V4 file format ---------- */ file_version = FILE_VERSION_EM_V4; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v4[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; } else if (length >= 2106 && src[0] == 241 && /* <-- Emerald Mine I and III levels */ src[1983] == 27) { unsigned char j = 94; /* ---------- this cave has V3 file format ---------- */ file_version = FILE_VERSION_EM_V3; /* decrypt encrypted level file */ for (i = 0; i < 2106; i++) src[i] = (src[i] ^ (j += 7)) - 0x11; src[1] = 131; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v4[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; } #if 1 else if (length >= 2106 && src[0] == 245 && /* <-- Emerald Mine II levels */ src[1983] == 27) { unsigned char j = 94; /* ---------- this cave has V3 file format ---------- */ file_version = FILE_VERSION_EM_V3; /* decrypt encrypted level file */ for (i = 0; i < 2106; i++) src[i] = (src[i] ^ (j += 7)) - 0x11; src[0] = 131; /* needed for Emerald Mine II levels */ src[1] = 131; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v4[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; /* fix copyright sign in Emerald Mine II levels */ for (i = 0; i < 2048; i++) if (src[i] == 241) src[i] = 254; /* replace 'Xdecor_1' with 'Xalpha_copyr' */ } #endif else { /* ---------- this cave has unknown file format ---------- */ #if 0 printf("::: %d, %d\n", src[0], src[1983]); #endif return 0; } #endif /* ================================================================== */ if (file_version < FILE_VERSION_EM_V6) { /* id */ src[2106] = 255; /* version id: */ src[2107] = 54; /* '6' */ src[2108] = 48; /* '0' */ src[2109] = 48; /* '0' */ /* time */ i = src[2094] * 10; /* stored level time of levels for the V2 player was changed to 50% of the time for the V1 player (original V3 levels already considered this) */ if (file_version != FILE_VERSION_EM_V1 && file_version != FILE_VERSION_EM_V3) i /= 2; src[2110] = i >> 8; src[2111] = i; for (i = 2148; i < 2172; i++) src[i] = 0; /* ball data */ src[2159] = 128; #if 0 printf("::: STORED TIME (< V6): %d s\n", src[2094] * 10); #endif } #if 0 else { printf("::: STORED TIME (>= V6): %d s\n", src[2110] * 256 + src[2111]); } #endif /* ---------- at this stage, the cave data always has V6 format ---------- */ /* fix wheel */ for (i = 0; i < 2048; i++) if (src[i] == 40) break; for (i++; i < 2048; i++) if (src[i] == 40) src[i] = 147; #if 0 /* fix acid */ for (i = 64; i < 2048; i++) if (src[i] == 63) /* replace element above 'Xacid_s' ... */ src[i - 64] = 101; /* ... with 'Xacid_1' */ #else #if 1 /* fix acid */ for (i = 64; i < 2048; i++) if (src[i] == 63) /* replace element above 'Xacid_s' ... */ src[i - 64] = 101; /* ... with 'Xacid_1' */ /* fix acid with no base beneath it (see below for details (*)) */ for (i = 64; i < 2048 - 1; i++) { if (file_version <= FILE_VERSION_EM_V2 && src[i - 64] == 101 && src[i] != 63) /* acid without base */ { if (src[i - 1] == 101 || /* remove acid over acid row */ src[i + 1] == 101) src[i - 64] = 6; /* replace element above with 'Xblank' */ else src[i - 64] = 255; /* replace element above with 'Xfake_acid_1' */ } } #else /* fix acid */ for (i = 64; i < 2048; i++) { if (src[i] == 63) /* 'Xacid_s' (acid pool, bottom middle) */ { if (file_version <= FILE_VERSION_EM_V2 && i < 2048 - 64 && src[i + 64] == 63) { int obj_left = remap_emerald[src[i - 1]]; int obj_right = remap_emerald[src[i + 1]]; if (obj_left == Xblank || obj_right == Xblank || obj_left == Xplant || obj_right == Xplant) src[i - 64] = 6; /* replace element above with 'Xblank' */ else src[i - 64] = 255; /* replace element above with 'Xfake_acid_1' */ } else { src[i - 64] = 101; /* replace element above with 'Xacid_1' */ } } } #endif #endif /* fix acid in eater 1 */ for (i = 2051; i < 2057; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 2 */ for (i = 2060; i < 2066; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 3 */ for (i = 2069; i < 2075; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 4 */ for (i = 2078; i < 2084; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 5 */ for (i = 2115; i < 2121; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 6 */ for (i = 2124; i < 2130; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 7 */ for (i = 2133; i < 2139; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 8 */ for (i = 2142; i < 2148; i++) if (src[i] == 63) src[i - 3] = 101; /* old style time */ src[2094] = 0; /* player 1 pos */ src[2096] &= 7; src[src[2096] << 8 | src[2097]] = 128; /* player 2 pos */ src[2098] &= 7; src[src[2098] << 8 | src[2099]] = 128; /* amoeba speed */ if ((src[2100] << 8 | src[2101]) > 9999) { src[2100] = 39; src[2101] = 15; } /* time wonderwall */ if ((src[2102] << 8 | src[2103]) > 9999) { src[2102] = 39; src[2103] = 15; } /* time */ if ((src[2110] << 8 | src[2111]) > 9999) { src[2110] = 39; src[2111] = 15; } /* wind direction */ i = src[2149]; i &= 15; i &= -i; src[2149] = i; /* time lenses */ if ((src[2154] << 8 | src[2155]) > 9999) { src[2154] = 39; src[2155] = 15; } /* time magnify */ if ((src[2156] << 8 | src[2157]) > 9999) { src[2156] = 39; src[2157] = 15; } /* ball object */ src[2158] = 0; src[2159] = remap_v6[src[2159]]; /* ball pause */ if ((src[2160] << 8 | src[2161]) > 9999) { src[2160] = 39; src[2161] = 15; } /* ball data */ src[2162] &= 129; if (src[2162] & 1) src[2163] = 0; /* android move pause */ if ((src[2164] << 8 | src[2165]) > 9999) { src[2164] = 39; src[2165] = 15; } /* android clone pause */ if ((src[2166] << 8 | src[2167]) > 9999) { src[2166] = 39; src[2167] = 15; } /* android data */ src[2168] &= 31; /* size of v6 cave */ length = 2172; #if 1 #if 1 if (options.debug) #endif printf("::: EM level file version: %d\n", file_version); #endif return file_version; } /* 2000-07-30T00:26:00Z * * Read emerald mine caves version 6 * * v4 and v5 emerald mine caves are converted to v6 (which completely supports * older versions) * * converting to the internal format loses /significant/ information which can * break lots of caves. * * major incompatibilities: * - borderless caves behave completely differently, the player no longer * "warps" to the other side. * - a compile time option for spring can make it behave differently when it * rolls. * - a compile time option for rolling objects (stone, nut, spring, bomb) only * in eater. * - acid is always deadly even with no base beneath it (this breaks cave 0 in * downunder mine 16) * (*) fixed (see above): * - downunder mine 16, level 0, works again * - downunder mine 11, level 71, corrected (only cosmetically) * * so far all below have not broken any caves: * * - active wheel inside an eater will not function, eater explosions will not * change settings. * - initial collect objects (emerald, diamond, dynamite) don't exist. * - initial rolling objects will be moved manually and made into sitting * objects. * - drips always appear from dots. * - more than one thing can fall into acid at the same time. * - acid explodes when the player walks into it, rather than splashing. * - simultaneous explosions may be in a slightly different order. * - quicksand states have been reduced. * - acid base is effectively an indestructable wall now which can affect eater * explosions. * - android can clone forever with a clone pause of 0 (emeralds, diamonds, * nuts, stones, bombs, springs). * * 2001-03-12T02:46:55Z * - rolling stuff is now allowed in the cave, i didn't like making this * decision. * - if BAD_ROLL is not defined, initial rolling objects are moved by hand. * - initial collect objects break some cave in elvis mine 5. * - different timing for wonderwall break some cave in exception mine 2. * - i think i'm pretty locked into always using the bad roll. *sigh* * - rolling spring is now turned into regular spring. it appears the emc * editor only uses the force code for initially moving spring. i will * follow this in my editor. * * 2006-04-02 * - introduced ALLOW_ROLLING_SPRING; if defined, do NOT turn rolling spring * into regular spring, because this breaks at least E.M.C. Mine 3, level 79 * (see comment directly above) */ static unsigned short remap_emerald[256] = { Xstone, Xstone, Xdiamond, Xdiamond, Xalien, Xalien, Xblank, Xblank, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Xbomb, Xbomb, Xemerald, Xemerald, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Xdrip_eat, Xdrip_eat, Xdrip_eat, Xdrip_eat, Xstone, Xbomb, Xdiamond, Xemerald, Xwonderwall, Xnut, Xnut, Xnut, Xwheel, Xeater_n, Xeater_s, Xeater_w, Xeater_e, Xsand_stone, Xblank, Xblank, Xblank, Xsand, Xsand, Xsand, Xsand_stone, Xsand_stone, Xsand_stone, Xsand, Xstone, Xgrow_ew, Xgrow_ns, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xacid_s, #ifdef ALLOW_ROLLING_SPRING Xexit_1, Xexit_2, Xexit_3, Xballoon, Xplant, Xspring, Xspring_fall, Xspring_w, Xspring_e, Xball_1, Xball_2, Xandroid, Xblank, Xandroid, Xandroid, Xandroid, #else Xexit_1, Xexit_2, Xexit_3, Xballoon, Xplant, Xspring, Xspring, Xspring, Xspring, Xball_1, Xball_2, Xandroid, Xblank, Xandroid, Xandroid, Xandroid, #endif Xandroid, Xandroid, Xandroid, Xandroid, Xandroid, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, #ifdef BAD_ROLL Xblank, Xblank, Xblank, Xspring_force_w, Xspring_force_e, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xnut_force_w, Xnut_force_e, Xsteel_1, Xblank, Xblank, Xbomb_force_w, Xbomb_force_e, Xstone_force_w, Xstone_force_e, Xblank, Xblank, Xblank, Xblank, Xblank, #else Xblank, Xblank, Xblank, Xspring, Xspring, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xnut, Xnut, Xsteel_1, Xblank, Xblank, Xbomb, Xbomb, Xstone, Xstone, Xblank, Xblank, Xblank, Xblank, Xblank, #endif Xblank, Xround_wall_1, Xgrass, Xsteel_1, Xwall_1, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdripper, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xwonderwall, Xwheel, Xsand, Xacid_nw, Xacid_ne, Xacid_sw, Xacid_se, Xfake_blank, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xexit, Xalpha_arrow_w, Xfake_grass, Xlenses, Xmagnify, Xfake_blank, Xfake_grass, Xswitch, Xswitch, Xblank, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_5, Xalpha_comma, Xalpha_quote, Xalpha_minus, Xdynamite, Xsteel_3, Xdecor_6, Xdecor_7, Xsteel_2, Xround_wall_2, Xdecor_2, Xdecor_4, Xdecor_3, Xwind_nesw, Xwind_e, Xwind_s, Xwind_w, Xwind_n, Xdirt, Xplant, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xbumper, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_perio, Xalpha_excla, Xalpha_colon, Xalpha_quest, Xalpha_arrow_e, Xdecor_1, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, #if 0 Xblank, Xblank, Xblank, Xblank, #else /* special elements added to solve compatibility problems */ Xblank, Xblank, Xalpha_copyr, Xfake_acid_1 #endif }; static int get_em_element(unsigned short em_element_raw, int file_version) { int em_element = remap_emerald[em_element_raw]; if (file_version < FILE_VERSION_EM_V5) { /* versions below V5 had no grass, but only sand/dirt */ if (em_element == Xgrass) em_element = Xdirt; } return em_element; } void convert_em_level(unsigned char *src, int file_version) { static int eater_offset[8] = { 0x800, 0x809, 0x812, 0x81B, 0x840, 0x849, 0x852, 0x85B }; int i, x, y, temp; #if 1 lev.time_seconds = src[0x83E] << 8 | src[0x83F]; if (lev.time_seconds > 9999) lev.time_seconds = 9999; #else temp = ((src[0x83E] << 8 | src[0x83F]) * 25 + 3) / 4; if (temp == 0 || temp > 9999) temp = 9999; lev.time_initial = temp; #endif lev.required_initial = src[0x82F]; for (i = 0; i < 2; i++) { temp = src[0x830 + i * 2] << 8 | src[0x831 + i * 2]; ply[i].x_initial = (temp & 63) + 1; ply[i].y_initial = (temp >> 6 & 31) + 1; } temp = (src[0x834] << 8 | src[0x835]) * 28; if (temp > 9999) temp = 9999; lev.amoeba_time = temp; lev.android_move_time = src[0x874] << 8 | src[0x875]; lev.android_clone_time = src[0x876] << 8 | src[0x877]; lev.ball_random = src[0x872] & 1 ? 1 : 0; lev.ball_state_initial = src[0x872] & 128 ? 1 : 0; lev.ball_time = src[0x870] << 8 | src[0x871]; lev.emerald_score = src[0x824]; lev.diamond_score = src[0x825]; lev.alien_score = src[0x826]; lev.tank_score = src[0x827]; lev.bug_score = src[0x828]; lev.eater_score = src[0x829]; lev.nut_score = src[0x82A]; lev.dynamite_score = src[0x82B]; lev.key_score = src[0x82C]; lev.exit_score = src[0x82D] * 8 / 5; lev.lenses_score = src[0x867]; lev.magnify_score = src[0x868]; lev.slurp_score = src[0x869]; lev.lenses_time = src[0x86A] << 8 | src[0x86B]; lev.magnify_time = src[0x86C] << 8 | src[0x86D]; lev.wheel_time = src[0x838] << 8 | src[0x839]; lev.wind_cnt_initial = src[0x865] & 15 ? lev.wind_time : 0; temp = src[0x865]; lev.wind_direction_initial = (temp & 8 ? 0 : temp & 1 ? 1 : temp & 2 ? 2 : temp & 4 ? 3 : 0); lev.wonderwall_time_initial = src[0x836] << 8 | src[0x837]; for (i = 0; i < 8; i++) for (x = 0; x < 9; x++) lev.eater_array[i][x] = get_em_element(src[eater_offset[i] + x], file_version); temp = get_em_element(src[0x86F], file_version); for (y = 0; y < 8; y++) { if (src[0x872] & 1) { for (x = 0; x < 8; x++) lev.ball_array[y][x] = temp; } else { lev.ball_array[y][1] = (src[0x873] & 1) ? temp : Xblank; /* north */ lev.ball_array[y][6] = (src[0x873] & 2) ? temp : Xblank; /* south */ lev.ball_array[y][3] = (src[0x873] & 4) ? temp : Xblank; /* west */ lev.ball_array[y][4] = (src[0x873] & 8) ? temp : Xblank; /* east */ lev.ball_array[y][7] = (src[0x873] & 16) ? temp : Xblank; /* southeast */ lev.ball_array[y][5] = (src[0x873] & 32) ? temp : Xblank; /* southwest */ lev.ball_array[y][2] = (src[0x873] & 64) ? temp : Xblank; /* northeast */ lev.ball_array[y][0] = (src[0x873] & 128)? temp : Xblank; /* northwest */ } } temp = src[0x878] << 8 | src[0x879]; if (temp & 1) { lev.android_array[Xemerald] = Xemerald; lev.android_array[Xemerald_pause] = Xemerald; lev.android_array[Xemerald_fall] = Xemerald; lev.android_array[Yemerald_sB] = Xemerald; lev.android_array[Yemerald_eB] = Xemerald; lev.android_array[Yemerald_wB] = Xemerald; } if (temp & 2) { lev.android_array[Xdiamond] = Xdiamond; lev.android_array[Xdiamond_pause] = Xdiamond; lev.android_array[Xdiamond_fall] = Xdiamond; lev.android_array[Ydiamond_sB] = Xdiamond; lev.android_array[Ydiamond_eB] = Xdiamond; lev.android_array[Ydiamond_wB] = Xdiamond; } if (temp & 4) { lev.android_array[Xstone] = Xstone; lev.android_array[Xstone_pause] = Xstone; lev.android_array[Xstone_fall] = Xstone; lev.android_array[Ystone_sB] = Xstone; lev.android_array[Ystone_eB] = Xstone; lev.android_array[Ystone_wB] = Xstone; } if (temp & 8) { lev.android_array[Xbomb] = Xbomb; lev.android_array[Xbomb_pause] = Xbomb; lev.android_array[Xbomb_fall] = Xbomb; lev.android_array[Ybomb_sB] = Xbomb; lev.android_array[Ybomb_eB] = Xbomb; lev.android_array[Ybomb_wB] = Xbomb; } if (temp & 16) { lev.android_array[Xnut] = Xnut; lev.android_array[Xnut_pause] = Xnut; lev.android_array[Xnut_fall] = Xnut; lev.android_array[Ynut_sB] = Xnut; lev.android_array[Ynut_eB] = Xnut; lev.android_array[Ynut_wB] = Xnut; } if (temp & 32) { lev.android_array[Xtank_n] = Xtank_n; lev.android_array[Xtank_gon] = Xtank_n; lev.android_array[Ytank_nB] = Xtank_n; lev.android_array[Ytank_n_e] = Xtank_n; lev.android_array[Ytank_n_w] = Xtank_n; lev.android_array[Xtank_e] = Xtank_e; lev.android_array[Xtank_goe] = Xtank_e; lev.android_array[Ytank_eB] = Xtank_e; lev.android_array[Ytank_e_s] = Xtank_e; lev.android_array[Ytank_e_n] = Xtank_e; lev.android_array[Xtank_s] = Xtank_s; lev.android_array[Xtank_gos] = Xtank_s; lev.android_array[Ytank_sB] = Xtank_s; lev.android_array[Ytank_s_w] = Xtank_s; lev.android_array[Ytank_s_e] = Xtank_s; lev.android_array[Xtank_w] = Xtank_w; lev.android_array[Xtank_gow] = Xtank_w; lev.android_array[Ytank_wB] = Xtank_w; lev.android_array[Ytank_w_n] = Xtank_w; lev.android_array[Ytank_w_s] = Xtank_w; } if (temp & 64) { lev.android_array[Xeater_n] = Xeater_n; lev.android_array[Yeater_nB] = Xeater_n; lev.android_array[Xeater_e] = Xeater_e; lev.android_array[Yeater_eB] = Xeater_e; lev.android_array[Xeater_s] = Xeater_s; lev.android_array[Yeater_sB] = Xeater_s; lev.android_array[Xeater_w] = Xeater_w; lev.android_array[Yeater_wB] = Xeater_w; } if (temp & 128) { lev.android_array[Xbug_n] = Xbug_gon; lev.android_array[Xbug_gon] = Xbug_gon; lev.android_array[Ybug_nB] = Xbug_gon; lev.android_array[Ybug_n_e] = Xbug_gon; lev.android_array[Ybug_n_w] = Xbug_gon; lev.android_array[Xbug_e] = Xbug_goe; lev.android_array[Xbug_goe] = Xbug_goe; lev.android_array[Ybug_eB] = Xbug_goe; lev.android_array[Ybug_e_s] = Xbug_goe; lev.android_array[Ybug_e_n] = Xbug_goe; lev.android_array[Xbug_s] = Xbug_gos; lev.android_array[Xbug_gos] = Xbug_gos; lev.android_array[Ybug_sB] = Xbug_gos; lev.android_array[Ybug_s_w] = Xbug_gos; lev.android_array[Ybug_s_e] = Xbug_gos; lev.android_array[Xbug_w] = Xbug_gow; lev.android_array[Xbug_gow] = Xbug_gow; lev.android_array[Ybug_wB] = Xbug_gow; lev.android_array[Ybug_w_n] = Xbug_gow; lev.android_array[Ybug_w_s] = Xbug_gow; } if (temp & 256) { lev.android_array[Xalien] = Xalien; lev.android_array[Xalien_pause] = Xalien; lev.android_array[Yalien_nB] = Xalien; lev.android_array[Yalien_eB] = Xalien; lev.android_array[Yalien_sB] = Xalien; lev.android_array[Yalien_wB] = Xalien; } if (temp & 512) { lev.android_array[Xspring] = Xspring; lev.android_array[Xspring_pause] = Xspring; lev.android_array[Xspring_e] = Xspring; lev.android_array[Yspring_eB] = Xspring; lev.android_array[Yspring_kill_eB] = Xspring; lev.android_array[Xspring_w] = Xspring; lev.android_array[Yspring_wB] = Xspring; lev.android_array[Yspring_kill_wB] = Xspring; lev.android_array[Xspring_fall] = Xspring; lev.android_array[Yspring_sB] = Xspring; } if (temp & 1024) { lev.android_array[Yballoon_nB] = Xballoon; lev.android_array[Yballoon_eB] = Xballoon; lev.android_array[Yballoon_sB] = Xballoon; lev.android_array[Yballoon_wB] = Xballoon; lev.android_array[Xballoon] = Xballoon; } if (temp & 2048) { lev.android_array[Xdripper] = Xdrip_eat; lev.android_array[XdripperB] = Xdrip_eat; lev.android_array[Xamoeba_1] = Xdrip_eat; lev.android_array[Xamoeba_2] = Xdrip_eat; lev.android_array[Xamoeba_3] = Xdrip_eat; lev.android_array[Xamoeba_4] = Xdrip_eat; lev.android_array[Xamoeba_5] = Xdrip_eat; lev.android_array[Xamoeba_6] = Xdrip_eat; lev.android_array[Xamoeba_7] = Xdrip_eat; lev.android_array[Xamoeba_8] = Xdrip_eat; } if (temp & 4096) { lev.android_array[Xdynamite] = Xdynamite; } for (temp = 1; temp < 2047; temp++) { switch (src[temp]) { case 0x24: /* wonderwall */ lev.wonderwall_state_initial = 1; lev.wonderwall_time_initial = 9999; break; case 0x28: /* wheel */ lev.wheel_x_initial = temp & 63; lev.wheel_y_initial = temp >> 6; lev.wheel_cnt_initial = lev.wheel_time; break; #ifndef BAD_ROLL case 0x63: /* spring roll left */ src[temp - 1] = 0x45; src[temp] = 0x80; break; case 0x64: /* spring roll right */ src[temp + 1] = 0x45; src[temp] = 0x80; break; case 0x72: /* nut roll left */ src[temp - 1] = 0x25; src[temp] = 0x80; break; case 0x73: /* nut roll right */ src[temp + 1] = 0x25; src[temp] = 0x80; break; case 0x77: /* bomb roll left */ src[temp - 1] = 0x10; src[temp] = 0x80; break; case 0x78: /* bomb roll right */ src[temp + 1] = 0x10; src[temp] = 0x80; break; case 0x79: /* stone roll left */ src[temp - 1] = 0x00; src[temp] = 0x80; break; case 0x7A: /* stone roll right */ src[temp + 1] = 0x00; src[temp] = 0x80; break; #endif case 0xA3: /* fake blank */ lev.lenses_cnt_initial = 9999; break; case 0xA4: /* fake grass */ lev.magnify_cnt_initial = 9999; break; } } /* first fill the complete playfield with the default border element */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) native_em_level.cave[x][y] = ZBORDER; /* then copy the real level contents from level file into the playfield */ temp = 0; for (y = 0; y < lev.height; y++) for (x = 0; x < lev.width; x++) native_em_level.cave[x + 1][y + 1] = get_em_element(src[temp++], file_version); /* at last, set the two players at their positions in the playfield */ /* (native EM[C] levels always have exactly two players in a level) */ #if 1 for (i = 0; i < 2; i++) native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer; #else for (i = 0; i < 2; i++) if (ply[i].alive_initial) native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer; #endif native_em_level.file_version = file_version; } void prepare_em_level(void) { int i, x, y; int players_left; int num_tape_players; /* reset all runtime variables to their initial values */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Cave[y][x] = native_em_level.cave[x][y]; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Next[y][x] = Cave[y][x]; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Draw[y][x] = Cave[y][x]; #if 1 lev.time_initial = lev.time_seconds; #else lev.time_initial = (lev.time_seconds * 50 + 7) / 8; #endif lev.time = lev.time_initial; lev.required = lev.required_initial; lev.score = 0; lev.android_move_cnt = lev.android_move_time; lev.android_clone_cnt = lev.android_clone_time; lev.ball_pos = 0; lev.ball_state = lev.ball_state_initial; lev.ball_cnt = lev.ball_time; lev.eater_pos = 0; lev.shine_cnt = 0; lev.lenses_cnt = lev.lenses_cnt_initial; lev.magnify_cnt = lev.magnify_cnt_initial; lev.wheel_cnt = lev.wheel_cnt_initial; lev.wheel_x = lev.wheel_x_initial; lev.wheel_y = lev.wheel_y_initial; lev.wind_direction = lev.wind_direction_initial; lev.wind_cnt = lev.wind_cnt_initial; lev.wonderwall_state = lev.wonderwall_state_initial; lev.wonderwall_time = lev.wonderwall_time_initial; lev.killed_out_of_time = FALSE; /* determine number of players in this level */ lev.home_initial = 0; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].exists = 0; ply[i].alive_initial = FALSE; if (ply[i].x_initial > 0 && ply[i].y_initial > 0) { ply[i].exists = 1; lev.home_initial++; } } num_tape_players = getNumActivePlayers_EM(); if (num_tape_players != -1) lev.home_initial = MIN(lev.home_initial, num_tape_players); else if (!setup.team_mode) lev.home_initial = MIN(lev.home_initial, 1); lev.home = lev.home_initial; players_left = lev.home_initial; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].exists) { if (players_left) { ply[i].alive_initial = TRUE; players_left--; } else { int x = ply[i].x_initial; int y = ply[i].y_initial; native_em_level.cave[x][y] = Xblank; Cave[y][x] = Next[y][x] = Draw[y][x] = Xblank; } } } for (i = 0; i < MAX_PLAYERS; i++) { ply[i].num = i; ply[i].alive = ply[i].alive_initial; ply[i].dynamite = 0; ply[i].dynamite_cnt = 0; ply[i].keys = 0; ply[i].anim = 0; ply[i].oldx = ply[i].x = ply[i].x_initial; ply[i].oldy = ply[i].y = ply[i].y_initial; ply[i].last_move_dir = MV_NONE; ply[i].joy_n = ply[i].joy_e = ply[i].joy_s = ply[i].joy_w = 0; ply[i].joy_snap = ply[i].joy_drop = 0; ply[i].joy_stick = ply[i].joy_spin = 0; #if 0 printf("player %d: x/y == %d/%d, alive == %d\n", i, ply[i].x_initial, ply[i].y_initial, ply[i].alive); #endif } game_em.any_player_moving = FALSE; game_em.last_moving_player = 0; /* default: first player */ for (i = 0; i < MAX_PLAYERS; i++) game_em.last_player_direction[i] = MV_NONE; lev.exit_x = lev.exit_y = -1; /* kludge for playing player exit sound */ } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/sound.c0000644000175000017500000002442610613745005020314 0ustar dimkadimka/* 2000-08-10T17:39:15Z * * handle sounds in emerald mine */ #include "main_em.h" #if defined(AUDIO_UNIX_NATIVE) #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) #ifdef PLATFORM_LINUX #include #include #endif #ifdef PLATFORM_BSD #include #include #endif static char audioname[] = "/dev/audio"; static const int sound_priority[SAMPLE_MAX] = { SAMPLE_exit_open, SAMPLE_exit_leave, SAMPLE_die, SAMPLE_time, SAMPLE_boom, SAMPLE_tick, SAMPLE_collect, SAMPLE_roll, SAMPLE_push, SAMPLE_dynamite, SAMPLE_press, SAMPLE_door, SAMPLE_dirt, SAMPLE_blank, SAMPLE_android_clone, SAMPLE_android_move, SAMPLE_ball, SAMPLE_grow, SAMPLE_squash, SAMPLE_wonderfall, SAMPLE_crack, SAMPLE_slurp, SAMPLE_drip, SAMPLE_wonder, SAMPLE_wheel, SAMPLE_stone, SAMPLE_spring, SAMPLE_diamond, SAMPLE_nut, SAMPLE_bug, SAMPLE_tank, SAMPLE_eater, SAMPLE_eater_eat, SAMPLE_alien, SAMPLE_acid }; int sound_thread(void) { int audio_fd; /* file descriptor of /dev/audio or -1 if not open */ int audio_format; int sample_rate; int fragment_size; unsigned char *audio_buffer; /* actual buffer pumped to /dev/audio */ short *mix_buffer; char sound_play[SAMPLE_MAX]; /* if set, we should be playing these sounds */ long sound_pos[SAMPLE_MAX]; /* position in the sound */ int mix_play[MIXER_MAX]; /* which sounds we have chosen to mix (calculated each time) */ int mix_count; int i; loop: audio_fd = -1; audio_format = AUDIO_ULAW; /* defaults for non-OSS /dev/audio */ sample_rate = 8000; fragment_size = 256; audio_buffer = 0; mix_buffer = 0; mix_count = 0; clear_mem(sound_play, sizeof(sound_play)); /* not playing any sounds */ for (;;) { for (;;) { /* pick sounds to play, if any */ if (sound_play[SAMPLE_exit_open] || sound_play[SAMPLE_exit_leave] || sound_play[SAMPLE_die]) sound_play[SAMPLE_boom] = 0; /* no explosions if player goes home */ mix_count = 0; for (i = 0; i < SAMPLE_MAX; i++) { if (sound_play[sound_priority[i]]) { mix_play[mix_count++] = sound_priority[i]; if (mix_count == MIXER_MAX) break; /* cant mix too many sounds at once */ } } /* check for incoming messages */ if (mix_count || audio_fd != -1) { /* dont block if we are playing sounds */ fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(sound_pipe[0], &rfds); tv.tv_sec = 0; tv.tv_usec = 0; /* (900000 * fragment_size / sample_rate) */ i = select(sound_pipe[0] + 1, &rfds, 0, 0, &tv); /* dont block */ if (i == -1) { Error(ERR_WARN, "select() failed in sound thread"); goto fail; } if (i == 0) break; /* no messages */ } /* get a message and start a sound */ i = read(sound_pipe[0], &play, sizeof(play)); if (i == -1) { Error(ERR_WARN, "read() failed in sound thread"); goto fail; } if (i == 0) { Error(ERR_WARN, "reading sound failed in sound thread"); goto fail; } if (i != sizeof(play)) { Error(ERR_WARN, "bad message length in sound thread"); goto fail; } for (i = 0; i < SAMPLE_MAX; i++) { if (play[i]) { sound_play[i] = 1; /* play this sound */ sound_pos[i] = 0; /* start it from the start */ } } } /* open the audio device if there are sounds to play */ if (mix_count && audio_fd == -1) { audio_fd = open(audioname, O_WRONLY); if (audio_fd == -1) goto reset; #ifdef OPEN_SOUND_SYSTEM i = 0x00020008; if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i) == -1) { Error(ERR_WARN, "unable to set fragment size in sound thread"); goto reset; } if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i) == -1) { Error(ERR_WARN, "unable to query audio format in sound thread"); goto reset; } /* prefer 8 bit unsigned and fall back on mu-law */ audio_format = (i & AFMT_U8) ? AFMT_U8 : AFMT_MU_LAW; i = audio_format; if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &i) == -1) { Error(ERR_WARN, "unable to set audio format in sound thread"); goto reset; } if (i == AFMT_MU_LAW) { audio_format = AUDIO_ULAW; } else if (i == AFMT_U8) { audio_format = AUDIO_U8; } else { Error(ERR_WARN, "audio format required by device not supported"); goto reset; } i = 1; if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &i) == -1) { Error(ERR_WARN, "unable to set channels to mono in sound thread"); goto reset; } if (i != 1) { Error(ERR_WARN, "channels required by device not supported"); goto reset; } i = 8000; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &i) == -1) { Error(ERR_WARN, "unable to set sampling rate in sound thread"); goto reset; } sample_rate = i; if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &i) == -1) { Error(ERR_WARN, "unable to get block size in sound thread"); goto reset; } fragment_size = i; #else if (fcntl(audio_fd, F_SETFL, O_NONBLOCK) == -1) { Error(ERR_WARN, "unable to make audio non blocking in sound thread"); goto reset; } #endif /* OPEN_SOUND_SYSTEM */ audio_buffer = malloc(fragment_size * sizeof(*audio_buffer)); if (audio_buffer == 0) { Error(ERR_WARN, "unable to malloc audio buffer in sound thread"); goto fail; } mix_buffer = malloc(fragment_size * sizeof(*mix_buffer)); if (mix_buffer == 0) { Error(ERR_WARN, "unable to malloc mixing buffer in sound thread"); goto fail; } } /* close the audio device if no sounds are playing */ if (mix_count == 0 && audio_fd != -1) { close(audio_fd); free(audio_buffer); free(mix_buffer); audio_fd = -1; audio_buffer = 0; mix_buffer = 0; } /* if we are playing sounds and the audio device is open, mix them */ if (mix_count && audio_fd != -1) { /* prepare mix buffer */ clear_mem(mix_buffer, fragment_size * sizeof(*mix_buffer)); for (i = 0; i < mix_count; i++) { register short *mix_ptr = mix_buffer; register short *sound_ptr = sound_data[mix_play[i]] + sound_pos[mix_play[i]]; register long count = sound_length[mix_play[i]] - sound_pos[mix_play[i]]; if (count > fragment_size) count = fragment_size; while (count--) *mix_ptr++ += *sound_ptr++; /* mix the sounds in */ } switch(audio_format) { case AUDIO_ULAW: for (i = 0; i < fragment_size; i++) audio_buffer[i] = linear_to_ulaw[mix_buffer[i] + 32768]; break; case AUDIO_U8: for (i = 0; i < fragment_size; i++) audio_buffer[i] = (mix_buffer[i] + 32768) >> 8; break; } /* advance sound pointers */ for (i = 0; i < SAMPLE_MAX; i++) { if (sound_play[i]) { if (sound_pos[i] + fragment_size < sound_length[i]) { sound_pos[i] += fragment_size; } else { sound_play[i] = 0; } } } /* send the data to the audio device */ i = write(audio_fd, audio_buffer, fragment_size); if (i == -1) { Error(ERR_WARN, "cannot write to audio device in sound thread"); goto reset; } if (i != fragment_size) { Error(ERR_WARN, "bad write length to audio device in sound thread"); goto reset; } } } /* for */ reset: if (audio_fd != -1) close(audio_fd); if (audio_buffer) free(audio_buffer); if (mix_buffer) free(mix_buffer); goto loop; /* back to top */ fail: if (audio_fd != -1) close(audio_fd); if (audio_buffer) free(audio_buffer); if (mix_buffer) free(mix_buffer); return(0); } int read_sample(char *name, short **data, long *length) { int result; FILE *file = 0; short *dataptr = 0; long datalength; int i, actual, ch; unsigned char buffer[24]; unsigned long temp; file = fopen(name, "rb"); if (file == 0) { Error(ERR_WARN, "cannot open file '%s' in sound thread", name); result = 1; goto fail; } actual = fread(buffer, 1, 24, file); if (actual == -1) { Error(ERR_WARN, "cannot read file '%s' in sound thread", name); result = 1; goto fail; } if (actual < 24) { Error(ERR_WARN, "premature eof of file '%s' in sound thread", name); result = 1; goto fail; } /* magic */ temp = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; if (temp != 0x2e736e64) { Error(ERR_WARN, "unrecognized format of file '%s' in sound thread", name); result = 1; goto fail; } /* header length */ temp = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; if (temp < 24) { Error(ERR_WARN, "bad header length of file '%s' in sound thread", name); result = 1; goto fail; } actual = temp; for (i = 24; i < actual; i++) { /* skip the rest of the header */ ch = fgetc(file); if (ch == EOF) break; } /* data length */ temp = buffer[8] << 24 | buffer[9] << 16 | buffer[10] << 8 | buffer[11]; datalength = temp; /* encoding */ temp = buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15]; if (temp != 1) { fprintf(stderr, "%s: \"%s\": %s (%ld != 1)\n", progname, name, "bad encoding type", temp); result = 1; goto fail; } /* sample rate */ temp = buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19]; if (temp != 8000) { fprintf(stderr, "%s: \"%s\": %s (%ld != 8000)\n", progname, name, "bad sample rate", temp); result = 1; goto fail; } /* channels */ temp = buffer[20] << 24 | buffer[21] << 16 | buffer[22] << 8 | buffer[23]; if (temp != 1) { fprintf(stderr, "%s: \"%s\": %s (%ld != 1)\n", progname, name, "unsupported channels", temp); result = 1; goto fail; } dataptr = malloc(datalength * sizeof(*dataptr)); if (dataptr == 0) { Error(ERR_WARN, "unable to malloc buffer for file '%s' in sound thread", name); result = 1; goto fail; } for (i = 0; i < datalength; i++) { ch = fgetc(file); if (ch == EOF) break; dataptr[i] = ulaw_to_linear[ch]; } fclose(file); file = 0; *data = dataptr; *length = datalength; result = 0; fail: if (file) fclose(file); return(result); } #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) */ #endif /* AUDIO_UNIX_NATIVE */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/export.h0000644000175000017500000003703511264170262020512 0ustar dimkadimka#ifndef EXPORT_H #define EXPORT_H /* ========================================================================= */ /* functions and definitions exported from game_em to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* define these for backwards compatibility */ #define EM_ENGINE_BAD_ROLL #define EM_ENGINE_BAD_SPRING /* define these to use additional elements */ #define EM_ENGINE_USE_ADDITIONAL_ELEMENTS /* internal definitions for EM engine */ #ifdef EM_ENGINE_BAD_ROLL #define BAD_ROLL #endif #ifdef EM_ENGINE_BAD_SPRING #define BAD_SPRING #endif /* one border for ZBORDER elements, one border for steelwall, if needed */ #define EM_MAX_CAVE_WIDTH (MAX_PLAYFIELD_WIDTH + 2 + 2) #define EM_MAX_CAVE_HEIGHT (MAX_PLAYFIELD_HEIGHT + 2 + 2) /* ----------------------------------------------------------------------------- definition of elements used in the Emerald Mine Club engine; the element names have the following properties: - elements that start with 'X' can be stored in a level file - elements that start with 'Y' indicate moving elements - elements that end with 'B' are the "backside" of moving elements ----------------------------------------------------------------------------- */ enum { Xblank = 0, /* still */ Yacid_splash_eB, /* hmm */ Yacid_splash_wB, /* hmm */ #ifdef EM_ENGINE_BAD_ROLL Xstone_force_e, /* only use these in eater */ Xstone_force_w, Xnut_force_e, Xnut_force_w, Xspring_force_e, Xspring_force_w, Xemerald_force_e, Xemerald_force_w, Xdiamond_force_e, Xdiamond_force_w, Xbomb_force_e, Xbomb_force_w, #endif Xstone, Xstone_pause, Xstone_fall, Ystone_s, Ystone_sB, Ystone_e, Ystone_eB, Ystone_w, Ystone_wB, Xnut, Xnut_pause, Xnut_fall, Ynut_s, Ynut_sB, Ynut_e, Ynut_eB, Ynut_w, Ynut_wB, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Ybug_n, Ybug_nB, Ybug_e, Ybug_eB, Ybug_s, Ybug_sB, Ybug_w, Ybug_wB, Ybug_w_n, Ybug_n_e, Ybug_e_s, Ybug_s_w, Ybug_e_n, Ybug_s_e, Ybug_w_s, Ybug_n_w, Ybug_stone, Ybug_spring, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Ytank_n, Ytank_nB, Ytank_e, Ytank_eB, Ytank_s, Ytank_sB, Ytank_w, Ytank_wB, Ytank_w_n, Ytank_n_e, Ytank_e_s, Ytank_s_w, Ytank_e_n, Ytank_s_e, Ytank_w_s, Ytank_n_w, Ytank_stone, Ytank_spring, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_w, Xandroid_2_w, Xandroid_1_s, Xandroid_2_s, Yandroid_n, Yandroid_nB, Yandroid_ne, Yandroid_neB, Yandroid_e, Yandroid_eB, Yandroid_se, Yandroid_seB, Yandroid_s, Yandroid_sB, Yandroid_sw, Yandroid_swB, Yandroid_w, Yandroid_wB, Yandroid_nw, Yandroid_nwB, Xspring, Xspring_pause, Xspring_e, Xspring_w, Xspring_fall, Yspring_s, Yspring_sB, Yspring_e, Yspring_eB, Yspring_w, Yspring_wB, Yspring_kill_e, Yspring_kill_eB, Yspring_kill_w, Yspring_kill_wB, Xeater_n, Xeater_e, Xeater_w, Xeater_s, Yeater_n, Yeater_nB, Yeater_e, Yeater_eB, Yeater_s, Yeater_sB, Yeater_w, Yeater_wB, Yeater_stone, Yeater_spring, Xalien, Xalien_pause, Yalien_n, Yalien_nB, Yalien_e, Yalien_eB, Yalien_s, Yalien_sB, Yalien_w, Yalien_wB, Yalien_stone, Yalien_spring, Xemerald, Xemerald_pause, Xemerald_fall, Xemerald_shine, Yemerald_s, Yemerald_sB, Yemerald_e, Yemerald_eB, Yemerald_w, Yemerald_wB, Yemerald_eat, Yemerald_stone, Xdiamond, Xdiamond_pause, Xdiamond_fall, Xdiamond_shine, Ydiamond_s, Ydiamond_sB, Ydiamond_e, Ydiamond_eB, Ydiamond_w, Ydiamond_wB, Ydiamond_eat, Ydiamond_stone, Xdrip_fall, Xdrip_stretch, Xdrip_stretchB, Xdrip_eat, Ydrip_s1, Ydrip_s1B, Ydrip_s2, Ydrip_s2B, Xbomb, Xbomb_pause, Xbomb_fall, Ybomb_s, Ybomb_sB, Ybomb_e, Ybomb_eB, Ybomb_w, Ybomb_wB, Ybomb_eat, Xballoon, Yballoon_n, Yballoon_nB, Yballoon_e, Yballoon_eB, Yballoon_s, Yballoon_sB, Yballoon_w, Yballoon_wB, Xgrass, Ygrass_nB, Ygrass_eB, Ygrass_sB, Ygrass_wB, Xdirt, Ydirt_nB, Ydirt_eB, Ydirt_sB, Ydirt_wB, Xacid_ne, Xacid_se, Xacid_s, Xacid_sw, Xacid_nw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xball_1, Xball_1B, Xball_2, Xball_2B, Yball_eat, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Ykey_1_eat, Ykey_2_eat, Ykey_3_eat, Ykey_4_eat, Ykey_5_eat, Ykey_6_eat, Ykey_7_eat, Ykey_8_eat, Ylenses_eat, Ymagnify_eat, Ygrass_eat, Ydirt_eat, #endif Xgrow_ns, Ygrow_ns_eat, Xgrow_ew, Ygrow_ew_eat, Xwonderwall, XwonderwallB, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xamoeba_5, Xamoeba_6, Xamoeba_7, Xamoeba_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xwind_n, Xwind_e, Xwind_s, Xwind_w, Xwind_nesw, Xwind_stop, Xexit, Xexit_1, Xexit_2, Xexit_3, Xdynamite, Ydynamite_eat, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xbumper, XbumperB, Xwheel, XwheelB, Xswitch, XswitchB, Xsand, Xsand_stone, Xsand_stonein_1, Xsand_stonein_2, Xsand_stonein_3, Xsand_stonein_4, Xsand_stonesand_1, Xsand_stonesand_2, Xsand_stonesand_3, Xsand_stonesand_4, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Xsand_stonesand_quickout_1, Xsand_stonesand_quickout_2, #endif Xsand_stoneout_1, Xsand_stoneout_2, Xsand_sandstone_1, Xsand_sandstone_2, Xsand_sandstone_3, Xsand_sandstone_4, Xplant, Yplant, Xlenses, Xmagnify, Xdripper, XdripperB, Xfake_blank, Xfake_blankB, Xfake_grass, Xfake_grassB, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Xfake_acid_1, Xfake_acid_2, Xfake_acid_3, Xfake_acid_4, Xfake_acid_5, Xfake_acid_6, Xfake_acid_7, Xfake_acid_8, #endif Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, Xwall_1, Xwall_2, Xwall_3, Xwall_4, Xround_wall_1, Xround_wall_2, Xround_wall_3, Xround_wall_4, Xdecor_1, Xdecor_2, Xdecor_3, Xdecor_4, Xdecor_5, Xdecor_6, Xdecor_7, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_11, Xdecor_12, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_excla, Xalpha_quote, Xalpha_comma, Xalpha_minus, Xalpha_perio, Xalpha_colon, Xalpha_quest, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_arrow_e, Xalpha_arrow_w, Xalpha_copyr, Xboom_bug, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_bomb, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_android, /* passed from explode to synchro; transition to boom_2 */ Xboom_1, /* passed from explode to synchro; transition to boom_2 */ Xboom_2, /* transition to boom[] */ Znormal, /* passed from synchro to explode, only in next[]; no picture */ Zdynamite, /* passed from synchro to explode, only in next[]; no picture */ Zplayer, /* special code to indicate player; no picture */ ZBORDER, /* special code to indicate border; no picture */ TILE_MAX }; /* other definitions */ enum { SPR_still = 0, SPR_walk = 1, SPR_push = 5, SPR_spray = 9, SPR_MAX = 13 }; enum { SAMPLE_blank = 0, /* player walks on blank */ SAMPLE_roll, /* player pushes stone/bomb/nut/spring */ SAMPLE_stone, /* stone hits ground */ SAMPLE_nut, /* nut hits ground */ SAMPLE_crack, /* stone hits nut */ SAMPLE_bug, /* bug moves */ SAMPLE_tank, /* tank moves */ SAMPLE_android_clone, /* android places something */ SAMPLE_android_move, /* android moves */ SAMPLE_spring, /* spring hits ground/wall/bumper, stone hits spring */ SAMPLE_slurp, /* spring kills alien */ SAMPLE_eater, /* eater sits */ SAMPLE_eater_eat, /* eater eats diamond */ SAMPLE_alien, /* alien moves */ SAMPLE_collect, /* player collects object */ SAMPLE_diamond, /* diamond/emerald hits ground */ SAMPLE_squash, /* stone squashes diamond */ SAMPLE_wonderfall, /* object falls thru wonderwall */ SAMPLE_drip, /* drip hits ground */ SAMPLE_push, /* player pushes balloon/android */ SAMPLE_dirt, /* player walks on dirt */ SAMPLE_acid, /* acid splashes */ SAMPLE_ball, /* ball places something */ SAMPLE_grow, /* growing wall grows */ SAMPLE_wonder, /* wonderwall is active */ SAMPLE_door, /* player goes thru door (gate) */ SAMPLE_exit_open, /* exit opens */ SAMPLE_exit_leave, /* player goes into exit */ SAMPLE_dynamite, /* player places dynamite */ SAMPLE_tick, /* dynamite ticks */ SAMPLE_press, /* player presses wheel/wind/switch */ SAMPLE_wheel, /* wheel moves */ SAMPLE_boom, /* explosion */ SAMPLE_time, /* time runs out */ SAMPLE_die, /* player dies */ SAMPLE_MAX }; /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ struct LEVEL { int home_initial; /* number of players (initial) */ int home; /* number of players not yet at home */ /* 0 == all players at home */ int width; /* playfield width */ int height; /* playfield height */ int time_seconds; /* available time (seconds) */ int time_initial; /* available time (initial) */ int time; /* time remaining (runtime) */ boolean killed_out_of_time; /* kill player due to time out */ int required_initial; /* emeralds needed (initial) */ int required; /* emeralds needed (runtime) */ int score; /* score */ /* all below entries must be filled every time a level is read */ int alien_score; /* score for killing alien */ int amoeba_time; /* amoeba speed */ int android_move_cnt_initial; /* android move counter (initial) */ int android_move_cnt; /* android move counter */ int android_move_time; /* android move reset time */ int android_clone_cnt_initial;/* android clone counter (initial) */ int android_clone_cnt; /* android clone counter */ int android_clone_time; /* android clone reset time */ int ball_cnt; /* ball counter */ int ball_pos; /* ball array pos counter */ int ball_random; /* ball is random flag */ int ball_state_initial; /* ball active flag (initial) */ int ball_state; /* ball active flag */ int ball_time; /* ball reset time */ int bug_score; /* score for killing bug */ int diamond_score; /* score for collecting diamond */ int dynamite_score; /* score for collecting dynamite */ int eater_pos; /* eater array pos */ int eater_score; /* score for killing eater */ int emerald_score; /* score for collecting emerald */ int exit_score; /* score for entering exit */ int key_score; /* score for colleting key */ int lenses_cnt_initial; /* lenses counter (initial) */ int lenses_cnt; /* lenses counter */ int lenses_score; /* score for collecting lenses */ int lenses_time; /* lenses reset time */ int magnify_cnt_initial; /* magnify counter (initial) */ int magnify_cnt; /* magnify counter */ int magnify_score; /* score for collecting magnifier */ int magnify_time; /* magnify reset time */ int nut_score; /* score for cracking nut */ int shine_cnt; /* shine counter for emerald/diamond */ int slurp_score; /* score for slurping alien */ int tank_score; /* score for killing tank */ int wheel_cnt_initial; /* wheel counter (initial) */ int wheel_cnt; /* wheel counter */ int wheel_x_initial; /* wheel x pos (initial) */ int wheel_x; /* wheel x pos */ int wheel_y_initial; /* wheel y pos (initial) */ int wheel_y; /* wheel y pos */ int wheel_time; /* wheel reset time */ int wind_cnt_initial; /* wind counter (initial) */ int wind_cnt; /* wind time counter */ int wind_direction_initial; /* wind direction (initial) */ int wind_direction; /* wind direction */ int wind_time; /* wind reset time */ int wonderwall_state_initial; /* wonderwall active flag (initial) */ int wonderwall_state; /* wonderwall active flag */ int wonderwall_time_initial; /* wonderwall time (initial) */ int wonderwall_time; /* wonderwall time */ short eater_array[8][9]; /* eater data */ short ball_array[8][8]; /* ball data */ short android_array[TILE_MAX];/* android clone table */ int num_ball_arrays; /* number of ball data arrays used */ int exit_x, exit_y; /* kludge for playing player exit sound */ }; struct PLAYER { int num; int exists; int alive_initial; int alive; int dynamite; int dynamite_cnt; int keys; int anim; int x_initial; int y_initial; int x; int y; int oldx; int oldy; int last_move_dir; int joy_n:1; int joy_e:1; int joy_s:1; int joy_w:1; int joy_snap:1; int joy_drop:1; int joy_stick:1; int joy_spin:1; }; struct GlobalInfo_EM { Bitmap *screenbuffer; }; struct GameInfo_EM { boolean any_player_moving; int last_moving_player; int last_player_direction[MAX_PLAYERS]; }; struct LevelInfo_EM { int file_version; short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT]; struct LEVEL *lev; struct PLAYER *ply[MAX_PLAYERS]; }; struct GraphicInfo_EM { Bitmap *bitmap; int src_x, src_y; int src_offset_x, src_offset_y; int dst_offset_x, dst_offset_y; int width, height; Bitmap *crumbled_bitmap; int crumbled_src_x, crumbled_src_y; int crumbled_border_size; boolean has_crumbled_graphics; boolean preserve_background; int unique_identifier; /* used to identify needed screen updates */ }; struct EngineSnapshotInfo_EM { struct GameInfo_EM game_em; unsigned long RandomEM; struct LEVEL lev; struct PLAYER ply[MAX_PLAYERS]; short Array[4][EM_MAX_CAVE_HEIGHT][EM_MAX_CAVE_WIDTH]; int screen_x; int screen_y; int frame; short **Boom; short **Cave; short **Next; short **Draw; }; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ extern struct GlobalInfo_EM global_em_info; extern struct LevelInfo_EM native_em_level; extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; extern struct EngineSnapshotInfo_EM engine_snapshot_em; extern void em_open_all(); extern void em_close_all(); extern void InitGameEngine_EM(); extern void GameActions_EM(byte *, boolean); extern unsigned int InitEngineRandom_EM(long); extern void setLevelInfoToDefaults_EM(); extern boolean LoadNativeLevel_EM(char *); extern void BackToFront_EM(void); extern void BlitScreenToBitmap_EM(Bitmap *); extern void RedrawPlayfield_EM(boolean); extern void DrawGameDoorValues_EM(); extern void LoadEngineSnapshotValues_EM(); extern void SaveEngineSnapshotValues_EM(); #endif /* EXPORT_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/tab_generate.c0000644000175000017500000020602010407325362021575 0ustar dimkadimka/* 2000-04-19T13:26:05Z * * construct some tables to be included directly in emerald mine source. * i made this because dynamically building the tables every time sucks and i * need to be able to easily modify tile.h. * * this is key data which almost everything depends on. * * this is supposed to be fairly easy to read and modify. the tab values * are still hard coded constants but that should be less of a problem to * modify. */ #include "main_em.h" /* ------------------------------------------------------------------------- */ /* 0=stop 1=blank */ int tile_blank[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, TILE_MAX }; /* 0=stop 1=acid */ int tile_acid[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, Xacid_1, 1, Xacid_2, 1, Xacid_3, 1, Xacid_4, 1, Xacid_5, 1, Xacid_6, 1, Xacid_7, 1, Xacid_8, 1, TILE_MAX }; /* 0=stop 1=amoeba */ int tile_amoeba[] = { Xdripper, 1, XdripperB, 1, Xamoeba_1, 1, Xamoeba_2, 1, Xamoeba_3, 1, Xamoeba_4, 1, Xamoeba_5, 1, Xamoeba_6, 1, Xamoeba_7, 1, Xamoeba_8, 1, TILE_MAX }; /* 0=stop 1=move */ int tile_android_move[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, Xplant, 1, TILE_MAX }; /* ------------------------------------------------------------------------- */ /* explosions: special format */ /* everything is initially filled with Xboom_1 */ int tile_explode[] = { ZBORDER, Znormal, Zdynamite, Xboom_bug, Xboom_bomb, Xboom_android, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_s, Xandroid_2_s, Xandroid_1_w, Xandroid_2_w, Xacid_ne, Xacid_nw, Xacid_s, Xacid_se, Xacid_sw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xplant, Yplant, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, TILE_MAX, /* up till here are indestructable */ Xbug_n, Xboom_bug, Xbug_e, Xboom_bug, Xbug_s, Xboom_bug, Xbug_w, Xboom_bug, Xbug_gon, Xboom_bug, Xbug_goe, Xboom_bug, Xbug_gos, Xboom_bug, Xbug_gow, Xboom_bug, Xbomb, Xboom_bomb, Xbomb_pause, Xboom_bomb, Xbomb_fall, Xboom_bomb, TILE_MAX, /* up till here are special explosions */ Xandroid, Xboom_android, Xandroid_1_n, Xboom_android, Xandroid_2_n, Xboom_android, Xandroid_1_e, Xboom_android, Xandroid_2_e, Xboom_android, Xandroid_1_s, Xboom_android, Xandroid_2_s, Xboom_android, Xandroid_1_w, Xboom_android, Xandroid_2_w, Xboom_android, TILE_MAX /* up until here are dynamite explosions */ }; /* ------------------------------------------------------------------------- */ /* map the graphics file to internal tiles and animations * * one graphics icon maps to many tiles and animations */ int obj_map[] = { /* special */ Ystone_sB, 7, Xsand_stonein_4, 7, -1, Xsand_stonein_4, 5, Xsand_stonein_4, 6, -1, Ystone_sB, 6, Xsand_stonein_4, 3, Xsand_stonein_4, 4, -1, Xsand_stonein_4, 1, Xsand_stonein_4, 2, -1, Ystone_sB, 5, Xsand_stonein_3, 7, Xsand_stonein_4, 0, -1, Xsand_stonein_3, 5, Xsand_stonein_3, 6, -1, Ystone_sB, 4, Xsand_stonein_3, 3, Xsand_stonein_3, 4, -1, Xsand_stonein_3, 1, Xsand_stonein_3, 2, -1, Ystone_sB, 3, Xsand_stonein_2, 7, Xsand_stonein_3, 0, -1, Xsand_stonein_2, 5, Xsand_stonein_2, 6, -1, Ystone_sB, 2, Xsand_stonein_2, 3, Xsand_stonein_2, 4, -1, Xsand_stonein_2, 1, Xsand_stonein_2, 2, -1, Ystone_sB, 1, Xsand_stonein_1, 7, Xsand_stonein_2, 0, -1, Xsand_stonein_1, 5, Xsand_stonein_1, 6, -1, Ystone_sB, 0, Xsand_stonein_1, 3, Xsand_stonein_1, 4, -1, Xsand_stonein_1, 1, Xsand_stonein_1, 2, -1, Xstone, 0, Xstone, 1, Xstone, 2, Xstone, 3, Xstone, 4, Xstone, 5, Xstone, 6, Xstone, 7, Xstone_pause, 0, Xstone_pause, 1, Xstone_pause, 2, Xstone_pause, 3, Xstone_pause, 4, Xstone_pause, 5, Xstone_pause, 6, Xstone_pause, 7, Xstone_fall, 0, Xstone_fall, 1, Xstone_fall, 2, Xstone_fall, 3, Xstone_fall, 4, Xstone_fall, 5, Xstone_fall, 6, Xstone_fall, 7, #ifdef BAD_ROLL Xstone_force_e, 0, Xstone_force_e, 1, Xstone_force_e, 2, Xstone_force_e, 3, Xstone_force_e, 4, Xstone_force_e, 5, Xstone_force_e, 6, Xstone_force_e, 7, Xstone_force_w, 0, Xstone_force_w, 1, Xstone_force_w, 2, Xstone_force_w, 3, Xstone_force_w, 4, Xstone_force_w, 5, Xstone_force_w, 6, Xstone_force_w, 7, #endif Ystone_s, 7, Xsand_stoneout_2, 7, Xsand_stonein_1, 0, Ystone_e, 7, Ystone_w, 7, Ydiamond_stone, 7, -1, -1, Ystone_s, 6, Xsand_stoneout_2, 6, -1, -1, Ystone_s, 5, Xsand_stoneout_2, 5, -1, -1, Ystone_s, 4, Xsand_stoneout_2, 4, -1, Xsand_stoneout_2, 3, -1, Ystone_s, 3, Xsand_stoneout_2, 2, -1, Xsand_stoneout_2, 1, -1, Ystone_s, 2, Xsand_stoneout_2, 0, -1, Xsand_stoneout_1, 7, Xsand_stoneout_1, 6, -1, Ystone_s, 1, Xsand_stoneout_1, 5, -1, Xsand_stoneout_1, 4, Xsand_stoneout_1, 3, -1, Ystone_s, 0, Xsand_stoneout_1, 2, -1, Xsand_stoneout_1, 1, Xsand_stoneout_1, 0, -1, #if 0 /* use normal "Xblank" instead of explicit x==0, y==2 empty space graphic */ Ynut_sB, 7, #endif -1, -1, Ynut_sB, 6, -1, -1, Ynut_sB, 5, -1, -1, Ynut_sB, 4, -1, -1, Ynut_sB, 3, -1, -1, Ynut_sB, 2, -1, -1, Ynut_sB, 1, -1, -1, Ynut_sB, 0, -1, -1, Ynut_s, 7, Ynut_e, 7, Ynut_w, 7, Xnut, 0, Xnut, 1, Xnut, 2, Xnut, 3, Xnut, 4, Xnut, 5, Xnut, 6, Xnut, 7, Xnut_pause, 0, Xnut_pause, 1, Xnut_pause, 2, Xnut_pause, 3, Xnut_pause, 4, Xnut_pause, 5, Xnut_pause, 6, Xnut_pause, 7, Xnut_fall, 0, Xnut_fall, 1, Xnut_fall, 2, Xnut_fall, 3, Xnut_fall, 4, Xnut_fall, 5, Xnut_fall, 6, Xnut_fall, 7, #ifdef BAD_ROLL Xnut_force_e, 0, Xnut_force_e, 1, Xnut_force_e, 2, Xnut_force_e, 3, Xnut_force_e, 4, Xnut_force_e, 5, Xnut_force_e, 6, Xnut_force_e, 7, Xnut_force_w, 0, Xnut_force_w, 1, Xnut_force_w, 2, Xnut_force_w, 3, Xnut_force_w, 4, Xnut_force_w, 5, Xnut_force_w, 6, Xnut_force_w, 7, #endif -1, -1, Ynut_s, 6, -1, -1, Ynut_s, 5, -1, -1, Ynut_s, 4, -1, -1, Ynut_s, 3, -1, -1, Ynut_s, 2, -1, -1, Ynut_s, 1, -1, -1, Ynut_s, 0, -1, -1, /* normal */ Xblank, 0, Xblank, 1, Xblank, 2, Xblank, 3, Xblank, 4, Xblank, 5, Xblank, 6, Xblank, 7, Xfake_blank, 0, Xfake_blank, 1, Xfake_blank, 2, Xfake_blank, 3, Xfake_blank, 4, Xfake_blank, 5, Xfake_blank, 6, Xfake_blank, 7, Xdripper, 0, Xdripper, 1, Xdripper, 2, Xdripper, 3, Xdripper, 4, Xdripper, 5, Xdripper, 6, Xdripper, 7, Zplayer, 0, Zplayer, 1, Zplayer, 2, Zplayer, 3, Zplayer, 4, Zplayer, 5, Zplayer, 6, Zplayer, 7, Ydynamite_eat, 3, Ydynamite_eat, 4, Ydynamite_eat, 5, Ydynamite_eat, 6, Ydynamite_eat, 7, -1, -1, -1, -1, -1, Ystone_eB, 6, Ystone_w, 0, -1, Ystone_e, 6, Ystone_wB, 0, -1, Ystone_eB, 5, Ystone_w, 1, -1, Ystone_e, 5, Ystone_wB, 1, -1, Ystone_eB, 4, Ystone_w, 2, -1, Ystone_e, 4, Ystone_wB, 2, -1, Ystone_eB, 3, Ystone_w, 3, -1, Ystone_e, 3, Ystone_wB, 3, -1, Ystone_eB, 2, Ystone_w, 4, -1, Ystone_e, 2, Ystone_wB, 4, -1, Ystone_eB, 1, Ystone_w, 5, -1, Ystone_e, 1, Ystone_wB, 5, -1, Ystone_eB, 0, Ystone_w, 6, -1, Ystone_e, 0, Ystone_wB, 6, -1, Ynut_eB, 6, Ynut_w, 0, -1, Ynut_e, 6, Ynut_wB, 0, -1, Ynut_eB, 5, Ynut_w, 1, -1, Ynut_e, 5, Ynut_wB, 1, -1, Ynut_eB, 4, Ynut_w, 2, -1, Ynut_e, 4, Ynut_wB, 2, -1, Ynut_eB, 3, Ynut_w, 3, -1, Ynut_e, 3, Ynut_wB, 3, -1, Ynut_eB, 2, Ynut_w, 4, -1, Ynut_e, 2, Ynut_wB, 4, -1, Ynut_eB, 1, Ynut_w, 5, -1, Ynut_e, 1, Ynut_wB, 5, -1, Ynut_eB, 0, Ynut_w, 6, -1, Ynut_e, 0, Ynut_wB, 6, -1, Ybug_w_n, 7, Ybug_e_n, 7, Ybug_n, 7, Xbug_n, 0, Xbug_n, 1, Xbug_n, 2, Xbug_n, 3, Xbug_n, 4, Xbug_n, 5, Xbug_n, 6, Xbug_n, 7, Xbug_gon, 0, Xbug_gon, 1, Xbug_gon, 2, Xbug_gon, 3, Xbug_gon, 4, Xbug_gon, 5, Xbug_gon, 6, Xbug_gon, 7, -1, Ybug_n_e, 7, Ybug_s_e, 7, Ybug_e, 7, Xbug_e, 0, Xbug_e, 1, Xbug_e, 2, Xbug_e, 3, Xbug_e, 4, Xbug_e, 5, Xbug_e, 6, Xbug_e, 7, Xbug_goe, 0, Xbug_goe, 1, Xbug_goe, 2, Xbug_goe, 3, Xbug_goe, 4, Xbug_goe, 5, Xbug_goe, 6, Xbug_goe, 7, -1, Ybug_e_s, 7, Ybug_w_s, 7, Ybug_s, 7, Xbug_s, 0, Xbug_s, 1, Xbug_s, 2, Xbug_s, 3, Xbug_s, 4, Xbug_s, 5, Xbug_s, 6, Xbug_s, 7, Xbug_gos, 0, Xbug_gos, 1, Xbug_gos, 2, Xbug_gos, 3, Xbug_gos, 4, Xbug_gos, 5, Xbug_gos, 6, Xbug_gos, 7, -1, Ybug_n_w, 7, Ybug_s_w, 7, Ybug_w, 7, Xbug_w, 0, Xbug_w, 1, Xbug_w, 2, Xbug_w, 3, Xbug_w, 4, Xbug_w, 5, Xbug_w, 6, Xbug_w, 7, Xbug_gow, 0, Xbug_gow, 1, Xbug_gow, 2, Xbug_gow, 3, Xbug_gow, 4, Xbug_gow, 5, Xbug_gow, 6, Xbug_gow, 7, -1, Ybug_n, 0, -1, Ybug_nB, 0, -1, Ybug_n, 1, -1, Ybug_nB, 1, -1, Ybug_n, 2, -1, Ybug_nB, 2, -1, Ybug_n, 3, -1, Ybug_nB, 3, -1, Ybug_n, 4, -1, Ybug_nB, 4, -1, Ybug_n, 5, -1, Ybug_nB, 5, -1, Ybug_n, 6, -1, Ybug_nB, 6, -1, Ybug_eB, 6, -1, Ybug_e, 6, -1, Ybug_eB, 5, -1, Ybug_e, 5, -1, Ybug_eB, 4, -1, Ybug_e, 4, -1, Ybug_eB, 3, -1, Ybug_e, 3, -1, Ybug_eB, 2, -1, Ybug_e, 2, -1, Ybug_eB, 1, -1, Ybug_e, 1, -1, Ybug_eB, 0, -1, Ybug_e, 0, -1, Ybug_sB, 6, -1, Ybug_s, 6, -1, Ybug_sB, 5, -1, Ybug_s, 5, -1, Ybug_sB, 4, -1, Ybug_s, 4, -1, Ybug_sB, 3, -1, Ybug_s, 3, -1, Ybug_sB, 2, -1, Ybug_s, 2, -1, Ybug_sB, 1, -1, Ybug_s, 1, -1, Ybug_sB, 0, -1, Ybug_s, 0, -1, Ybug_w, 0, -1, Ybug_wB, 0, -1, Ybug_w, 1, -1, Ybug_wB, 1, -1, Ybug_w, 2, -1, Ybug_wB, 2, -1, Ybug_w, 3, -1, Ybug_wB, 3, -1, Ybug_w, 4, -1, Ybug_wB, 4, -1, Ybug_w, 5, -1, Ybug_wB, 5, -1, Ybug_w, 6, -1, Ybug_wB, 6, -1, Ybug_n_e, 0, Ybug_e_n, 6, -1, Ybug_n_e, 1, Ybug_e_n, 5, -1, Ybug_n_e, 2, Ybug_e_n, 4, -1, Ybug_n_e, 3, Ybug_e_n, 3, -1, Ybug_n_e, 4, Ybug_e_n, 2, -1, Ybug_n_e, 5, Ybug_e_n, 1, -1, Ybug_n_e, 6, Ybug_e_n, 0, -1, Ybug_e_s, 0, Ybug_s_e, 6, -1, Ybug_e_s, 1, Ybug_s_e, 5, -1, Ybug_e_s, 2, Ybug_s_e, 4, -1, Ybug_e_s, 3, Ybug_s_e, 3, -1, Ybug_e_s, 4, Ybug_s_e, 2, -1, Ybug_e_s, 5, Ybug_s_e, 1, -1, Ybug_e_s, 6, Ybug_s_e, 0, -1, Ybug_s_w, 0, Ybug_w_s, 6, -1, Ybug_s_w, 1, Ybug_w_s, 5, -1, Ybug_s_w, 2, Ybug_w_s, 4, -1, Ybug_s_w, 3, Ybug_w_s, 3, -1, Ybug_s_w, 4, Ybug_w_s, 2, -1, Ybug_s_w, 5, Ybug_w_s, 1, -1, Ybug_s_w, 6, Ybug_w_s, 0, -1, Ybug_n_w, 6, Ybug_w_n, 0, -1, Ybug_n_w, 5, Ybug_w_n, 1, -1, Ybug_n_w, 4, Ybug_w_n, 2, -1, Ybug_n_w, 3, Ybug_w_n, 3, -1, Ybug_n_w, 2, Ybug_w_n, 4, -1, Ybug_n_w, 1, Ybug_w_n, 5, -1, Ybug_n_w, 0, Ybug_w_n, 6, -1, Ybug_stone, 0, -1, Ybug_stone, 1, -1, Ybug_stone, 2, -1, Ybug_stone, 3, -1, Ybug_stone, 4, -1, Ybug_stone, 5, -1, Ybug_stone, 6, -1, Ybug_spring, 0, -1, Ybug_spring, 1, -1, Ybug_spring, 2, -1, Ybug_spring, 3, -1, Ybug_spring, 4, -1, Ybug_spring, 5, -1, Ybug_spring, 6, -1, Ytank_w_n, 7, Ytank_e_n, 7, Ytank_n, 7, Xtank_n, 0, Xtank_n, 1, Xtank_n, 2, Xtank_n, 3, Xtank_n, 4, Xtank_n, 5, Xtank_n, 6, Xtank_n, 7, Xtank_gon, 0, Xtank_gon, 1, Xtank_gon, 2, Xtank_gon, 3, Xtank_gon, 4, Xtank_gon, 5, Xtank_gon, 6, Xtank_gon, 7, -1, Ytank_n_e, 7, Ytank_s_e, 7, Ytank_e, 7, Xtank_e, 0, Xtank_e, 1, Xtank_e, 2, Xtank_e, 3, Xtank_e, 4, Xtank_e, 5, Xtank_e, 6, Xtank_e, 7, Xtank_goe, 0, Xtank_goe, 1, Xtank_goe, 2, Xtank_goe, 3, Xtank_goe, 4, Xtank_goe, 5, Xtank_goe, 6, Xtank_goe, 7, -1, Ytank_e_s, 7, Ytank_w_s, 7, Ytank_s, 7, Xtank_s, 0, Xtank_s, 1, Xtank_s, 2, Xtank_s, 3, Xtank_s, 4, Xtank_s, 5, Xtank_s, 6, Xtank_s, 7, Xtank_gos, 0, Xtank_gos, 1, Xtank_gos, 2, Xtank_gos, 3, Xtank_gos, 4, Xtank_gos, 5, Xtank_gos, 6, Xtank_gos, 7, -1, Ytank_n_w, 7, Ytank_s_w, 7, Ytank_w, 7, Xtank_w, 0, Xtank_w, 1, Xtank_w, 2, Xtank_w, 3, Xtank_w, 4, Xtank_w, 5, Xtank_w, 6, Xtank_w, 7, Xtank_gow, 0, Xtank_gow, 1, Xtank_gow, 2, Xtank_gow, 3, Xtank_gow, 4, Xtank_gow, 5, Xtank_gow, 6, Xtank_gow, 7, -1, Ytank_n, 0, -1, Ytank_nB, 0, -1, Ytank_n, 1, -1, Ytank_nB, 1, -1, Ytank_n, 2, -1, Ytank_nB, 2, -1, Ytank_n, 3, -1, Ytank_nB, 3, -1, Ytank_n, 4, -1, Ytank_nB, 4, -1, Ytank_n, 5, -1, Ytank_nB, 5, -1, Ytank_n, 6, -1, Ytank_nB, 6, -1, Ytank_eB, 6, -1, Ytank_e, 6, -1, Ytank_eB, 5, -1, Ytank_e, 5, -1, Ytank_eB, 4, -1, Ytank_e, 4, -1, Ytank_eB, 3, -1, Ytank_e, 3, -1, Ytank_eB, 2, -1, Ytank_e, 2, -1, Ytank_eB, 1, -1, Ytank_e, 1, -1, Ytank_eB, 0, -1, Ytank_e, 0, -1, Ytank_sB, 6, -1, Ytank_s, 6, -1, Ytank_sB, 5, -1, Ytank_s, 5, -1, Ytank_sB, 4, -1, Ytank_s, 4, -1, Ytank_sB, 3, -1, Ytank_s, 3, -1, Ytank_sB, 2, -1, Ytank_s, 2, -1, Ytank_sB, 1, -1, Ytank_s, 1, -1, Ytank_sB, 0, -1, Ytank_s, 0, -1, Ytank_w, 0, -1, Ytank_wB, 0, -1, Ytank_w, 1, -1, Ytank_wB, 1, -1, Ytank_w, 2, -1, Ytank_wB, 2, -1, Ytank_w, 3, -1, Ytank_wB, 3, -1, Ytank_w, 4, -1, Ytank_wB, 4, -1, Ytank_w, 5, -1, Ytank_wB, 5, -1, Ytank_w, 6, -1, Ytank_wB, 6, -1, Ytank_n_e, 0, Ytank_e_n, 6, -1, Ytank_n_e, 1, Ytank_e_n, 5, -1, Ytank_n_e, 2, Ytank_e_n, 4, -1, Ytank_n_e, 3, Ytank_e_n, 3, -1, Ytank_n_e, 4, Ytank_e_n, 2, -1, Ytank_n_e, 5, Ytank_e_n, 1, -1, Ytank_n_e, 6, Ytank_e_n, 0, -1, Ytank_e_s, 0, Ytank_s_e, 6, -1, Ytank_e_s, 1, Ytank_s_e, 5, -1, Ytank_e_s, 2, Ytank_s_e, 4, -1, Ytank_e_s, 3, Ytank_s_e, 3, -1, Ytank_e_s, 4, Ytank_s_e, 2, -1, Ytank_e_s, 5, Ytank_s_e, 1, -1, Ytank_e_s, 6, Ytank_s_e, 0, -1, Ytank_s_w, 0, Ytank_w_s, 6, -1, Ytank_s_w, 1, Ytank_w_s, 5, -1, Ytank_s_w, 2, Ytank_w_s, 4, -1, Ytank_s_w, 3, Ytank_w_s, 3, -1, Ytank_s_w, 4, Ytank_w_s, 2, -1, Ytank_s_w, 5, Ytank_w_s, 1, -1, Ytank_s_w, 6, Ytank_w_s, 0, -1, Ytank_n_w, 6, Ytank_w_n, 0, -1, Ytank_n_w, 5, Ytank_w_n, 1, -1, Ytank_n_w, 4, Ytank_w_n, 2, -1, Ytank_n_w, 3, Ytank_w_n, 3, -1, Ytank_n_w, 2, Ytank_w_n, 4, -1, Ytank_n_w, 1, Ytank_w_n, 5, -1, Ytank_n_w, 0, Ytank_w_n, 6, -1, Ytank_stone, 0, -1, Ytank_stone, 1, -1, Ytank_stone, 2, -1, Ytank_stone, 3, -1, Ytank_stone, 4, -1, Ytank_stone, 5, -1, Ytank_stone, 6, -1, Ytank_spring, 0, -1, Ytank_spring, 1, -1, Ytank_spring, 2, -1, Ytank_spring, 3, -1, Ytank_spring, 4, -1, Ytank_spring, 5, -1, Ytank_spring, 6, -1, Yandroid_n, 7, Yandroid_ne, 7, Yandroid_e, 7, Yandroid_se, 7, Yandroid_s, 7, Yandroid_sw, 7, Yandroid_w, 7, Yandroid_nw, 7, Xandroid, 7, Xandroid_1_n, 7, Xandroid_2_n, 7, Xandroid_1_e, 7, Xandroid_2_e, 7, Xandroid_1_w, 7, Xandroid_2_w, 7, Xandroid_1_s, 7, Xandroid_2_s, 7, -1, Xandroid, 0, Xandroid_1_n, 0, Xandroid_2_n, 0, Xandroid_1_e, 0, Xandroid_2_e, 0, Xandroid_1_w, 0, Xandroid_2_w, 0, Xandroid_1_s, 0, Xandroid_2_s, 0, -1, Xandroid, 1, Xandroid_1_n, 1, Xandroid_2_n, 1, Xandroid_1_e, 1, Xandroid_2_e, 1, Xandroid_1_w, 1, Xandroid_2_w, 1, Xandroid_1_s, 1, Xandroid_2_s, 1, -1, Xandroid, 2, Xandroid_1_n, 2, Xandroid_2_n, 2, Xandroid_1_e, 2, Xandroid_2_e, 2, Xandroid_1_w, 2, Xandroid_2_w, 2, Xandroid_1_s, 2, Xandroid_2_s, 2, -1, Xandroid, 3, Xandroid_1_n, 3, Xandroid_2_n, 3, Xandroid_1_e, 3, Xandroid_2_e, 3, Xandroid_1_w, 3, Xandroid_2_w, 3, Xandroid_1_s, 3, Xandroid_2_s, 3, -1, Xandroid, 4, Xandroid_1_n, 4, Xandroid_2_n, 4, Xandroid_1_e, 4, Xandroid_2_e, 4, Xandroid_1_w, 4, Xandroid_2_w, 4, Xandroid_1_s, 4, Xandroid_2_s, 4, -1, Xandroid, 5, Xandroid_1_n, 5, Xandroid_2_n, 5, Xandroid_1_e, 5, Xandroid_2_e, 5, Xandroid_1_w, 5, Xandroid_2_w, 5, Xandroid_1_s, 5, Xandroid_2_s, 5, -1, Xandroid, 6, Xandroid_1_n, 6, Xandroid_2_n, 6, Xandroid_1_e, 6, Xandroid_2_e, 6, Xandroid_1_w, 6, Xandroid_2_w, 6, Xandroid_1_s, 6, Xandroid_2_s, 6, -1, Yandroid_n, 0, Yandroid_sB, 6, -1, Yandroid_nB, 0, Yandroid_s, 6, -1, Yandroid_n, 1, Yandroid_sB, 5, -1, Yandroid_nB, 1, Yandroid_s, 5, -1, Yandroid_n, 2, Yandroid_sB, 4, Xboom_android, 0, -1, Yandroid_nB, 2, Yandroid_s, 4, Xboom_android, 1, -1, Yandroid_n, 3, Yandroid_sB, 3, Xboom_android, 2, -1, Yandroid_nB, 3, Yandroid_s, 3, Xboom_android, 3, -1, Yandroid_n, 4, Yandroid_sB, 2, Xboom_android, 4, -1, Yandroid_nB, 4, Yandroid_s, 2, Xboom_android, 5, -1, Yandroid_n, 5, Yandroid_sB, 1, Xboom_android, 6, -1, Yandroid_nB, 5, Yandroid_s, 1, -1, Yandroid_n, 6, Yandroid_sB, 0, -1, Yandroid_nB, 6, Yandroid_s, 0, -1, Yandroid_eB, 6, Yandroid_w, 0, -1, Yandroid_e, 6, Yandroid_wB, 0, -1, Yandroid_eB, 5, Yandroid_w, 1, -1, Yandroid_e, 5, Yandroid_wB, 1, -1, Yandroid_eB, 4, Yandroid_w, 2, -1, Yandroid_e, 4, Yandroid_wB, 2, -1, Yandroid_eB, 3, Yandroid_w, 3, -1, Yandroid_e, 3, Yandroid_wB, 3, -1, Yandroid_eB, 2, Yandroid_w, 4, -1, Yandroid_e, 2, Yandroid_wB, 4, -1, Yandroid_eB, 1, Yandroid_w, 5, -1, Yandroid_e, 1, Yandroid_wB, 5, -1, Yandroid_eB, 0, Yandroid_w, 6, -1, Yandroid_e, 0, Yandroid_wB, 6, -1, Yandroid_neB, 6, Yandroid_sw, 0, -1, Yandroid_ne, 6, Yandroid_swB, 0, -1, Yandroid_neB, 5, Yandroid_sw, 1, -1, Yandroid_ne, 5, Yandroid_swB, 1, -1, Yandroid_neB, 4, Yandroid_sw, 2, -1, Yandroid_ne, 4, Yandroid_swB, 2, -1, Yandroid_neB, 3, Yandroid_sw, 3, -1, Yandroid_ne, 3, Yandroid_swB, 3, -1, Yandroid_neB, 2, Yandroid_sw, 4, -1, Yandroid_ne, 2, Yandroid_swB, 4, -1, Yandroid_neB, 1, Yandroid_sw, 5, -1, Yandroid_ne, 1, Yandroid_swB, 5, -1, Yandroid_neB, 0, Yandroid_sw, 6, -1, Yandroid_ne, 0, Yandroid_swB, 6, -1, Yandroid_nw, 0, Yandroid_seB, 6, -1, Yandroid_nwB, 0, Yandroid_se, 6, -1, Yandroid_nw, 1, Yandroid_seB, 5, -1, Yandroid_nwB, 1, Yandroid_se, 5, -1, Yandroid_nw, 2, Yandroid_seB, 4, -1, Yandroid_nwB, 2, Yandroid_se, 4, -1, Yandroid_nw, 3, Yandroid_seB, 3, -1, Yandroid_nwB, 3, Yandroid_se, 3, -1, Yandroid_nw, 4, Yandroid_seB, 2, -1, Yandroid_nwB, 4, Yandroid_se, 2, -1, Yandroid_nw, 5, Yandroid_seB, 1, -1, Yandroid_nwB, 5, Yandroid_se, 1, -1, Yandroid_nw, 6, Yandroid_seB, 0, -1, Yandroid_nwB, 6, Yandroid_se, 0, -1, Yspring_e, 7, Yspring_w, 7, Yspring_kill_e, 7, Yspring_kill_w, 7, Yspring_s, 7, Xspring, 0, Xspring, 1, Xspring, 2, Xspring, 3, Xspring, 4, Xspring, 5, Xspring, 6, Xspring, 7, Xspring_pause, 0, Xspring_pause, 1, Xspring_pause, 2, Xspring_pause, 3, Xspring_pause, 4, Xspring_pause, 5, Xspring_pause, 6, Xspring_pause, 7, Xspring_e, 0, Xspring_e, 1, Xspring_e, 2, Xspring_e, 3, Xspring_e, 4, Xspring_e, 5, Xspring_e, 6, Xspring_e, 7, Xspring_w, 0, Xspring_w, 1, Xspring_w, 2, Xspring_w, 3, Xspring_w, 4, Xspring_w, 5, Xspring_w, 6, Xspring_w, 7, Xspring_fall, 0, Xspring_fall, 1, Xspring_fall, 2, Xspring_fall, 3, Xspring_fall, 4, Xspring_fall, 5, Xspring_fall, 6, Xspring_fall, 7, #ifdef BAD_ROLL Xspring_force_e, 0, Xspring_force_e, 1, Xspring_force_e, 2, Xspring_force_e, 3, Xspring_force_e, 4, Xspring_force_e, 5, Xspring_force_e, 6, Xspring_force_e, 7, Xspring_force_w, 0, Xspring_force_w, 1, Xspring_force_w, 2, Xspring_force_w, 3, Xspring_force_w, 4, Xspring_force_w, 5, Xspring_force_w, 6, Xspring_force_w, 7, #endif -1, Yspring_sB, 6, -1, Yspring_s, 6, -1, Yspring_sB, 5, -1, Yspring_s, 5, -1, Yspring_sB, 4, -1, Yspring_s, 4, -1, Yspring_sB, 3, -1, Yspring_s, 3, -1, Yspring_sB, 2, -1, Yspring_s, 2, -1, Yspring_sB, 1, -1, Yspring_s, 1, -1, Yspring_sB, 0, -1, Yspring_s, 0, -1, Yspring_eB, 6, Yspring_w, 0, -1, Yspring_e, 6, Yspring_wB, 0, -1, Yspring_eB, 5, Yspring_w, 1, -1, Yspring_e, 5, Yspring_wB, 1, -1, Yspring_eB, 4, Yspring_w, 2, -1, Yspring_e, 4, Yspring_wB, 2, -1, Yspring_eB, 3, Yspring_w, 3, -1, Yspring_e, 3, Yspring_wB, 3, -1, Yspring_eB, 2, Yspring_w, 4, -1, Yspring_e, 2, Yspring_wB, 4, -1, Yspring_eB, 1, Yspring_w, 5, -1, Yspring_e, 1, Yspring_wB, 5, -1, Yspring_eB, 0, Yspring_w, 6, -1, Yspring_e, 0, Yspring_wB, 6, -1, Yspring_kill_eB, 6, -1, Yspring_kill_e, 6, -1, Yspring_kill_eB, 5, -1, Yspring_kill_e, 5, -1, Yspring_kill_eB, 4, -1, Yspring_kill_e, 4, -1, Yspring_kill_eB, 3, -1, Yspring_kill_e, 3, -1, Yspring_kill_eB, 2, -1, Yspring_kill_e, 2, -1, Yspring_kill_eB, 1, -1, Yspring_kill_e, 1, -1, Yspring_kill_eB, 0, -1, Yspring_kill_e, 0, -1, Yspring_kill_w, 0, -1, Yspring_kill_wB, 0, -1, Yspring_kill_w, 1, -1, Yspring_kill_wB, 1, -1, Yspring_kill_w, 2, -1, Yspring_kill_wB, 2, -1, Yspring_kill_w, 3, -1, Yspring_kill_wB, 3, -1, Yspring_kill_w, 4, -1, Yspring_kill_wB, 4, -1, Yspring_kill_w, 5, -1, Yspring_kill_wB, 5, -1, Yspring_kill_w, 6, -1, Yspring_kill_wB, 6, -1, Xeater_n, 0, Xeater_e, 0, Xeater_w, 0, Xeater_s, 0, Xeater_n, 7, Xeater_e, 7, Xeater_s, 7, Xeater_w, 7, Yeater_n, 7, Yeater_e, 7, Yeater_s, 7, Yeater_w, 7, -1, Xeater_n, 1, Xeater_e, 1, Xeater_w, 1, Xeater_s, 1, Xeater_n, 6, Xeater_e, 6, Xeater_w, 6, Xeater_s, 6, -1, Xeater_n, 2, Xeater_e, 2, Xeater_w, 2, Xeater_s, 2, Xeater_n, 5, Xeater_e, 5, Xeater_w, 5, Xeater_s, 5, -1, Xeater_n, 3, Xeater_e, 3, Xeater_w, 3, Xeater_s, 3, Xeater_n, 4, Xeater_e, 4, Xeater_w, 4, Xeater_s, 4, -1, Yeater_n, 0, Yeater_sB, 6, -1, Yeater_nB, 0, Yeater_s, 6, -1, Yeater_n, 1, Yeater_sB, 5, -1, Yeater_nB, 1, Yeater_s, 5, -1, Yeater_n, 2, Yeater_sB, 4, -1, Yeater_nB, 2, Yeater_s, 4, -1, Yeater_n, 3, Yeater_sB, 3, -1, Yeater_nB, 3, Yeater_s, 3, -1, Yeater_n, 4, Yeater_sB, 2, -1, Yeater_nB, 4, Yeater_s, 2, -1, Yeater_n, 5, Yeater_sB, 1, -1, Yeater_nB, 5, Yeater_s, 1, -1, Yeater_n, 6, Yeater_sB, 0, -1, Yeater_nB, 6, Yeater_s, 0, -1, Yeater_eB, 6, Yeater_w, 0, -1, Yeater_e, 6, Yeater_wB, 0, -1, Yeater_eB, 5, Yeater_w, 1, -1, Yeater_e, 5, Yeater_wB, 1, -1, Yeater_eB, 4, Yeater_w, 2, -1, Yeater_e, 4, Yeater_wB, 2, -1, Yeater_eB, 3, Yeater_w, 3, -1, Yeater_e, 3, Yeater_wB, 3, -1, Yeater_eB, 2, Yeater_w, 4, -1, Yeater_e, 2, Yeater_wB, 4, -1, Yeater_eB, 1, Yeater_w, 5, -1, Yeater_e, 1, Yeater_wB, 5, -1, Yeater_eB, 0, Yeater_w, 6, -1, Yeater_e, 0, Yeater_wB, 6, -1, Yeater_stone, 0, -1, Yeater_stone, 1, -1, Yeater_stone, 2, -1, Yeater_stone, 3, -1, Yeater_stone, 4, -1, Yeater_stone, 5, -1, Yeater_stone, 6, -1, Yeater_spring, 0, -1, Yeater_spring, 1, -1, Yeater_spring, 2, -1, Yeater_spring, 3, -1, Yeater_spring, 4, -1, Yeater_spring, 5, -1, Yeater_spring, 6, -1, Xalien, 0, Xalien_pause, 0, Xalien, 7, Xalien_pause, 7, Yalien_n, 7, Yalien_e, 7, Yalien_s, 7, Yalien_w, 7, -1, Xalien, 1, Xalien_pause, 1, Xalien, 6, Xalien_pause, 6, -1, Xalien, 2, Xalien_pause, 2, Xalien, 5, Xalien_pause, 5, -1, Xalien, 3, Xalien_pause, 3, Xalien, 4, Xalien_pause, 4, -1, Yalien_n, 0, Yalien_sB, 6, -1, Yalien_nB, 0, Yalien_s, 6, -1, Yalien_n, 1, Yalien_sB, 5, -1, Yalien_nB, 1, Yalien_s, 5, -1, Yalien_n, 2, Yalien_sB, 4, -1, Yalien_nB, 2, Yalien_s, 4, -1, Yalien_n, 3, Yalien_sB, 3, -1, Yalien_nB, 3, Yalien_s, 3, -1, Yalien_n, 4, Yalien_sB, 2, -1, Yalien_nB, 4, Yalien_s, 2, -1, Yalien_n, 5, Yalien_sB, 1, -1, Yalien_nB, 5, Yalien_s, 1, -1, Yalien_n, 6, Yalien_sB, 0, -1, Yalien_nB, 6, Yalien_s, 0, -1, Yalien_eB, 6, Yalien_w, 0, -1, Yalien_e, 6, Yalien_wB, 0, -1, Yalien_eB, 5, Yalien_w, 1, -1, Yalien_e, 5, Yalien_wB, 1, -1, Yalien_eB, 4, Yalien_w, 2, -1, Yalien_e, 4, Yalien_wB, 2, -1, Yalien_eB, 3, Yalien_w, 3, -1, Yalien_e, 3, Yalien_wB, 3, -1, Yalien_eB, 2, Yalien_w, 4, -1, Yalien_e, 2, Yalien_wB, 4, -1, Yalien_eB, 1, Yalien_w, 5, -1, Yalien_e, 1, Yalien_wB, 5, -1, Yalien_eB, 0, Yalien_w, 6, -1, Yalien_e, 0, Yalien_wB, 6, -1, Yalien_stone, 0, -1, Yalien_stone, 1, -1, Yalien_stone, 2, -1, Yalien_stone, 3, -1, Yalien_stone, 4, -1, Yalien_stone, 5, -1, Yalien_stone, 6, -1, Yalien_spring, 0, -1, Yalien_spring, 1, -1, Yalien_spring, 2, -1, Yalien_spring, 3, -1, Yalien_spring, 4, -1, Yalien_spring, 5, -1, Yalien_spring, 6, -1, Xemerald, 0, Xemerald, 1, Xemerald, 2, Xemerald, 3, Xemerald, 4, Xemerald, 5, Xemerald, 6, Xemerald, 7, Xemerald_pause, 0, Xemerald_pause, 1, Xemerald_pause, 2, Xemerald_pause, 3, Xemerald_pause, 4, Xemerald_pause, 5, Xemerald_pause, 6, Xemerald_pause, 7, Xemerald_fall, 0, Xemerald_fall, 1, Xemerald_fall, 2, Xemerald_fall, 3, Xemerald_fall, 4, Xemerald_fall, 5, Xemerald_fall, 6, Xemerald_fall, 7, #ifdef BAD_ROLL Xemerald_force_e, 0, Xemerald_force_e, 1, Xemerald_force_e, 2, Xemerald_force_e, 3, Xemerald_force_e, 4, Xemerald_force_e, 5, Xemerald_force_e, 6, Xemerald_force_e, 7, Xemerald_force_w, 0, Xemerald_force_w, 1, Xemerald_force_w, 2, Xemerald_force_w, 3, Xemerald_force_w, 4, Xemerald_force_w, 5, Xemerald_force_w, 6, Xemerald_force_w, 7, #endif Xemerald_shine, 0, Xemerald_shine, 7, Yemerald_stone, 7, Yemerald_s, 7, Yemerald_e, 7, Yemerald_w, 7, -1, Xemerald_shine, 1, Xemerald_shine, 6, -1, Xemerald_shine, 2, Xemerald_shine, 5, -1, Xemerald_shine, 3, Xemerald_shine, 4, -1, Yemerald_sB, 6, -1, Yemerald_s, 6, -1, Yemerald_sB, 5, -1, Yemerald_s, 5, -1, Yemerald_sB, 4, -1, Yemerald_s, 4, -1, Yemerald_sB, 3, -1, Yemerald_s, 3, -1, Yemerald_sB, 2, -1, Yemerald_s, 2, -1, Yemerald_sB, 1, -1, Yemerald_s, 1, -1, Yemerald_sB, 0, -1, Yemerald_s, 0, -1, Yemerald_eB, 6, Yemerald_w, 0, -1, Yemerald_e, 6, Yemerald_wB, 0, -1, Yemerald_eB, 5, Yemerald_w, 1, -1, Yemerald_e, 5, Yemerald_wB, 1, -1, Yemerald_eB, 4, Yemerald_w, 2, -1, Yemerald_e, 4, Yemerald_wB, 2, -1, Yemerald_eB, 3, Yemerald_w, 3, -1, Yemerald_e, 3, Yemerald_wB, 3, -1, Yemerald_eB, 2, Yemerald_w, 4, -1, Yemerald_e, 2, Yemerald_wB, 4, -1, Yemerald_eB, 1, Yemerald_w, 5, -1, Yemerald_e, 1, Yemerald_wB, 5, -1, Yemerald_eB, 0, Yemerald_w, 6, -1, Yemerald_e, 0, Yemerald_wB, 6, -1, Yemerald_eat, 6, -1, Yemerald_eat, 5, -1, Yemerald_eat, 4, -1, Yemerald_eat, 3, -1, Yemerald_eat, 2, -1, Yemerald_eat, 1, -1, Yemerald_eat, 0, -1, Yemerald_stone, 0, -1, Yemerald_stone, 1, -1, Yemerald_stone, 2, -1, Yemerald_stone, 3, -1, Yemerald_stone, 4, -1, Yemerald_stone, 5, -1, Yemerald_stone, 6, -1, Xdiamond, 0, Xdiamond, 1, Xdiamond, 2, Xdiamond, 3, Xdiamond, 4, Xdiamond, 5, Xdiamond, 6, Xdiamond, 7, Xdiamond_pause, 0, Xdiamond_pause, 1, Xdiamond_pause, 2, Xdiamond_pause, 3, Xdiamond_pause, 4, Xdiamond_pause, 5, Xdiamond_pause, 6, Xdiamond_pause, 7, Xdiamond_fall, 0, Xdiamond_fall, 1, Xdiamond_fall, 2, Xdiamond_fall, 3, Xdiamond_fall, 4, Xdiamond_fall, 5, Xdiamond_fall, 6, Xdiamond_fall, 7, #ifdef BAD_ROLL Xdiamond_force_e, 0, Xdiamond_force_e, 1, Xdiamond_force_e, 2, Xdiamond_force_e, 3, Xdiamond_force_e, 4, Xdiamond_force_e, 5, Xdiamond_force_e, 6, Xdiamond_force_e, 7, Xdiamond_force_w, 0, Xdiamond_force_w, 1, Xdiamond_force_w, 2, Xdiamond_force_w, 3, Xdiamond_force_w, 4, Xdiamond_force_w, 5, Xdiamond_force_w, 6, Xdiamond_force_w, 7, #endif Xdiamond_shine, 0, Xdiamond_shine, 7, Ydiamond_s, 7, Ydiamond_e, 7, Ydiamond_w, 7, -1, Xdiamond_shine, 1, Xdiamond_shine, 6, -1, Xdiamond_shine, 2, Xdiamond_shine, 5, -1, Xdiamond_shine, 3, Xdiamond_shine, 4, -1, Ydiamond_sB, 6, -1, Ydiamond_s, 6, -1, Ydiamond_sB, 5, -1, Ydiamond_s, 5, -1, Ydiamond_sB, 4, -1, Ydiamond_s, 4, -1, Ydiamond_sB, 3, -1, Ydiamond_s, 3, -1, Ydiamond_sB, 2, -1, Ydiamond_s, 2, -1, Ydiamond_sB, 1, -1, Ydiamond_s, 1, -1, Ydiamond_sB, 0, -1, Ydiamond_s, 0, -1, Ydiamond_eB, 6, Ydiamond_w, 0, -1, Ydiamond_e, 6, Ydiamond_wB, 0, -1, Ydiamond_eB, 5, Ydiamond_w, 1, -1, Ydiamond_e, 5, Ydiamond_wB, 1, -1, Ydiamond_eB, 4, Ydiamond_w, 2, -1, Ydiamond_e, 4, Ydiamond_wB, 2, -1, Ydiamond_eB, 3, Ydiamond_w, 3, -1, Ydiamond_e, 3, Ydiamond_wB, 3, -1, Ydiamond_eB, 2, Ydiamond_w, 4, -1, Ydiamond_e, 2, Ydiamond_wB, 4, -1, Ydiamond_eB, 1, Ydiamond_w, 5, -1, Ydiamond_e, 1, Ydiamond_wB, 5, -1, Ydiamond_eB, 0, Ydiamond_w, 6, -1, Ydiamond_e, 0, Ydiamond_wB, 6, -1, Ydiamond_eat, 6, -1, Ydiamond_eat, 5, -1, Ydiamond_eat, 4, -1, Ydiamond_eat, 3, -1, Ydiamond_eat, 2, -1, Ydiamond_eat, 1, -1, Ydiamond_eat, 0, -1, Ydiamond_stone, 0, -1, Ydiamond_stone, 1, -1, Ydiamond_stone, 2, -1, Ydiamond_stone, 3, -1, Ydiamond_stone, 4, -1, Ydiamond_stone, 5, -1, Ydiamond_stone, 6, -1, Xdrip_fall, 0, Xdrip_fall, 1, Xdrip_fall, 2, Xdrip_fall, 3, Xdrip_fall, 4, Xdrip_fall, 5, Xdrip_fall, 6, Xdrip_fall, 7, Xdrip_eat, 7, Ydrip_s2, 7, -1, Ydrip_s2B, 6, -1, Ydrip_s2, 6, -1, Ydrip_s2B, 5, -1, Ydrip_s2, 5, -1, Ydrip_s2B, 4, -1, Ydrip_s2, 4, -1, Ydrip_s2B, 3, -1, Ydrip_s2, 3, -1, Ydrip_s2B, 2, -1, Ydrip_s2, 2, -1, Ydrip_s2B, 1, -1, Ydrip_s2, 1, -1, Ydrip_s2B, 0, -1, Ydrip_s2, 0, -1, Xdrip_stretchB, 0, Xdrip_stretchB, 1, Xdrip_stretchB, 2, Xdrip_stretchB, 3, Xdrip_stretchB, 4, Xdrip_stretchB, 5, Xdrip_stretchB, 6, Xdrip_stretchB, 7, Ydrip_s1B, 7, -1, Xdrip_stretch, 0, Xdrip_stretch, 1, Xdrip_stretch, 2, Xdrip_stretch, 3, Xdrip_stretch, 4, Xdrip_stretch, 5, Xdrip_stretch, 6, Xdrip_stretch, 7, Ydrip_s1, 7, -1, Ydrip_s1B, 6, -1, Ydrip_s1, 6, -1, Ydrip_s1B, 5, -1, Ydrip_s1, 5, -1, Ydrip_s1B, 4, -1, Ydrip_s1, 4, -1, Ydrip_s1B, 3, -1, Ydrip_s1, 3, -1, Ydrip_s1B, 2, -1, Ydrip_s1, 2, -1, Ydrip_s1B, 1, -1, Ydrip_s1, 1, -1, Ydrip_s1B, 0, -1, Ydrip_s1, 0, -1, Xdrip_eat, 0, -1, Xdrip_eat, 1, -1, Xdrip_eat, 2, -1, Xdrip_eat, 3, -1, Xdrip_eat, 4, -1, Xdrip_eat, 5, -1, Xdrip_eat, 6, -1, Xbomb, 0, Xbomb, 1, Xbomb, 2, Xbomb, 3, Xbomb, 4, Xbomb, 5, Xbomb, 6, Xbomb, 7, Xbomb_pause, 0, Xbomb_pause, 1, Xbomb_pause, 2, Xbomb_pause, 3, Xbomb_pause, 4, Xbomb_pause, 5, Xbomb_pause, 6, Xbomb_pause, 7, Xbomb_fall, 0, Xbomb_fall, 1, Xbomb_fall, 2, Xbomb_fall, 3, Xbomb_fall, 4, Xbomb_fall, 5, Xbomb_fall, 6, Xbomb_fall, 7, #ifdef BAD_ROLL Xbomb_force_e, 0, Xbomb_force_e, 1, Xbomb_force_e, 2, Xbomb_force_e, 3, Xbomb_force_e, 4, Xbomb_force_e, 5, Xbomb_force_e, 6, Xbomb_force_e, 7, Xbomb_force_w, 0, Xbomb_force_w, 1, Xbomb_force_w, 2, Xbomb_force_w, 3, Xbomb_force_w, 4, Xbomb_force_w, 5, Xbomb_force_w, 6, Xbomb_force_w, 7, #endif Ybomb_s, 7, Ybomb_e, 7, Ybomb_w, 7, -1, Ybomb_sB, 6, -1, Ybomb_s, 6, -1, Ybomb_sB, 5, -1, Ybomb_s, 5, -1, Ybomb_sB, 4, -1, Ybomb_s, 4, -1, Ybomb_sB, 3, -1, Ybomb_s, 3, -1, Ybomb_sB, 2, -1, Ybomb_s, 2, -1, Ybomb_sB, 1, -1, Ybomb_s, 1, -1, Ybomb_sB, 0, -1, Ybomb_s, 0, -1, Ybomb_eB, 6, Ybomb_w, 0, -1, Ybomb_e, 6, Ybomb_wB, 0, -1, Ybomb_eB, 5, Ybomb_w, 1, -1, Ybomb_e, 5, Ybomb_wB, 1, -1, Ybomb_eB, 4, Ybomb_w, 2, -1, Ybomb_e, 4, Ybomb_wB, 2, -1, Ybomb_eB, 3, Ybomb_w, 3, -1, Ybomb_e, 3, Ybomb_wB, 3, -1, Ybomb_eB, 2, Ybomb_w, 4, -1, Ybomb_e, 2, Ybomb_wB, 4, -1, Ybomb_eB, 1, Ybomb_w, 5, -1, Ybomb_e, 1, Ybomb_wB, 5, -1, Ybomb_eB, 0, Ybomb_w, 6, -1, Ybomb_e, 0, Ybomb_wB, 6, -1, Ybomb_eat, 6, -1, Ybomb_eat, 5, -1, Ybomb_eat, 4, -1, Ybomb_eat, 3, -1, Ybomb_eat, 2, -1, Ybomb_eat, 1, -1, Ybomb_eat, 0, -1, Yballoon_n, 7, Yballoon_e, 7, Yballoon_s, 7, Yballoon_w, 7, Xballoon, 0, Xballoon, 1, Xballoon, 2, Xballoon, 3, Xballoon, 4, Xballoon, 5, Xballoon, 6, Xballoon, 7, -1, Yballoon_n, 0, Yballoon_sB, 6, -1, Yballoon_nB, 0, Yballoon_s, 6, -1, Yballoon_n, 1, Yballoon_sB, 5, -1, Yballoon_nB, 1, Yballoon_s, 5, -1, Yballoon_n, 2, Yballoon_sB, 4, -1, Yballoon_nB, 2, Yballoon_s, 4, -1, Yballoon_n, 3, Yballoon_sB, 3, -1, Yballoon_nB, 3, Yballoon_s, 3, -1, Yballoon_n, 4, Yballoon_sB, 2, -1, Yballoon_nB, 4, Yballoon_s, 2, -1, Yballoon_n, 5, Yballoon_sB, 1, -1, Yballoon_nB, 5, Yballoon_s, 1, -1, Yballoon_n, 6, Yballoon_sB, 0, -1, Yballoon_nB, 6, Yballoon_s, 0, -1, Yballoon_eB, 6, Yballoon_w, 0, -1, Yballoon_e, 6, Yballoon_wB, 0, -1, Yballoon_eB, 5, Yballoon_w, 1, -1, Yballoon_e, 5, Yballoon_wB, 1, -1, Yballoon_eB, 4, Yballoon_w, 2, -1, Yballoon_e, 4, Yballoon_wB, 2, -1, Yballoon_eB, 3, Yballoon_w, 3, -1, Yballoon_e, 3, Yballoon_wB, 3, -1, Yballoon_eB, 2, Yballoon_w, 4, -1, Yballoon_e, 2, Yballoon_wB, 4, -1, Yballoon_eB, 1, Yballoon_w, 5, -1, Yballoon_e, 1, Yballoon_wB, 5, -1, Yballoon_eB, 0, Yballoon_w, 6, -1, Yballoon_e, 0, Yballoon_wB, 6, -1, Xgrass, 0, Xgrass, 1, Xgrass, 2, Xgrass, 3, Xgrass, 4, Xgrass, 5, Xgrass, 6, Xgrass, 7, Xfake_grass, 0, Xfake_grass, 1, Xfake_grass, 2, Xfake_grass, 3, Xfake_grass, 4, Xfake_grass, 5, Xfake_grass, 6, Xfake_grass, 7, -1, Ygrass_nB, 6, -1, Ygrass_nB, 5, -1, Ygrass_nB, 4, -1, Ygrass_nB, 3, -1, Ygrass_nB, 2, -1, Ygrass_nB, 1, -1, Ygrass_nB, 0, -1, Ygrass_eB, 6, -1, Ygrass_eB, 5, -1, Ygrass_eB, 4, -1, Ygrass_eB, 3, -1, Ygrass_eB, 2, -1, Ygrass_eB, 1, -1, Ygrass_eB, 0, -1, Ygrass_sB, 6, -1, Ygrass_sB, 5, -1, Ygrass_sB, 4, -1, Ygrass_sB, 3, -1, Ygrass_sB, 2, -1, Ygrass_sB, 1, -1, Ygrass_sB, 0, -1, Ygrass_wB, 6, -1, Ygrass_wB, 5, -1, Ygrass_wB, 4, -1, Ygrass_wB, 3, -1, Ygrass_wB, 2, -1, Ygrass_wB, 1, -1, Ygrass_wB, 0, -1, Xdirt, 0, Xdirt, 1, Xdirt, 2, Xdirt, 3, Xdirt, 4, Xdirt, 5, Xdirt, 6, Xdirt, 7, -1, Ydirt_nB, 6, -1, Ydirt_nB, 5, -1, Ydirt_nB, 4, -1, Ydirt_nB, 3, -1, Ydirt_nB, 2, -1, Ydirt_nB, 1, -1, Ydirt_nB, 0, -1, Ydirt_eB, 6, -1, Ydirt_eB, 5, -1, Ydirt_eB, 4, -1, Ydirt_eB, 3, -1, Ydirt_eB, 2, -1, Ydirt_eB, 1, -1, Ydirt_eB, 0, -1, Ydirt_sB, 6, -1, Ydirt_sB, 5, -1, Ydirt_sB, 4, -1, Ydirt_sB, 3, -1, Ydirt_sB, 2, -1, Ydirt_sB, 1, -1, Ydirt_sB, 0, -1, Ydirt_wB, 6, -1, Ydirt_wB, 5, -1, Ydirt_wB, 4, -1, Ydirt_wB, 3, -1, Ydirt_wB, 2, -1, Ydirt_wB, 1, -1, Ydirt_wB, 0, -1, Xacid_nw, 0, Xacid_nw, 1, Xacid_nw, 2, Xacid_nw, 3, Xacid_nw, 4, Xacid_nw, 5, Xacid_nw, 6, Xacid_nw, 7, -1, Xacid_ne, 0, Xacid_ne, 1, Xacid_ne, 2, Xacid_ne, 3, Xacid_ne, 4, Xacid_ne, 5, Xacid_ne, 6, Xacid_ne, 7, -1, Xacid_sw, 0, Xacid_sw, 1, Xacid_sw, 2, Xacid_sw, 3, Xacid_sw, 4, Xacid_sw, 5, Xacid_sw, 6, Xacid_sw, 7, -1, Xacid_s, 0, Xacid_s, 1, Xacid_s, 2, Xacid_s, 3, Xacid_s, 4, Xacid_s, 5, Xacid_s, 6, Xacid_s, 7, -1, Xacid_se, 0, Xacid_se, 1, Xacid_se, 2, Xacid_se, 3, Xacid_se, 4, Xacid_se, 5, Xacid_se, 6, Xacid_se, 7, -1, Xacid_1, 0, Xacid_1, 1, Xacid_1, 2, Xacid_1, 3, Xacid_1, 4, Xacid_1, 5, Xacid_1, 6, Xacid_1, 7, -1, Xacid_2, 0, Xacid_2, 1, Xacid_2, 2, Xacid_2, 3, Xacid_2, 4, Xacid_2, 5, Xacid_2, 6, Xacid_2, 7, -1, Xacid_3, 0, Xacid_3, 1, Xacid_3, 2, Xacid_3, 3, Xacid_3, 4, Xacid_3, 5, Xacid_3, 6, Xacid_3, 7, -1, Xacid_4, 0, Xacid_4, 1, Xacid_4, 2, Xacid_4, 3, Xacid_4, 4, Xacid_4, 5, Xacid_4, 6, Xacid_4, 7, -1, Xacid_5, 0, Xacid_5, 1, Xacid_5, 2, Xacid_5, 3, Xacid_5, 4, Xacid_5, 5, Xacid_5, 6, Xacid_5, 7, -1, Xacid_6, 0, Xacid_6, 1, Xacid_6, 2, Xacid_6, 3, Xacid_6, 4, Xacid_6, 5, Xacid_6, 6, Xacid_6, 7, -1, Xacid_7, 0, Xacid_7, 1, Xacid_7, 2, Xacid_7, 3, Xacid_7, 4, Xacid_7, 5, Xacid_7, 6, Xacid_7, 7, -1, Xacid_8, 0, Xacid_8, 1, Xacid_8, 2, Xacid_8, 3, Xacid_8, 4, Xacid_8, 5, Xacid_8, 6, Xacid_8, 7, -1, Yacid_splash_wB, 4, Yacid_splash_wB, 5, -1, Yacid_splash_wB, 2, Yacid_splash_wB, 3, -1, Yacid_splash_wB, 0, Yacid_splash_wB, 1, -1, Yacid_splash_eB, 4, Yacid_splash_eB, 5, -1, Yacid_splash_eB, 2, Yacid_splash_eB, 3, -1, Yacid_splash_eB, 0, Yacid_splash_eB, 1, -1, Xball_2B, 7, Xball_1, 0, Xball_1, 1, Xball_1, 2, Xball_1, 3, Xball_1, 4, Xball_1, 5, Xball_1, 6, Xball_1, 7, -1, Xball_1B, 0, -1, Xball_1B, 1, -1, Xball_1B, 2, -1, Xball_1B, 3, -1, Xball_1B, 4, -1, Xball_1B, 5, -1, Xball_1B, 6, -1, Xball_1B, 7, Xball_2, 0, Xball_2, 1, Xball_2, 2, Xball_2, 3, Xball_2, 4, Xball_2, 5, Xball_2, 6, Xball_2, 7, -1, Xball_2B, 0, -1, Xball_2B, 1, -1, Xball_2B, 2, -1, Xball_2B, 3, -1, Xball_2B, 4, -1, Xball_2B, 5, -1, Xball_2B, 6, -1, Ygrow_ew_eat, 7, Xgrow_ew, 0, Xgrow_ew, 1, Xgrow_ew, 2, Xgrow_ew, 3, Xgrow_ew, 4, Xgrow_ew, 5, Xgrow_ew, 6, Xgrow_ew, 7, -1, Ygrow_ew_eat, 0, -1, Ygrow_ew_eat, 1, -1, Ygrow_ew_eat, 2, -1, Ygrow_ew_eat, 3, -1, Ygrow_ew_eat, 4, -1, Ygrow_ew_eat, 5, -1, Ygrow_ew_eat, 6, -1, Ygrow_ns_eat, 7, Xgrow_ns, 0, Xgrow_ns, 1, Xgrow_ns, 2, Xgrow_ns, 3, Xgrow_ns, 4, Xgrow_ns, 5, Xgrow_ns, 6, Xgrow_ns, 7, -1, Ygrow_ns_eat, 0, -1, Ygrow_ns_eat, 1, -1, Ygrow_ns_eat, 2, -1, Ygrow_ns_eat, 3, -1, Ygrow_ns_eat, 4, -1, Ygrow_ns_eat, 5, -1, Ygrow_ns_eat, 6, -1, XwonderwallB, 7, Xwonderwall, 0, Xwonderwall, 1, Xwonderwall, 2, Xwonderwall, 3, Xwonderwall, 4, Xwonderwall, 5, Xwonderwall, 6, Xwonderwall, 7, -1, XwonderwallB, 0, -1, XwonderwallB, 1, -1, XwonderwallB, 2, -1, XwonderwallB, 3, -1, XwonderwallB, 4, -1, XwonderwallB, 5, -1, XwonderwallB, 6, -1, Xamoeba_1, 0, Xamoeba_1, 1, Xamoeba_1, 2, Xamoeba_1, 3, Xamoeba_1, 4, Xamoeba_1, 5, Xamoeba_1, 6, Xamoeba_1, 7, -1, Xamoeba_2, 0, Xamoeba_2, 1, Xamoeba_2, 2, Xamoeba_2, 3, Xamoeba_2, 4, Xamoeba_2, 5, Xamoeba_2, 6, Xamoeba_2, 7, -1, Xamoeba_3, 0, Xamoeba_3, 1, Xamoeba_3, 2, Xamoeba_3, 3, Xamoeba_3, 4, Xamoeba_3, 5, Xamoeba_3, 6, Xamoeba_3, 7, -1, Xamoeba_4, 0, Xamoeba_4, 1, Xamoeba_4, 2, Xamoeba_4, 3, Xamoeba_4, 4, Xamoeba_4, 5, Xamoeba_4, 6, Xamoeba_4, 7, -1, Xamoeba_5, 0, Xamoeba_5, 1, Xamoeba_5, 2, Xamoeba_5, 3, Xamoeba_5, 4, Xamoeba_5, 5, Xamoeba_5, 6, Xamoeba_5, 7, -1, Xamoeba_6, 0, Xamoeba_6, 1, Xamoeba_6, 2, Xamoeba_6, 3, Xamoeba_6, 4, Xamoeba_6, 5, Xamoeba_6, 6, Xamoeba_6, 7, -1, Xamoeba_7, 0, Xamoeba_7, 1, Xamoeba_7, 2, Xamoeba_7, 3, Xamoeba_7, 4, Xamoeba_7, 5, Xamoeba_7, 6, Xamoeba_7, 7, -1, Xamoeba_8, 0, Xamoeba_8, 1, Xamoeba_8, 2, Xamoeba_8, 3, Xamoeba_8, 4, Xamoeba_8, 5, Xamoeba_8, 6, Xamoeba_8, 7, -1, Xdoor_1, 0, Xdoor_1, 1, Xdoor_1, 2, Xdoor_1, 3, Xdoor_1, 4, Xdoor_1, 5, Xdoor_1, 6, Xdoor_1, 7, -1, Xdoor_2, 0, Xdoor_2, 1, Xdoor_2, 2, Xdoor_2, 3, Xdoor_2, 4, Xdoor_2, 5, Xdoor_2, 6, Xdoor_2, 7, -1, Xdoor_3, 0, Xdoor_3, 1, Xdoor_3, 2, Xdoor_3, 3, Xdoor_3, 4, Xdoor_3, 5, Xdoor_3, 6, Xdoor_3, 7, -1, Xdoor_4, 0, Xdoor_4, 1, Xdoor_4, 2, Xdoor_4, 3, Xdoor_4, 4, Xdoor_4, 5, Xdoor_4, 6, Xdoor_4, 7, -1, Xdoor_5, 0, Xdoor_5, 1, Xdoor_5, 2, Xdoor_5, 3, Xdoor_5, 4, Xdoor_5, 5, Xdoor_5, 6, Xdoor_5, 7, -1, Xdoor_6, 0, Xdoor_6, 1, Xdoor_6, 2, Xdoor_6, 3, Xdoor_6, 4, Xdoor_6, 5, Xdoor_6, 6, Xdoor_6, 7, -1, Xdoor_7, 0, Xdoor_7, 1, Xdoor_7, 2, Xdoor_7, 3, Xdoor_7, 4, Xdoor_7, 5, Xdoor_7, 6, Xdoor_7, 7, -1, Xdoor_8, 0, Xdoor_8, 1, Xdoor_8, 2, Xdoor_8, 3, Xdoor_8, 4, Xdoor_8, 5, Xdoor_8, 6, Xdoor_8, 7, -1, Xkey_1, 0, Xkey_1, 1, Xkey_1, 2, Xkey_1, 3, Xkey_1, 4, Xkey_1, 5, Xkey_1, 6, Xkey_1, 7, -1, Xkey_2, 0, Xkey_2, 1, Xkey_2, 2, Xkey_2, 3, Xkey_2, 4, Xkey_2, 5, Xkey_2, 6, Xkey_2, 7, -1, Xkey_3, 0, Xkey_3, 1, Xkey_3, 2, Xkey_3, 3, Xkey_3, 4, Xkey_3, 5, Xkey_3, 6, Xkey_3, 7, -1, Xkey_4, 0, Xkey_4, 1, Xkey_4, 2, Xkey_4, 3, Xkey_4, 4, Xkey_4, 5, Xkey_4, 6, Xkey_4, 7, -1, Xkey_5, 0, Xkey_5, 1, Xkey_5, 2, Xkey_5, 3, Xkey_5, 4, Xkey_5, 5, Xkey_5, 6, Xkey_5, 7, -1, Xkey_6, 0, Xkey_6, 1, Xkey_6, 2, Xkey_6, 3, Xkey_6, 4, Xkey_6, 5, Xkey_6, 6, Xkey_6, 7, -1, Xkey_7, 0, Xkey_7, 1, Xkey_7, 2, Xkey_7, 3, Xkey_7, 4, Xkey_7, 5, Xkey_7, 6, Xkey_7, 7, -1, Xkey_8, 0, Xkey_8, 1, Xkey_8, 2, Xkey_8, 3, Xkey_8, 4, Xkey_8, 5, Xkey_8, 6, Xkey_8, 7, -1, Xwind_n, 0, Xwind_n, 1, Xwind_n, 2, Xwind_n, 3, Xwind_n, 4, Xwind_n, 5, Xwind_n, 6, Xwind_n, 7, -1, Xwind_e, 0, Xwind_e, 1, Xwind_e, 2, Xwind_e, 3, Xwind_e, 4, Xwind_e, 5, Xwind_e, 6, Xwind_e, 7, -1, Xwind_s, 0, Xwind_s, 1, Xwind_s, 2, Xwind_s, 3, Xwind_s, 4, Xwind_s, 5, Xwind_s, 6, Xwind_s, 7, -1, Xwind_w, 0, Xwind_w, 1, Xwind_w, 2, Xwind_w, 3, Xwind_w, 4, Xwind_w, 5, Xwind_w, 6, Xwind_w, 7, -1, Xwind_nesw, 0, Xwind_nesw, 1, Xwind_nesw, 2, Xwind_nesw, 3, Xwind_nesw, 4, Xwind_nesw, 5, Xwind_nesw, 6, Xwind_nesw, 7, -1, Xwind_stop, 0, Xwind_stop, 1, Xwind_stop, 2, Xwind_stop, 3, Xwind_stop, 4, Xwind_stop, 5, Xwind_stop, 6, Xwind_stop, 7, -1, Xexit, 0, Xexit, 1, Xexit, 2, Xexit, 3, Xexit, 4, Xexit, 5, Xexit, 6, Xexit, 7, -1, Xexit_1, 0, Xexit_1, 1, Xexit_1, 2, -1, Xexit_1, 3, Xexit_1, 4, Xexit_1, 5, Xexit_3, 7, Xexit_3, 6, Xexit_3, 5, -1, Xexit_1, 6, Xexit_1, 7, Xexit_2, 0, Xexit_3, 4, Xexit_3, 3, Xexit_3, 2, -1, Xexit_2, 1, Xexit_2, 2, Xexit_2, 3, Xexit_3, 1, Xexit_3, 0, Xexit_2, 7, -1, Xexit_2, 4, Xexit_2, 5, Xexit_2, 6, -1, Ydynamite_eat, 0, Ydynamite_eat, 1, Ydynamite_eat, 2, Xdynamite, 0, Xdynamite, 1, Xdynamite, 2, Xdynamite, 3, Xdynamite, 4, Xdynamite, 5, Xdynamite, 6, Xdynamite, 7, -1, Xdynamite_4, 0, Xdynamite_4, 1, Xdynamite_4, 2, Xdynamite_4, 3, Xdynamite_4, 4, Xdynamite_4, 5, Xdynamite_4, 6, Xdynamite_4, 7, -1, Xdynamite_3, 0, Xdynamite_3, 1, Xdynamite_3, 2, Xdynamite_3, 3, Xdynamite_3, 4, Xdynamite_3, 5, Xdynamite_3, 6, Xdynamite_3, 7, -1, Xdynamite_2, 0, Xdynamite_2, 1, Xdynamite_2, 2, Xdynamite_2, 3, Xdynamite_2, 4, Xdynamite_2, 5, Xdynamite_2, 6, Xdynamite_2, 7, -1, Xdynamite_1, 0, Xdynamite_1, 1, Xdynamite_1, 2, Xdynamite_1, 3, Xdynamite_1, 4, Xdynamite_1, 5, Xdynamite_1, 6, Xdynamite_1, 7, -1, Xbumper, 0, Xbumper, 1, Xbumper, 2, Xbumper, 3, Xbumper, 4, Xbumper, 5, Xbumper, 6, Xbumper, 7, XbumperB, 0, XbumperB, 7, -1, XbumperB, 1, XbumperB, 6, -1, XbumperB, 2, XbumperB, 5, -1, XbumperB, 3, XbumperB, 4, -1, Xwheel, 0, Xwheel, 1, Xwheel, 2, Xwheel, 3, Xwheel, 4, Xwheel, 5, Xwheel, 6, Xwheel, 7, XwheelB, 7, XwheelB, 6, XwheelB, 5, XwheelB, 4, -1, XwheelB, 3, XwheelB, 2, XwheelB, 1, XwheelB, 0, -1, XswitchB, 0, XswitchB, 1, XswitchB, 2, XswitchB, 3, XswitchB, 4, XswitchB, 5, XswitchB, 6, XswitchB, 7, -1, Xswitch, 0, Xswitch, 1, Xswitch, 2, Xswitch, 3, Xswitch, 4, Xswitch, 5, Xswitch, 6, Xswitch, 7, -1, Xsand, 0, Xsand, 1, Xsand, 2, Xsand, 3, Xsand, 4, Xsand, 5, Xsand, 6, Xsand, 7, Xsand_stone, 0, Xsand_stone, 1, Xsand_stone, 2, Xsand_stone, 3, Xsand_stone, 4, Xsand_stone, 5, Xsand_stone, 6, Xsand_stone, 7, Xsand_stonesand_1, 0, Xsand_stonesand_1, 1, Xsand_stonesand_1, 2, Xsand_stonesand_1, 3, Xsand_stonesand_1, 4, Xsand_stonesand_1, 5, Xsand_stonesand_1, 6, Xsand_stonesand_1, 7, Xsand_stonesand_2, 0, Xsand_stonesand_2, 1, Xsand_stonesand_2, 2, Xsand_stonesand_2, 3, Xsand_stonesand_2, 4, Xsand_stonesand_2, 5, Xsand_stonesand_2, 6, Xsand_stonesand_2, 7, Xsand_stonesand_3, 0, Xsand_stonesand_3, 1, Xsand_stonesand_3, 2, Xsand_stonesand_3, 3, Xsand_stonesand_3, 4, Xsand_stonesand_3, 5, Xsand_stonesand_3, 6, Xsand_stonesand_3, 7, Xsand_stonesand_4, 0, Xsand_stonesand_4, 1, Xsand_stonesand_4, 2, Xsand_stonesand_4, 3, Xsand_stonesand_4, 4, Xsand_stonesand_4, 5, Xsand_stonesand_4, 6, Xsand_stonesand_4, 7, Xsand_sandstone_1, 0, Xsand_sandstone_1, 1, Xsand_sandstone_1, 2, Xsand_sandstone_1, 3, Xsand_sandstone_1, 4, Xsand_sandstone_1, 5, Xsand_sandstone_1, 6, Xsand_sandstone_1, 7, Xsand_sandstone_2, 0, Xsand_sandstone_2, 1, Xsand_sandstone_2, 2, Xsand_sandstone_2, 3, Xsand_sandstone_2, 4, Xsand_sandstone_2, 5, Xsand_sandstone_2, 6, Xsand_sandstone_2, 7, Xsand_sandstone_3, 0, Xsand_sandstone_3, 1, Xsand_sandstone_3, 2, Xsand_sandstone_3, 3, Xsand_sandstone_3, 4, Xsand_sandstone_3, 5, Xsand_sandstone_3, 6, Xsand_sandstone_3, 7, Xsand_sandstone_4, 0, Xsand_sandstone_4, 1, Xsand_sandstone_4, 2, Xsand_sandstone_4, 3, Xsand_sandstone_4, 4, Xsand_sandstone_4, 5, Xsand_sandstone_4, 6, Xsand_sandstone_4, 7, -1, Xplant, 0, Xplant, 1, Xplant, 2, Xplant, 3, Xplant, 4, Xplant, 5, Xplant, 6, Xplant, 7, Yplant, 0, Yplant, 1, Yplant, 2, Yplant, 3, Yplant, 4, Yplant, 5, Yplant, 6, Yplant, 7, -1, Xlenses, 0, Xlenses, 1, Xlenses, 2, Xlenses, 3, Xlenses, 4, Xlenses, 5, Xlenses, 6, Xlenses, 7, -1, Xmagnify, 0, Xmagnify, 1, Xmagnify, 2, Xmagnify, 3, Xmagnify, 4, Xmagnify, 5, Xmagnify, 6, Xmagnify, 7, -1, XdripperB, 0, XdripperB, 1, XdripperB, 2, XdripperB, 3, XdripperB, 4, XdripperB, 5, XdripperB, 6, XdripperB, 7, -1, Xfake_blankB, 0, Xfake_blankB, 1, Xfake_blankB, 2, Xfake_blankB, 3, Xfake_blankB, 4, Xfake_blankB, 5, Xfake_blankB, 6, Xfake_blankB, 7, -1, Xfake_grassB, 0, Xfake_grassB, 1, Xfake_grassB, 2, Xfake_grassB, 3, Xfake_grassB, 4, Xfake_grassB, 5, Xfake_grassB, 6, Xfake_grassB, 7, -1, Xfake_door_1, 0, Xfake_door_1, 1, Xfake_door_1, 2, Xfake_door_1, 3, Xfake_door_1, 4, Xfake_door_1, 5, Xfake_door_1, 6, Xfake_door_1, 7, Xfake_door_2, 0, Xfake_door_2, 1, Xfake_door_2, 2, Xfake_door_2, 3, Xfake_door_2, 4, Xfake_door_2, 5, Xfake_door_2, 6, Xfake_door_2, 7, Xfake_door_3, 0, Xfake_door_3, 1, Xfake_door_3, 2, Xfake_door_3, 3, Xfake_door_3, 4, Xfake_door_3, 5, Xfake_door_3, 6, Xfake_door_3, 7, Xfake_door_4, 0, Xfake_door_4, 1, Xfake_door_4, 2, Xfake_door_4, 3, Xfake_door_4, 4, Xfake_door_4, 5, Xfake_door_4, 6, Xfake_door_4, 7, Xfake_door_5, 0, Xfake_door_5, 1, Xfake_door_5, 2, Xfake_door_5, 3, Xfake_door_5, 4, Xfake_door_5, 5, Xfake_door_5, 6, Xfake_door_5, 7, Xfake_door_6, 0, Xfake_door_6, 1, Xfake_door_6, 2, Xfake_door_6, 3, Xfake_door_6, 4, Xfake_door_6, 5, Xfake_door_6, 6, Xfake_door_6, 7, Xfake_door_7, 0, Xfake_door_7, 1, Xfake_door_7, 2, Xfake_door_7, 3, Xfake_door_7, 4, Xfake_door_7, 5, Xfake_door_7, 6, Xfake_door_7, 7, Xfake_door_8, 0, Xfake_door_8, 1, Xfake_door_8, 2, Xfake_door_8, 3, Xfake_door_8, 4, Xfake_door_8, 5, Xfake_door_8, 6, Xfake_door_8, 7, -1, Xsteel_1, 0, Xsteel_1, 1, Xsteel_1, 2, Xsteel_1, 3, Xsteel_1, 4, Xsteel_1, 5, Xsteel_1, 6, Xsteel_1, 7, -1, Xsteel_2, 0, Xsteel_2, 1, Xsteel_2, 2, Xsteel_2, 3, Xsteel_2, 4, Xsteel_2, 5, Xsteel_2, 6, Xsteel_2, 7, -1, Xsteel_3, 0, Xsteel_3, 1, Xsteel_3, 2, Xsteel_3, 3, Xsteel_3, 4, Xsteel_3, 5, Xsteel_3, 6, Xsteel_3, 7, -1, Xsteel_4, 0, Xsteel_4, 1, Xsteel_4, 2, Xsteel_4, 3, Xsteel_4, 4, Xsteel_4, 5, Xsteel_4, 6, Xsteel_4, 7, -1, Xwall_1, 0, Xwall_1, 1, Xwall_1, 2, Xwall_1, 3, Xwall_1, 4, Xwall_1, 5, Xwall_1, 6, Xwall_1, 7, -1, Xwall_2, 0, Xwall_2, 1, Xwall_2, 2, Xwall_2, 3, Xwall_2, 4, Xwall_2, 5, Xwall_2, 6, Xwall_2, 7, -1, Xwall_3, 0, Xwall_3, 1, Xwall_3, 2, Xwall_3, 3, Xwall_3, 4, Xwall_3, 5, Xwall_3, 6, Xwall_3, 7, -1, Xwall_4, 0, Xwall_4, 1, Xwall_4, 2, Xwall_4, 3, Xwall_4, 4, Xwall_4, 5, Xwall_4, 6, Xwall_4, 7, -1, Xround_wall_1, 0, Xround_wall_1, 1, Xround_wall_1, 2, Xround_wall_1, 3, Xround_wall_1, 4, Xround_wall_1, 5, Xround_wall_1, 6, Xround_wall_1, 7, -1, Xround_wall_2, 0, Xround_wall_2, 1, Xround_wall_2, 2, Xround_wall_2, 3, Xround_wall_2, 4, Xround_wall_2, 5, Xround_wall_2, 6, Xround_wall_2, 7, -1, Xround_wall_3, 0, Xround_wall_3, 1, Xround_wall_3, 2, Xround_wall_3, 3, Xround_wall_3, 4, Xround_wall_3, 5, Xround_wall_3, 6, Xround_wall_3, 7, -1, Xround_wall_4, 0, Xround_wall_4, 1, Xround_wall_4, 2, Xround_wall_4, 3, Xround_wall_4, 4, Xround_wall_4, 5, Xround_wall_4, 6, Xround_wall_4, 7, -1, Xdecor_1, 0, Xdecor_1, 1, Xdecor_1, 2, Xdecor_1, 3, Xdecor_1, 4, Xdecor_1, 5, Xdecor_1, 6, Xdecor_1, 7, -1, Xdecor_2, 0, Xdecor_2, 1, Xdecor_2, 2, Xdecor_2, 3, Xdecor_2, 4, Xdecor_2, 5, Xdecor_2, 6, Xdecor_2, 7, -1, Xdecor_3, 0, Xdecor_3, 1, Xdecor_3, 2, Xdecor_3, 3, Xdecor_3, 4, Xdecor_3, 5, Xdecor_3, 6, Xdecor_3, 7, -1, Xdecor_4, 0, Xdecor_4, 1, Xdecor_4, 2, Xdecor_4, 3, Xdecor_4, 4, Xdecor_4, 5, Xdecor_4, 6, Xdecor_4, 7, -1, Xdecor_5, 0, Xdecor_5, 1, Xdecor_5, 2, Xdecor_5, 3, Xdecor_5, 4, Xdecor_5, 5, Xdecor_5, 6, Xdecor_5, 7, -1, Xdecor_6, 0, Xdecor_6, 1, Xdecor_6, 2, Xdecor_6, 3, Xdecor_6, 4, Xdecor_6, 5, Xdecor_6, 6, Xdecor_6, 7, -1, Xdecor_7, 0, Xdecor_7, 1, Xdecor_7, 2, Xdecor_7, 3, Xdecor_7, 4, Xdecor_7, 5, Xdecor_7, 6, Xdecor_7, 7, -1, Xdecor_8, 0, Xdecor_8, 1, Xdecor_8, 2, Xdecor_8, 3, Xdecor_8, 4, Xdecor_8, 5, Xdecor_8, 6, Xdecor_8, 7, -1, Xdecor_9, 0, Xdecor_9, 1, Xdecor_9, 2, Xdecor_9, 3, Xdecor_9, 4, Xdecor_9, 5, Xdecor_9, 6, Xdecor_9, 7, -1, Xdecor_10, 0, Xdecor_10, 1, Xdecor_10, 2, Xdecor_10, 3, Xdecor_10, 4, Xdecor_10, 5, Xdecor_10, 6, Xdecor_10, 7, -1, Xdecor_11, 0, Xdecor_11, 1, Xdecor_11, 2, Xdecor_11, 3, Xdecor_11, 4, Xdecor_11, 5, Xdecor_11, 6, Xdecor_11, 7, -1, Xdecor_12, 0, Xdecor_12, 1, Xdecor_12, 2, Xdecor_12, 3, Xdecor_12, 4, Xdecor_12, 5, Xdecor_12, 6, Xdecor_12, 7, -1, Xalpha_excla, 0, Xalpha_excla, 1, Xalpha_excla, 2, Xalpha_excla, 3, Xalpha_excla, 4, Xalpha_excla, 5, Xalpha_excla, 6, Xalpha_excla, 7, -1, Xalpha_quote, 0, Xalpha_quote, 1, Xalpha_quote, 2, Xalpha_quote, 3, Xalpha_quote, 4, Xalpha_quote, 5, Xalpha_quote, 6, Xalpha_quote, 7, -1, Xalpha_comma, 0, Xalpha_comma, 1, Xalpha_comma, 2, Xalpha_comma, 3, Xalpha_comma, 4, Xalpha_comma, 5, Xalpha_comma, 6, Xalpha_comma, 7, -1, Xalpha_minus, 0, Xalpha_minus, 1, Xalpha_minus, 2, Xalpha_minus, 3, Xalpha_minus, 4, Xalpha_minus, 5, Xalpha_minus, 6, Xalpha_minus, 7, -1, Xalpha_perio, 0, Xalpha_perio, 1, Xalpha_perio, 2, Xalpha_perio, 3, Xalpha_perio, 4, Xalpha_perio, 5, Xalpha_perio, 6, Xalpha_perio, 7, -1, Xalpha_0, 0, Xalpha_0, 1, Xalpha_0, 2, Xalpha_0, 3, Xalpha_0, 4, Xalpha_0, 5, Xalpha_0, 6, Xalpha_0, 7, -1, Xalpha_1, 0, Xalpha_1, 1, Xalpha_1, 2, Xalpha_1, 3, Xalpha_1, 4, Xalpha_1, 5, Xalpha_1, 6, Xalpha_1, 7, -1, Xalpha_2, 0, Xalpha_2, 1, Xalpha_2, 2, Xalpha_2, 3, Xalpha_2, 4, Xalpha_2, 5, Xalpha_2, 6, Xalpha_2, 7, -1, Xalpha_3, 0, Xalpha_3, 1, Xalpha_3, 2, Xalpha_3, 3, Xalpha_3, 4, Xalpha_3, 5, Xalpha_3, 6, Xalpha_3, 7, -1, Xalpha_4, 0, Xalpha_4, 1, Xalpha_4, 2, Xalpha_4, 3, Xalpha_4, 4, Xalpha_4, 5, Xalpha_4, 6, Xalpha_4, 7, -1, Xalpha_5, 0, Xalpha_5, 1, Xalpha_5, 2, Xalpha_5, 3, Xalpha_5, 4, Xalpha_5, 5, Xalpha_5, 6, Xalpha_5, 7, -1, Xalpha_6, 0, Xalpha_6, 1, Xalpha_6, 2, Xalpha_6, 3, Xalpha_6, 4, Xalpha_6, 5, Xalpha_6, 6, Xalpha_6, 7, -1, Xalpha_7, 0, Xalpha_7, 1, Xalpha_7, 2, Xalpha_7, 3, Xalpha_7, 4, Xalpha_7, 5, Xalpha_7, 6, Xalpha_7, 7, -1, Xalpha_8, 0, Xalpha_8, 1, Xalpha_8, 2, Xalpha_8, 3, Xalpha_8, 4, Xalpha_8, 5, Xalpha_8, 6, Xalpha_8, 7, -1, Xalpha_9, 0, Xalpha_9, 1, Xalpha_9, 2, Xalpha_9, 3, Xalpha_9, 4, Xalpha_9, 5, Xalpha_9, 6, Xalpha_9, 7, -1, Xalpha_colon, 0, Xalpha_colon, 1, Xalpha_colon, 2, Xalpha_colon, 3, Xalpha_colon, 4, Xalpha_colon, 5, Xalpha_colon, 6, Xalpha_colon, 7, -1, Xalpha_arrow_w, 0, Xalpha_arrow_w, 1, Xalpha_arrow_w, 2, Xalpha_arrow_w, 3, Xalpha_arrow_w, 4, Xalpha_arrow_w, 5, Xalpha_arrow_w, 6, Xalpha_arrow_w, 7, -1, Xalpha_arrow_e, 0, Xalpha_arrow_e, 1, Xalpha_arrow_e, 2, Xalpha_arrow_e, 3, Xalpha_arrow_e, 4, Xalpha_arrow_e, 5, Xalpha_arrow_e, 6, Xalpha_arrow_e, 7, -1, Xalpha_quest, 0, Xalpha_quest, 1, Xalpha_quest, 2, Xalpha_quest, 3, Xalpha_quest, 4, Xalpha_quest, 5, Xalpha_quest, 6, Xalpha_quest, 7, -1, Xalpha_a, 0, Xalpha_a, 1, Xalpha_a, 2, Xalpha_a, 3, Xalpha_a, 4, Xalpha_a, 5, Xalpha_a, 6, Xalpha_a, 7, -1, Xalpha_b, 0, Xalpha_b, 1, Xalpha_b, 2, Xalpha_b, 3, Xalpha_b, 4, Xalpha_b, 5, Xalpha_b, 6, Xalpha_b, 7, -1, Xalpha_c, 0, Xalpha_c, 1, Xalpha_c, 2, Xalpha_c, 3, Xalpha_c, 4, Xalpha_c, 5, Xalpha_c, 6, Xalpha_c, 7, -1, Xalpha_d, 0, Xalpha_d, 1, Xalpha_d, 2, Xalpha_d, 3, Xalpha_d, 4, Xalpha_d, 5, Xalpha_d, 6, Xalpha_d, 7, -1, Xalpha_e, 0, Xalpha_e, 1, Xalpha_e, 2, Xalpha_e, 3, Xalpha_e, 4, Xalpha_e, 5, Xalpha_e, 6, Xalpha_e, 7, -1, Xalpha_f, 0, Xalpha_f, 1, Xalpha_f, 2, Xalpha_f, 3, Xalpha_f, 4, Xalpha_f, 5, Xalpha_f, 6, Xalpha_f, 7, -1, Xalpha_g, 0, Xalpha_g, 1, Xalpha_g, 2, Xalpha_g, 3, Xalpha_g, 4, Xalpha_g, 5, Xalpha_g, 6, Xalpha_g, 7, -1, Xalpha_h, 0, Xalpha_h, 1, Xalpha_h, 2, Xalpha_h, 3, Xalpha_h, 4, Xalpha_h, 5, Xalpha_h, 6, Xalpha_h, 7, -1, Xalpha_i, 0, Xalpha_i, 1, Xalpha_i, 2, Xalpha_i, 3, Xalpha_i, 4, Xalpha_i, 5, Xalpha_i, 6, Xalpha_i, 7, -1, Xalpha_j, 0, Xalpha_j, 1, Xalpha_j, 2, Xalpha_j, 3, Xalpha_j, 4, Xalpha_j, 5, Xalpha_j, 6, Xalpha_j, 7, -1, Xalpha_k, 0, Xalpha_k, 1, Xalpha_k, 2, Xalpha_k, 3, Xalpha_k, 4, Xalpha_k, 5, Xalpha_k, 6, Xalpha_k, 7, -1, Xalpha_l, 0, Xalpha_l, 1, Xalpha_l, 2, Xalpha_l, 3, Xalpha_l, 4, Xalpha_l, 5, Xalpha_l, 6, Xalpha_l, 7, -1, Xalpha_m, 0, Xalpha_m, 1, Xalpha_m, 2, Xalpha_m, 3, Xalpha_m, 4, Xalpha_m, 5, Xalpha_m, 6, Xalpha_m, 7, -1, Xalpha_n, 0, Xalpha_n, 1, Xalpha_n, 2, Xalpha_n, 3, Xalpha_n, 4, Xalpha_n, 5, Xalpha_n, 6, Xalpha_n, 7, -1, Xalpha_o, 0, Xalpha_o, 1, Xalpha_o, 2, Xalpha_o, 3, Xalpha_o, 4, Xalpha_o, 5, Xalpha_o, 6, Xalpha_o, 7, -1, Xalpha_p, 0, Xalpha_p, 1, Xalpha_p, 2, Xalpha_p, 3, Xalpha_p, 4, Xalpha_p, 5, Xalpha_p, 6, Xalpha_p, 7, -1, Xalpha_q, 0, Xalpha_q, 1, Xalpha_q, 2, Xalpha_q, 3, Xalpha_q, 4, Xalpha_q, 5, Xalpha_q, 6, Xalpha_q, 7, -1, Xalpha_r, 0, Xalpha_r, 1, Xalpha_r, 2, Xalpha_r, 3, Xalpha_r, 4, Xalpha_r, 5, Xalpha_r, 6, Xalpha_r, 7, -1, Xalpha_s, 0, Xalpha_s, 1, Xalpha_s, 2, Xalpha_s, 3, Xalpha_s, 4, Xalpha_s, 5, Xalpha_s, 6, Xalpha_s, 7, -1, Xalpha_t, 0, Xalpha_t, 1, Xalpha_t, 2, Xalpha_t, 3, Xalpha_t, 4, Xalpha_t, 5, Xalpha_t, 6, Xalpha_t, 7, -1, Xalpha_u, 0, Xalpha_u, 1, Xalpha_u, 2, Xalpha_u, 3, Xalpha_u, 4, Xalpha_u, 5, Xalpha_u, 6, Xalpha_u, 7, -1, Xalpha_v, 0, Xalpha_v, 1, Xalpha_v, 2, Xalpha_v, 3, Xalpha_v, 4, Xalpha_v, 5, Xalpha_v, 6, Xalpha_v, 7, -1, Xalpha_w, 0, Xalpha_w, 1, Xalpha_w, 2, Xalpha_w, 3, Xalpha_w, 4, Xalpha_w, 5, Xalpha_w, 6, Xalpha_w, 7, -1, Xalpha_x, 0, Xalpha_x, 1, Xalpha_x, 2, Xalpha_x, 3, Xalpha_x, 4, Xalpha_x, 5, Xalpha_x, 6, Xalpha_x, 7, -1, Xalpha_y, 0, Xalpha_y, 1, Xalpha_y, 2, Xalpha_y, 3, Xalpha_y, 4, Xalpha_y, 5, Xalpha_y, 6, Xalpha_y, 7, -1, Xalpha_z, 0, Xalpha_z, 1, Xalpha_z, 2, Xalpha_z, 3, Xalpha_z, 4, Xalpha_z, 5, Xalpha_z, 6, Xalpha_z, 7, -1, Xalpha_copyr, 0, Xalpha_copyr, 1, Xalpha_copyr, 2, Xalpha_copyr, 3, Xalpha_copyr, 4, Xalpha_copyr, 5, Xalpha_copyr, 6, Xalpha_copyr, 7, -1, Yball_eat, 7, Yball_eat, 6, Yball_eat, 5, Ykey_1_eat, 7, Ykey_1_eat, 6, Ykey_1_eat, 5, Ykey_2_eat, 7, Ykey_2_eat, 6, Ykey_2_eat, 5, Ykey_3_eat, 7, Ykey_3_eat, 6, Ykey_3_eat, 5, Ykey_4_eat, 7, Ykey_4_eat, 6, Ykey_4_eat, 5, Ykey_5_eat, 7, Ykey_5_eat, 6, Ykey_5_eat, 5, Ykey_6_eat, 7, Ykey_6_eat, 6, Ykey_6_eat, 5, Ykey_7_eat, 7, Ykey_7_eat, 6, Ykey_7_eat, 5, Ykey_8_eat, 7, Ykey_8_eat, 6, Ykey_8_eat, 5, Ylenses_eat, 7, Ylenses_eat, 6, Ylenses_eat, 5, Ymagnify_eat, 7, Ymagnify_eat, 6, Ymagnify_eat, 5, Ygrass_eat, 7, Ygrass_eat, 6, Ygrass_eat, 5, Ydirt_eat, 7, Ydirt_eat, 6, Ydirt_eat, 5, Xboom_2, 7, Xboom_2, 6, Xboom_2, 5, -1, Yball_eat, 4, Yball_eat, 3, Yball_eat, 2, Ykey_1_eat, 4, Ykey_1_eat, 3, Ykey_1_eat, 2, Ykey_2_eat, 4, Ykey_2_eat, 3, Ykey_2_eat, 2, Ykey_3_eat, 4, Ykey_3_eat, 3, Ykey_3_eat, 2, Ykey_4_eat, 4, Ykey_4_eat, 3, Ykey_4_eat, 2, Ykey_5_eat, 4, Ykey_5_eat, 3, Ykey_5_eat, 2, Ykey_6_eat, 4, Ykey_6_eat, 3, Ykey_6_eat, 2, Ykey_7_eat, 4, Ykey_7_eat, 3, Ykey_7_eat, 2, Ykey_8_eat, 4, Ykey_8_eat, 3, Ykey_8_eat, 2, Ylenses_eat, 4, Ylenses_eat, 3, Ylenses_eat, 2, Ymagnify_eat, 4, Ymagnify_eat, 3, Ymagnify_eat, 2, Ygrass_eat, 4, Ygrass_eat, 3, Ygrass_eat, 2, Ydirt_eat, 4, Ydirt_eat, 3, Ydirt_eat, 2, Xboom_2, 4, Xboom_2, 3, Xboom_2, 2, -1, Yball_eat, 1, Yball_eat, 0, Ykey_1_eat, 1, Ykey_1_eat, 0, Ykey_2_eat, 1, Ykey_2_eat, 0, Ykey_3_eat, 1, Ykey_3_eat, 0, Ykey_4_eat, 1, Ykey_4_eat, 0, Ykey_5_eat, 1, Ykey_5_eat, 0, Ykey_6_eat, 1, Ykey_6_eat, 0, Ykey_7_eat, 1, Ykey_7_eat, 0, Ykey_8_eat, 1, Ykey_8_eat, 0, Ylenses_eat, 1, Ylenses_eat, 0, Ymagnify_eat, 1, Ymagnify_eat, 0, Ygrass_eat, 1, Ygrass_eat, 0, Ydirt_eat, 1, Ydirt_eat, 0, Xboom_2, 1, Xboom_2, 0, Xboom_1, 7, -1, Xboom_1, 6, Xboom_1, 5, Xboom_android, 7, -1, Xboom_1, 4, Xboom_1, 3, Xboom_bug, 4, Xboom_bomb, 4, Xboom_bug, 3, Xboom_bomb, 3, -1, Xboom_1, 2, Xboom_1, 1, Xboom_bug, 6, Xboom_bomb, 6, Xboom_bug, 5, Xboom_bomb, 5, Xboom_bug, 2, Xboom_bomb, 2, Xboom_bug, 1, Xboom_bomb, 1, -1, Xboom_bug, 0, Xboom_bug, 7, Xboom_bomb, 0, Xboom_bomb, 7, Xboom_1, 0, Ybug_stone, 7, Ybug_spring, 7, Ytank_stone, 7, Ytank_spring, 7, Yeater_stone, 7, Yeater_spring, 7, Yalien_stone, 7, Yalien_spring, 7, Ybomb_eat, 7, -1 }; int spr_map[] = { SPR_walk + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, SPR_walk + 1, 0, 8, 9, 10, 11, 12, 13, 14, 15, SPR_walk + 2, 0, 16, 17, 18, 19, 20, 21, 22, 23, SPR_walk + 3, 0, 24, 25, 26, 27, 28, 29, 30, 31, SPR_push + 0, 0, 32, 33, 34, 35, 36, 35, 34, 33, SPR_push + 1, 0, 37, 38, 39, 40, 41, 40, 39, 38, SPR_push + 2, 0, 42, 43, 44, 45, 46, 45, 44, 43, SPR_push + 3, 0, 47, 48, 49, 50, 51, 50, 49, 48, SPR_spray + 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, SPR_spray + 1, 0, 53, 53, 53, 53, 53, 53, 53, 53, SPR_spray + 2, 0, 54, 54, 54, 54, 54, 54, 54, 54, SPR_spray + 3, 0, 55, 55, 55, 55, 55, 55, 55, 55, SPR_walk + 0, 1, 56, 57, 58, 59, 60, 61, 62, 63, SPR_walk + 1, 1, 64, 65, 66, 67, 68, 69, 70, 71, SPR_walk + 2, 1, 72, 73, 74, 75, 76, 77, 78, 79, SPR_walk + 3, 1, 80, 81, 82, 83, 84, 85, 86, 87, SPR_push + 0, 1, 88, 89, 90, 91, 92, 91, 90, 89, SPR_push + 1, 1, 93, 94, 95, 96, 97, 96, 95, 94, SPR_push + 2, 1, 98, 99, 100, 101, 102, 101, 100, 99, SPR_push + 3, 1, 103, 104, 105, 106, 107, 106, 105, 104, SPR_spray + 0, 1, 108, 108, 108, 108, 108, 108, 108, 108, SPR_spray + 1, 1, 109, 109, 109, 109, 109, 109, 109, 109, SPR_spray + 2, 1, 110, 110, 110, 110, 110, 110, 110, 110, SPR_spray + 3, 1, 111, 111, 111, 111, 111, 111, 111, 111, SPR_still, 0, 112,112, 112, 112, 112, 112, 112, 112, SPR_still, 1, 113,113, 113, 113, 113, 113, 113, 113, SPR_MAX }; /* 0=stop 1=blank */ unsigned char tab_blank[TILE_MAX]; /* 0=stop 1=acid */ unsigned char tab_acid[TILE_MAX]; /* 0=stop 1=amoeba */ unsigned char tab_amoeba[TILE_MAX]; /* 0=stop 1=move */ unsigned char tab_android_move[TILE_MAX]; /* normal explosion */ unsigned short tab_explode_normal[TILE_MAX]; /* dynamite explosion */ unsigned short tab_explode_dynamite[TILE_MAX]; /* map tiles to coords */ unsigned short map_obj[8][TILE_MAX]; /* map sprites to coords */ unsigned short map_spr[2][8][13]; /* map ascii to coords */ unsigned short map_ttl[128]; /* map tiles and frames to graphic info */ struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; /* map player number, frames and action to graphic info */ struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; void create_tab(int *invert, unsigned char *array) { int i; int buffer[TILE_MAX]; for (i = 0; i < TILE_MAX; i++) buffer[i] = 0; for (;invert[0] < TILE_MAX; invert += 2) buffer[invert[0]] = invert[1]; for (i = 0; i < TILE_MAX; i++) array[i] = buffer[i]; } void create_explode() { int i; int *tile = tile_explode; int buffer[TILE_MAX]; for (i = 0; i < TILE_MAX; i++) buffer[i] = Xboom_1; while ((i = *tile++) < TILE_MAX) buffer[i] = i; /* these tiles are indestructable */ while ((i = *tile++) < TILE_MAX) buffer[i] = *tile++; /* these tiles are special */ for (i = 0; i < TILE_MAX; i++) tab_explode_normal[i] = buffer[i]; while ((i = *tile++) < TILE_MAX) buffer[i] = *tile++; /* these tiles for dynamite */ for (i = 0; i < TILE_MAX; i++) tab_explode_dynamite[i] = buffer[i]; } void create_obj() { int i, j; int *map = obj_map; int buffer[8][TILE_MAX]; #if 0 int debug = 0; for (i = 0; i < 8; i++) for (j = 0; j < TILE_MAX; j++) buffer[i][j] = 0; for (i = 0; i < 64; i++) { for (;*map != -1; map += 2) { if (map[0] < 0 || map[0] >= TILE_MAX || map[1] < 0 || map[1] >= 8) { fprintf(stderr, "obj_map: bad tile (%d, %d) @ %d+%d\n", map[0], map[1], i / 16, i % 16); debug = 1; continue; } buffer[map[1]][map[0]]++; } map++; } for (i = 0; i < 896; i++) { for (;*map != -1; map += 2) { if (map[0] < 0 || map[0] >= TILE_MAX || map[1] < 0 || map[1] >= 8) { fprintf(stderr, "obj_map: bad tile (%d, %d) @ %d\n", map[0], map[1], i); debug = 1; continue; } buffer[map[1]][map[0]]++; } map++; } for (i = 0; i < TILE_MAX; i++) { for (j = 0; j < 8; j++) { switch(buffer[j][i]) { case 0: fprintf(stderr, "obj_map: uninitialized (%d, %d)\n", i, j); debug = 1; break; case 1: break; /* good */ default: fprintf(stderr, "obj_map: duplicate (%d, %d)\n", i, j); debug = 1; break; } } } if (sizeof(obj_map) / sizeof(*obj_map) != map - obj_map) { fprintf(stderr, "obj_map: bad end (%d != %d)\n", sizeof(obj_map) / sizeof(*obj_map), map - obj_map); debug = 1; } if (debug == 0) fprintf(stderr, "obj_map: looks good, now disable debug code\n"); abort(); #else for (i = 0; i < 8; i++) for (j = 0; j < TILE_MAX; j++) buffer[i][j] = Xblank; /* special case for first 64 entries */ for (i = 0; i < 64; i++) { for (;*map != -1; map += 2) buffer[map[1]][map[0]] = i; map++; } /* now regular entries */ for (i = 0; i < 896 * 16; i += 16) { for (;*map != -1; map += 2) buffer[map[1]][map[0]] = i; map++; } for (i = 0; i < 8; i++) for (j = 0; j < TILE_MAX; j++) map_obj[i][j] = buffer[7 - i][j]; #endif } void create_obj_graphics_info_em() { int i, j; for (i = 0; i < TILE_MAX; i++) { for (j = 0; j < 8; j++) { struct GraphicInfo_EM *g = &graphic_info_em_object[i][j]; int obj = map_obj[j][i]; g->bitmap = objBitmap; g->src_x = (obj / 512) * TILEX; g->src_y = (obj % 512) * TILEY / 16; g->src_offset_x = 0; g->src_offset_y = 0; g->dst_offset_x = 0; g->dst_offset_y = 0; g->width = TILEX; g->height = TILEY; g->crumbled_bitmap = NULL; g->crumbled_src_x = 0; g->crumbled_src_y = 0; g->crumbled_border_size = 0; g->has_crumbled_graphics = FALSE; g->preserve_background = FALSE; /* create unique graphic identifier to decide if tile must be redrawn */ g->unique_identifier = obj; } } } void create_spr() { int i, j, k; int *map = spr_map; int buffer[2][8][SPR_MAX]; while (*map < SPR_MAX) { i = *map++; j = *map++; for (k = 0; k < 8; k++) buffer[j][k][i] = *map++; } for (i = 0; i < 2; i++) for (j = 0; j < 8; j++) for (k = 0; k < SPR_MAX; k++) map_spr[i][j][k] = buffer[i][7 - j][k]; } void create_spr_graphics_info_em() { int i, j, k; for (i = 0; i < MAX_PLAYERS; i++) { for (j = 0; j < SPR_MAX; j++) { for (k = 0; k < 8; k++) { struct GraphicInfo_EM *g = &graphic_info_em_player[i][j][k]; int spr = map_spr[i % 2][k][j]; g->bitmap = sprBitmap; g->src_x = (spr / 8) * TILEX; g->src_y = (spr % 8) * TILEY; g->src_offset_x = 0; g->src_offset_y = 0; g->dst_offset_x = 0; g->dst_offset_y = 0; g->width = TILEX; g->height = TILEY; g->has_crumbled_graphics = FALSE; g->crumbled_bitmap = NULL; g->crumbled_src_x = 0; g->crumbled_src_y = 0; g->crumbled_border_size = 0; g->unique_identifier = 0; } } } } void tab_generate() { create_tab(tile_blank, tab_blank); create_tab(tile_acid, tab_acid); create_tab(tile_amoeba, tab_amoeba); create_tab(tile_android_move, tab_android_move); create_explode(); create_obj(); create_spr(); } void tab_generate_graphics_info_em() { create_obj_graphics_info_em(); create_spr_graphics_info_em(); InitGraphicInfo_EM(); } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/Makefile0000644000175000017500000000317710471574171020466 0ustar dimkadimka# ============================================================================= # Rocks'n'Diamonds Makefile (game_em) # ----------------------------------------------------------------------------- # (c) 1995-2006 Holger Schemel # ----------------------------------------------------------------------------- # Emerald Mine for X11 © 2000,2001 David Tritscher # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = cave.c \ convert.c \ graphics.c \ init.c \ input.c \ main.c \ sound.c \ synchro_1.c \ synchro_2.c \ synchro_3.c \ tab_generate.c \ ulaw_generate.c OBJS = cave.o \ convert.o \ graphics.o \ init.o \ input.o \ main.o \ sound.o \ synchro_1.o \ synchro_2.o \ synchro_3.o \ tab_generate.o \ ulaw_generate.o GAME_EM = game_em.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(GAME_EM) $(GAME_EM): $(OBJS) $(AR) cru $(GAME_EM) $(OBJS) $(RANLIB) $(GAME_EM) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(GAME_EM) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif rocksndiamonds-3.3.0.1+dfsg1/src/game_em/sample.h0000644000175000017500000000074210407326135020445 0ustar dimkadimka#ifndef SAMPLE_H #define SAMPLE_H #include "main_em.h" extern void play_sound(int, int, int); extern void play_element_sound(int, int, int, int); extern char play[SAMPLE_MAX]; extern int sound_pipe[2]; extern short *sound_data[SAMPLE_MAX]; extern long sound_length[SAMPLE_MAX]; #define MIXER_MAX 4 /* maximum number of samples we can play at once */ #if defined(AUDIO_UNIX_NATIVE) enum { AUDIO_ULAW = 0, AUDIO_U8 }; #endif /* AUDIO_UNIX_NATIVE */ #endif /* SAMPLE_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/input.c0000644000175000017500000001033611375334327020325 0ustar dimkadimka/* 2000-08-13T15:29:40Z * * handle input from x11 and keyboard and joystick */ #include "main_em.h" unsigned long RandomEM; struct LEVEL lev; struct PLAYER ply[MAX_PLAYERS]; short **Boom; short **Cave; short **Next; short **Draw; static short *Index[4][HEIGHT]; static short Array[4][HEIGHT][WIDTH]; extern int screen_x; extern int screen_y; struct EngineSnapshotInfo_EM engine_snapshot_em; void game_init_vars(void) { int x, y; RandomEM = 1684108901; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[0][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[1][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[2][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[3][y][x] = Xblank; for (y = 0; y < HEIGHT; y++) Index[0][y] = Array[0][y]; for (y = 0; y < HEIGHT; y++) Index[1][y] = Array[1][y]; for (y = 0; y < HEIGHT; y++) Index[2][y] = Array[2][y]; for (y = 0; y < HEIGHT; y++) Index[3][y] = Array[3][y]; Cave = Index[0]; Next = Index[1]; Draw = Index[2]; Boom = Index[3]; } void InitGameEngine_EM() { prepare_em_level(); game_initscreen(); game_animscreen(); #if 0 /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_EM(backbuffer); #endif } void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode) { int i; #if 0 static int foo = -1; if (action[0] == 0 && foo != 0) printf("KEY RELEASED @ %05d\n", FrameCounter); foo = action[0]; #endif #if 0 #if 1 if (FrameCounter % 10 == 0) #endif printf("::: %05d: %lu, %d\n", FrameCounter, RandomEM, frame); #endif #if 0 game_animscreen(); #if 1 #if 0 SyncDisplay(); #endif blitscreen(); #endif #endif RandomEM = RandomEM * 129 + 1; frame = (frame - 1) & 7; for (i = 0; i < MAX_PLAYERS; i++) readjoy(action[i], &ply[i]); UpdateEngineValues(screen_x / TILEX, screen_y / TILEY); if (frame == 7) { synchro_1(); synchro_2(); } if (frame == 6) { synchro_3(); sound_play(); if (!warp_mode) /* do not redraw values in warp mode */ DrawGameDoorValues_EM(); } CheckSingleStepMode_EM(action, frame, game_em.any_player_moving); #if 1 game_animscreen(); #if 1 #if 0 SyncDisplay(); #endif blitscreen(); #endif #endif } /* read input device for players */ void readjoy(byte action, struct PLAYER *ply) { int north = 0, east = 0, south = 0, west = 0; int snap = 0, drop = 0; if (action & JOY_LEFT) west = 1; if (action & JOY_RIGHT) east = 1; if (action & JOY_UP) north = 1; if (action & JOY_DOWN) south = 1; if (action & JOY_BUTTON_1) snap = 1; if (action & JOY_BUTTON_2) drop = 1; ply->joy_snap = snap; ply->joy_drop = drop; if (ply->joy_stick || (north | east | south | west)) { ply->joy_n = north; ply->joy_e = east; ply->joy_s = south; ply->joy_w = west; } } void SaveEngineSnapshotValues_EM() { int i, j, k; engine_snapshot_em.game_em = game_em; engine_snapshot_em.lev = lev; engine_snapshot_em.RandomEM = RandomEM; engine_snapshot_em.frame = frame; engine_snapshot_em.screen_x = screen_x; engine_snapshot_em.screen_y = screen_y; engine_snapshot_em.Boom = Boom; engine_snapshot_em.Cave = Cave; engine_snapshot_em.Next = Next; engine_snapshot_em.Draw = Draw; for (i = 0; i < 4; i++) engine_snapshot_em.ply[i] = ply[i]; for (i = 0; i < 4; i++) for (j = 0; j < HEIGHT; j++) for (k = 0; k < WIDTH; k++) engine_snapshot_em.Array[i][j][k] = Array[i][j][k]; } void LoadEngineSnapshotValues_EM() { int i, j, k; game_em = engine_snapshot_em.game_em; lev = engine_snapshot_em.lev; RandomEM = engine_snapshot_em.RandomEM; frame = engine_snapshot_em.frame; screen_x = engine_snapshot_em.screen_x; screen_y = engine_snapshot_em.screen_y; Boom = engine_snapshot_em.Boom; Cave = engine_snapshot_em.Cave; Next = engine_snapshot_em.Next; Draw = engine_snapshot_em.Draw; for (i = 0; i < 4; i++) ply[i] = engine_snapshot_em.ply[i]; for (i = 0; i < 4; i++) for (j = 0; j < HEIGHT; j++) for (k = 0; k < WIDTH; k++) Array[i][j][k] = engine_snapshot_em.Array[i][j][k]; } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/game_em.h0000644000175000017500000000151510471574252020563 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * game_em.h * ***********************************************************/ #ifndef GAME_EM_H #define GAME_EM_H #define GAME_EM_VERSION_1_0_0 #include "export.h" #endif /* GAME_EM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/main.c0000644000175000017500000000017610123644647020112 0ustar dimkadimka/* Emerald Mine * * David Tritscher * * v0.0 2000-01-06T06:43:39Z * * set everything up and close everything down */ rocksndiamonds-3.3.0.1+dfsg1/src/game_em/synchro_3.c0000644000175000017500000000600410407326460021064 0ustar dimkadimka/* third part of synchro. * * handle global elements. * * this should be spread over the frames for reduced cpu load. */ #include "main_em.h" void synchro_3(void) { int x; int y; int count; unsigned long random; /* update variables */ if (lev.score > 9999) lev.score = 9999; #if 0 #if 1 if (lev.time_initial == 0) lev.time++; else if (lev.time > 0) lev.time--; #else if (lev.time) lev.time--; #endif #endif if (lev.android_move_cnt-- == 0) lev.android_move_cnt = lev.android_move_time; if (lev.android_clone_cnt-- == 0) lev.android_clone_cnt = lev.android_clone_time; if (lev.ball_state) if (lev.ball_cnt-- == 0) lev.ball_cnt = lev.ball_time; if (lev.lenses_cnt) lev.lenses_cnt--; if (lev.magnify_cnt) lev.magnify_cnt--; if (lev.wheel_cnt) lev.wheel_cnt--; if (lev.wind_cnt) lev.wind_cnt--; if (lev.wonderwall_time && lev.wonderwall_state) lev.wonderwall_time--; #if 0 if (lev.time_initial > 0 && lev.time > 0 && lev.time <= 50 && lev.time % 5 == 0 && setup.time_limit) play_sound(-1, -1, SAMPLE_time); #endif if (lev.wheel_cnt) play_element_sound(lev.wheel_x, lev.wheel_y, SAMPLE_wheel, Xwheel); /* grow amoeba */ random = RandomEM; for (count = lev.amoeba_time; count--;) { x = (random >> 10) % (WIDTH - 2); y = (random >> 20) % (HEIGHT - 2); switch (Cave[y][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xgrass: case Xdirt: case Xsand: case Xplant: case Yplant: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) Cave[y][x] = Xdrip_eat; } random = random * 129 + 1; } RandomEM = random; /* handle explosions */ for (y = 1; y < HEIGHT - 1; y++) for (x = 1; x < WIDTH - 1; x++) { switch (Cave[y][x]) { case Znormal: Cave[y][x] = Xboom_1; Cave[y-1][x] = tab_explode_normal[Cave[y-1][x]]; Cave[y][x-1] = tab_explode_normal[Cave[y][x-1]]; Cave[y][x+1] = tab_explode_normal[Cave[y][x+1]]; Cave[y+1][x] = tab_explode_normal[Cave[y+1][x]]; Cave[y-1][x-1] = tab_explode_normal[Cave[y-1][x-1]]; Cave[y-1][x+1] = tab_explode_normal[Cave[y-1][x+1]]; Cave[y+1][x-1] = tab_explode_normal[Cave[y+1][x-1]]; Cave[y+1][x+1] = tab_explode_normal[Cave[y+1][x+1]]; break; case Zdynamite: Cave[y][x] = Xboom_1; Cave[y-1][x] = tab_explode_dynamite[Cave[y-1][x]]; Cave[y][x-1] = tab_explode_dynamite[Cave[y][x-1]]; Cave[y][x+1] = tab_explode_dynamite[Cave[y][x+1]]; Cave[y+1][x] = tab_explode_dynamite[Cave[y+1][x]]; Cave[y-1][x-1] = tab_explode_dynamite[Cave[y-1][x-1]]; Cave[y-1][x+1] = tab_explode_dynamite[Cave[y-1][x+1]]; Cave[y+1][x-1] = tab_explode_dynamite[Cave[y+1][x-1]]; Cave[y+1][x+1] = tab_explode_dynamite[Cave[y+1][x+1]]; break; } } /* triple buffering */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Next[y][x] = Cave[y][x]; } rocksndiamonds-3.3.0.1+dfsg1/src/game_em/init.c0000644000175000017500000001567110613744747020145 0ustar dimkadimka/* 2000-08-10T18:03:54Z * * open X11 display and sound */ #include "main_em.h" #include #if !defined(TARGET_SDL) #include #endif Bitmap *objBitmap; Bitmap *sprBitmap; Bitmap *screenBitmap; #if 0 Pixmap spriteBitmap; #endif Pixmap objPixmap; Pixmap sprPixmap; #if 0 Pixmap objmaskBitmap; Pixmap sprmaskBitmap; GC spriteGC; #endif char play[SAMPLE_MAX]; int play_x[SAMPLE_MAX]; int play_y[SAMPLE_MAX]; int play_element[SAMPLE_MAX]; static boolean use_native_em_sound = 0; struct GlobalInfo_EM global_em_info; struct GameInfo_EM game_em; #if defined(AUDIO_UNIX_NATIVE) static int sound_pid = -1; int sound_pipe[2] = { -1, -1 }; /* for communication */ short *sound_data[SAMPLE_MAX]; /* pointer to sound data */ long sound_length[SAMPLE_MAX]; /* length of sound data */ static const char *sound_names[SAMPLE_MAX] = { "00.blank.au", "01.roll.au", "02.stone.au", "03.nut.au", "04.crack.au", "05.bug.au", "06.tank.au", "07.android.au", "06.tank.au", /* android moving */ "08.spring.au", "09.slurp.au", "10.eater.au", "10.eater.au", /* eater eating */ "11.alien.au", "12.collect.au", "13.diamond.au", "14.squash.au", "14.squash.au", "15.drip.au", "16.push.au", "17.dirt.au", "18.acid.au", "19.ball.au", "20.grow.au", "21.wonder.au", "22.door.au", "23.exit.au", "23.exit.au", "24.dynamite.au", "25.tick.au", "26.press.au", "27.wheel.au", "28.boom.au", "29.time.au", "30.die.au" }; static const int sound_volume[SAMPLE_MAX] = { 20, 100, 100, 100, 100, 20, 20, 100, 20, 100, 100, 50, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 20, 100, 100, 100, 100, 100, 100, 20, 100, 100, 100 }; #endif char *progname; char *arg_basedir; extern void tab_generate(); extern void tab_generate_graphics_info_em(); extern void ulaw_generate(); int open_all(void) { Bitmap *emc_bitmaps[2]; #if 0 XGCValues gcValues; #endif #if 1 SetBitmaps_EM(emc_bitmaps); objBitmap = emc_bitmaps[0]; sprBitmap = emc_bitmaps[1]; #if 0 objPixmap = emc_bitmaps[0]->drawable; sprPixmap = emc_bitmaps[1]->drawable; objmaskBitmap = emc_bitmaps[0]->clip_mask; sprmaskBitmap = emc_bitmaps[1]->clip_mask; #endif screenBitmap = CreateBitmap(MAX_BUF_XSIZE * TILEX, MAX_BUF_YSIZE * TILEY, DEFAULT_DEPTH); global_em_info.screenbuffer = screenBitmap; #endif #if 0 spriteBitmap = XCreatePixmap(display, window->drawable, TILEX, TILEY, 1); if (spriteBitmap == 0) Error(ERR_EXIT, "failed to create sprite pixmap for EM engine"); gcValues.function = objmaskBitmap ? GXcopyInverted : sprmaskBitmap ? GXcopy : GXset; gcValues.graphics_exposures = False; spriteGC = XCreateGC(display, spriteBitmap, GCFunction | GCGraphicsExposures, &gcValues); if (spriteGC == 0) Error(ERR_EXIT, "failed to create sprite GC for EM engine"); #endif /* ----------------------------------------------------------------- */ #if defined(AUDIO_UNIX_NATIVE) #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) if (use_native_em_sound) { char name[MAXNAME+2]; int i; for (i = 0; i < SAMPLE_MAX; i++) { name[MAXNAME] = 0; if (arg_basedir) { snprintf(name, MAXNAME+2, "%s/%s/%s", arg_basedir, EM_SND_DIR, sound_names[i]); } else { snprintf(name, MAXNAME+2, "%s/%s", EM_SND_DIR, sound_names[i]); } if (name[MAXNAME]) Error(ERR_EXIT, "buffer overflow when reading sounds directory"); if (read_sample(name, &sound_data[i], &sound_length[i])) return(1); { short *ptr, *stop; int mult = sound_volume[i] * 65536 / (100 * MIXER_MAX); stop = sound_data[i] + sound_length[i]; for (ptr = sound_data[i]; ptr < stop; ptr++) *ptr = (*ptr * mult) / 65536; } } if (pipe(sound_pipe) == -1) { Error(ERR_WARN, "unable to create sound pipe for EM engine -- no sound"); return(1); } sound_pid = fork(); if (sound_pid == -1) { Error(ERR_WARN, "unable to fork sound thread for EM engine -- no sound"); return(1); } close(sound_pipe[sound_pid == 0]); sound_pipe[sound_pid == 0] = -1; if (sound_pid == 0) _exit(sound_thread()); signal(SIGPIPE, SIG_IGN); /* dont crash if sound process dies */ } #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) */ #endif /* AUDIO_UNIX_NATIVE */ return(0); } void em_open_all() { /* pre-calculate some data */ tab_generate(); #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) ulaw_generate(); #endif progname = "emerald mine"; if (open_all() != 0) Error(ERR_EXIT, "em_open_all(): open_all() failed"); /* after "open_all()", because we need the graphic bitmaps to be defined */ tab_generate_graphics_info_em(); game_init_vars(); } void em_close_all(void) { #if defined(AUDIO_UNIX_NATIVE) int i; if (sound_pid != -1) { kill(sound_pid, SIGTERM); waitpid(sound_pid, 0, 0); } if (sound_pipe[0] != -1) close(sound_pipe[0]); if (sound_pipe[1] != -1) close(sound_pipe[1]); for (i = 0; i < SAMPLE_MAX; i++) if (sound_data[i]) free(sound_data[i]); #endif #if 0 if (spriteGC) XFreeGC(display, spriteGC); if (spriteBitmap) XFreePixmap(display, spriteBitmap); #endif } /* ---------------------------------------------------------------------- */ extern int screen_x; extern int screen_y; void play_element_sound(int x, int y, int sample, int element) { #if 0 int left = screen_x / TILEX; int top = screen_y / TILEY; if ((x == -1 && y == -1) || /* play sound in the middle of the screen */ ((int)(y - top) <= SCR_FIELDY && (int)(x - left) <= SCR_FIELDX)) #endif { #if 1 PlayLevelSound_EM(x, y, element, sample); #else play[sample] = 1; play_x[sample] = x; play_y[sample] = y; play_element[sample] = element; #endif } } void play_sound(int x, int y, int sample) { play_element_sound(x, y, sample, -1); } void sound_play(void) { if (!use_native_em_sound) { int i; #if 0 UpdateEngineValues(screen_x / TILEX, screen_y / TILEY); #endif return; for (i = 0; i < SAMPLE_MAX; i++) if (play[i]) PlayLevelSound_EM(play_x[i], play_y[i], play_element[i], i); } #if defined(AUDIO_UNIX_NATIVE) if (use_native_em_sound && sound_pipe[1] != -1) { if (write(sound_pipe[1], &play, sizeof(play)) == -1) { Error(ERR_WARN, "cannot write into pipe to child process -- no sounds"); if (sound_pipe[0] != -1) { close(sound_pipe[0]); sound_pipe[0] = -1; } if (sound_pipe[1] != -1) { close(sound_pipe[1]); sound_pipe[1] = -1; } } } #endif clear_mem(play, sizeof(play)); } unsigned int InitEngineRandom_EM(long seed) { if (seed == NEW_RANDOMIZE) { int simple_rnd = GetSimpleRandom(1000); int i; for (i = 0; i < simple_rnd || RandomEM == NEW_RANDOMIZE; i++) RandomEM = RandomEM * 129 + 1; seed = RandomEM; } RandomEM = seed; return (unsigned int) seed; } rocksndiamonds-3.3.0.1+dfsg1/src/files.h0000644000175000017500000000445611345416261016704 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * files.h * ***********************************************************/ #ifndef FILES_H #define FILES_H #include "main.h" #define LEVEL_PACKED_START 100 #define PACKED_LEVELS(x) (LEVEL_PACKED_START + x) #define LEVEL_FILE_TYPE_RND_PACKED PACKED_LEVELS(LEVEL_FILE_TYPE_RND) #define LEVEL_FILE_TYPE_EM_PACKED PACKED_LEVELS(LEVEL_FILE_TYPE_EM) #define IS_SINGLE_LEVEL_FILE(x) (x < LEVEL_PACKED_START) #define IS_PACKED_LEVEL_FILE(x) (x > LEVEL_PACKED_START) void setElementChangePages(struct ElementInfo *, int); void setElementChangeInfoToDefaults(struct ElementChangeInfo *); void copyElementInfo(struct ElementInfo *, struct ElementInfo *); char *getDefaultLevelFilename(int); void LoadLevelFromFilename(struct LevelInfo *, char *); void LoadLevel(int); void LoadLevelTemplate(int); void SaveLevel(int); void SaveLevelTemplate(); void SaveNativeLevel(struct LevelInfo *); void DumpLevel(struct LevelInfo *); boolean SaveLevelChecked(int); void CopyNativeLevel_RND_to_Native(struct LevelInfo *); void CopyNativeLevel_Native_to_RND(struct LevelInfo *); void LoadTapeFromFilename(char *); void LoadTape(int); void LoadSolutionTape(int); void SaveTape(int); void DumpTape(struct TapeInfo *); boolean SaveTapeChecked(int); void LoadScore(int); void SaveScore(int); void LoadSetup(); void SaveSetup(); void LoadSetup_EditorCascade(); void SaveSetup_EditorCascade(); void LoadCustomElementDescriptions(); void InitMenuDesignSettings_Static(); void LoadMenuDesignSettings(); void LoadUserDefinedEditorElementList(int **, int *); void LoadMusicInfo(); void LoadHelpAnimInfo(); void LoadHelpTextInfo(); void ConvertLevels(); void CreateLevelSketchImages(); #endif /* FILES_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_gfx.c0000644000175000017500000103733111375255464017376 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_gfx.c * ***********************************************************/ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is GFX_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo image_config_suffix[] = { { ".x", ARG_UNDEFINED, TYPE_INTEGER }, { ".y", ARG_UNDEFINED, TYPE_INTEGER }, { ".xpos", ARG_UNDEFINED, TYPE_INTEGER }, { ".ypos", ARG_UNDEFINED, TYPE_INTEGER }, { ".width", ARG_UNDEFINED, TYPE_INTEGER }, { ".height", ARG_UNDEFINED, TYPE_INTEGER }, { ".vertical", "false", TYPE_BOOLEAN }, { ".offset", ARG_UNDEFINED, TYPE_INTEGER }, { ".xoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".yoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_movement_tile", "false", TYPE_BOOLEAN }, { ".2nd_vertical", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".2nd_offset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_xoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_yoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_swap_tiles", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".frames", ARG_UNDEFINED, TYPE_INTEGER }, { ".frames_per_line", ARG_UNDEFINED, TYPE_INTEGER }, { ".start_frame", ARG_UNDEFINED, TYPE_INTEGER }, { ".delay", "1", TYPE_INTEGER }, { ".anim_mode", ARG_UNDEFINED, TYPE_STRING }, { ".global_sync", "false", TYPE_BOOLEAN }, { ".crumbled_like", ARG_UNDEFINED, TYPE_ELEMENT }, { ".diggable_like", ARG_UNDEFINED, TYPE_ELEMENT }, { ".border_size", ARG_UNDEFINED, TYPE_INTEGER }, { ".step_offset", "4", TYPE_INTEGER }, { ".step_delay", "1", TYPE_INTEGER }, { ".direction", ARG_UNDEFINED, TYPE_STRING }, { ".position", ARG_UNDEFINED, TYPE_STRING }, { ".draw_xoffset", "0", TYPE_INTEGER }, { ".draw_yoffset", "0", TYPE_INTEGER }, { ".draw_masked", "false", TYPE_BOOLEAN }, { ".anim_delay_fixed", ARG_UNDEFINED, TYPE_INTEGER }, { ".anim_delay_random", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay_fixed", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay_random", ARG_UNDEFINED, TYPE_INTEGER }, { ".name", ARG_UNDEFINED, TYPE_STRING }, { ".scale_up_factor", ARG_UNDEFINED, TYPE_INTEGER }, { ".clone_from", ARG_UNDEFINED, TYPE_GRAPHIC }, { ".fade_mode", ARG_UNDEFINED, TYPE_INTEGER }, { ".fade_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".auto_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".align", ARG_UNDEFINED, TYPE_INTEGER }, { ".valign", ARG_UNDEFINED, TYPE_INTEGER }, { ".sort_priority", ARG_UNDEFINED, TYPE_INTEGER }, { ".class", ARG_UNDEFINED, TYPE_STRING }, { ".style", ARG_UNDEFINED, TYPE_STRING }, { NULL, NULL, 0 } }; struct ConfigInfo image_config[] = { /* images for Boulder Dash style elements and actions */ { "bd_wall", "RocksDC.pcx" }, { "bd_wall.xpos", "12" }, { "bd_wall.ypos", "9" }, { "bd_wall.frames", "1" }, { "bd_wall.EDITOR", "RocksDC.pcx" }, { "bd_wall.EDITOR.xpos", "14" }, { "bd_wall.EDITOR.ypos", "13" }, { "bd_rock", "RocksDC.pcx" }, { "bd_rock.xpos", "12" }, { "bd_rock.ypos", "10" }, { "bd_rock.frames", "1" }, { "bd_rock.EDITOR", "RocksDC.pcx" }, { "bd_rock.EDITOR.xpos", "14" }, { "bd_rock.EDITOR.ypos", "14" }, { "bd_rock.moving.left", "RocksDC.pcx" }, { "bd_rock.moving.left.xpos", "12" }, { "bd_rock.moving.left.ypos", "10" }, { "bd_rock.moving.left.frames", "4" }, { "bd_rock.moving.left.delay", "2" }, { "bd_rock.moving.left.anim_mode", "reverse" }, { "bd_rock.moving.right", "RocksDC.pcx" }, { "bd_rock.moving.right.xpos", "12" }, { "bd_rock.moving.right.ypos", "10" }, { "bd_rock.moving.right.frames", "4" }, { "bd_rock.moving.right.start_frame", "1" }, { "bd_rock.moving.right.delay", "2" }, { "bd_rock.pushing.left", "RocksDC.pcx" }, { "bd_rock.pushing.left.xpos", "12" }, { "bd_rock.pushing.left.ypos", "10" }, { "bd_rock.pushing.left.frames", "4" }, { "bd_rock.pushing.left.delay", "2" }, { "bd_rock.pushing.left.anim_mode", "reverse" }, { "bd_rock.pushing.right", "RocksDC.pcx" }, { "bd_rock.pushing.right.xpos", "12" }, { "bd_rock.pushing.right.ypos", "10" }, { "bd_rock.pushing.right.frames", "4" }, { "bd_rock.pushing.right.start_frame", "1" }, { "bd_rock.pushing.right.delay", "2" }, { "bd_diamond", "RocksElements.pcx" }, { "bd_diamond.xpos", "0" }, { "bd_diamond.ypos", "10" }, { "bd_diamond.frames", "4" }, { "bd_diamond.delay", "4" }, { "bd_diamond.anim_mode", "reverse" }, { "bd_diamond.moving", "RocksElements.pcx" }, { "bd_diamond.moving.xpos", "3" }, { "bd_diamond.moving.ypos", "10" }, { "bd_diamond.moving.frames", "2" }, { "bd_diamond.moving.delay", "4" }, { "bd_diamond.falling", "RocksElements.pcx" }, { "bd_diamond.falling.xpos", "3" }, { "bd_diamond.falling.ypos", "10" }, { "bd_diamond.falling.frames", "2" }, { "bd_diamond.falling.delay", "4" }, { "bd_magic_wall", "RocksElements.pcx" }, { "bd_magic_wall.xpos", "12" }, { "bd_magic_wall.ypos", "10" }, { "bd_magic_wall.frames", "1" }, { "bd_magic_wall.active", "RocksElements.pcx" }, { "bd_magic_wall.active.xpos", "12" }, { "bd_magic_wall.active.ypos", "10" }, { "bd_magic_wall.active.frames", "4" }, { "bd_magic_wall.active.anim_mode", "reverse" }, { "bd_magic_wall.active.delay", "4" }, { "bd_magic_wall.active.global_sync", "true" }, { "bd_magic_wall.filling", "RocksElements.pcx" }, { "bd_magic_wall.filling.xpos", "12" }, { "bd_magic_wall.filling.ypos", "10" }, { "bd_magic_wall.filling.frames", "4" }, { "bd_magic_wall.filling.anim_mode", "reverse" }, { "bd_magic_wall.filling.delay", "4" }, { "bd_magic_wall.filling.global_sync", "true" }, { "bd_magic_wall_full", "RocksElements.pcx" }, { "bd_magic_wall_full.xpos", "12" }, { "bd_magic_wall_full.ypos", "10" }, { "bd_magic_wall_full.frames", "4" }, { "bd_magic_wall_full.anim_mode", "reverse" }, { "bd_magic_wall_full.delay", "4" }, { "bd_magic_wall_full.global_sync", "true" }, { "bd_magic_wall.emptying", "RocksElements.pcx" }, { "bd_magic_wall.emptying.xpos", "12" }, { "bd_magic_wall.emptying.ypos", "10" }, { "bd_magic_wall.emptying.frames", "4" }, { "bd_magic_wall.emptying.anim_mode", "reverse" }, { "bd_magic_wall.emptying.delay", "4" }, { "bd_magic_wall.emptying.global_sync", "true" }, { "bd_magic_wall_dead", "RocksElements.pcx" }, { "bd_magic_wall_dead.xpos", "12" }, { "bd_magic_wall_dead.ypos", "10" }, { "bd_magic_wall_dead.frames", "1" }, { "bd_amoeba", "RocksElements.pcx" }, { "bd_amoeba.xpos", "8" }, { "bd_amoeba.ypos", "6" }, { "bd_amoeba.frames", "4" }, { "bd_amoeba.delay", "1000000" }, { "bd_amoeba.anim_mode", "random" }, { "bd_amoeba.EDITOR", "RocksElements.pcx" }, { "bd_amoeba.EDITOR.xpos", "8" }, { "bd_amoeba.EDITOR.ypos", "7" }, { "bd_butterfly", "RocksElements.pcx" }, { "bd_butterfly.xpos", "4" }, { "bd_butterfly.ypos", "12" }, { "bd_butterfly.frames", "2" }, { "bd_butterfly.anim_mode", "pingpong" }, { "bd_butterfly.delay", "4" }, { "bd_butterfly.global_sync", "true" }, { "bd_butterfly.right", "RocksElements.pcx" }, { "bd_butterfly.right.xpos", "4" }, { "bd_butterfly.right.ypos", "12" }, { "bd_butterfly.right.frames", "2" }, { "bd_butterfly.right.anim_mode", "pingpong" }, { "bd_butterfly.right.delay", "4" }, { "bd_butterfly.right.global_sync", "true" }, { "bd_butterfly.right.EDITOR", "RocksElements.pcx" }, { "bd_butterfly.right.EDITOR.xpos", "8" }, { "bd_butterfly.right.EDITOR.ypos", "12" }, { "bd_butterfly.up", "RocksElements.pcx" }, { "bd_butterfly.up.xpos", "4" }, { "bd_butterfly.up.ypos", "12" }, { "bd_butterfly.up.frames", "2" }, { "bd_butterfly.up.anim_mode", "pingpong" }, { "bd_butterfly.up.delay", "4" }, { "bd_butterfly.up.global_sync", "true" }, { "bd_butterfly.up.EDITOR", "RocksElements.pcx" }, { "bd_butterfly.up.EDITOR.xpos", "9" }, { "bd_butterfly.up.EDITOR.ypos", "12" }, { "bd_butterfly.left", "RocksElements.pcx" }, { "bd_butterfly.left.xpos", "4" }, { "bd_butterfly.left.ypos", "12" }, { "bd_butterfly.left.frames", "2" }, { "bd_butterfly.left.anim_mode", "pingpong" }, { "bd_butterfly.left.delay", "4" }, { "bd_butterfly.left.global_sync", "true" }, { "bd_butterfly.left.EDITOR", "RocksElements.pcx" }, { "bd_butterfly.left.EDITOR.xpos", "10" }, { "bd_butterfly.left.EDITOR.ypos", "12" }, { "bd_butterfly.down", "RocksElements.pcx" }, { "bd_butterfly.down.xpos", "4" }, { "bd_butterfly.down.ypos", "12" }, { "bd_butterfly.down.frames", "2" }, { "bd_butterfly.down.anim_mode", "pingpong" }, { "bd_butterfly.down.delay", "4" }, { "bd_butterfly.down.global_sync", "true" }, { "bd_butterfly.down.EDITOR", "RocksElements.pcx" }, { "bd_butterfly.down.EDITOR.xpos", "11" }, { "bd_butterfly.down.EDITOR.ypos", "12" }, { "bd_firefly", "RocksElements.pcx" }, { "bd_firefly.xpos", "6" }, { "bd_firefly.ypos", "12" }, { "bd_firefly.frames", "2" }, { "bd_firefly.anim_mode", "pingpong" }, { "bd_firefly.delay", "4" }, { "bd_firefly.global_sync", "true" }, { "bd_firefly.right", "RocksElements.pcx" }, { "bd_firefly.right.xpos", "6" }, { "bd_firefly.right.ypos", "12" }, { "bd_firefly.right.frames", "2" }, { "bd_firefly.right.anim_mode", "pingpong" }, { "bd_firefly.right.delay", "4" }, { "bd_firefly.right.global_sync", "true" }, { "bd_firefly.right.EDITOR", "RocksElements.pcx" }, { "bd_firefly.right.EDITOR.xpos", "12" }, { "bd_firefly.right.EDITOR.ypos", "12" }, { "bd_firefly.up", "RocksElements.pcx" }, { "bd_firefly.up.xpos", "6" }, { "bd_firefly.up.ypos", "12" }, { "bd_firefly.up.frames", "2" }, { "bd_firefly.up.anim_mode", "pingpong" }, { "bd_firefly.up.delay", "4" }, { "bd_firefly.up.global_sync", "true" }, { "bd_firefly.up.EDITOR", "RocksElements.pcx" }, { "bd_firefly.up.EDITOR.xpos", "13" }, { "bd_firefly.up.EDITOR.ypos", "12" }, { "bd_firefly.left", "RocksElements.pcx" }, { "bd_firefly.left.xpos", "6" }, { "bd_firefly.left.ypos", "12" }, { "bd_firefly.left.frames", "2" }, { "bd_firefly.left.anim_mode", "pingpong" }, { "bd_firefly.left.delay", "4" }, { "bd_firefly.left.global_sync", "true" }, { "bd_firefly.left.EDITOR", "RocksElements.pcx" }, { "bd_firefly.left.EDITOR.xpos", "14" }, { "bd_firefly.left.EDITOR.ypos", "12" }, { "bd_firefly.down", "RocksElements.pcx" }, { "bd_firefly.down.xpos", "6" }, { "bd_firefly.down.ypos", "12" }, { "bd_firefly.down.frames", "2" }, { "bd_firefly.down.anim_mode", "pingpong" }, { "bd_firefly.down.delay", "4" }, { "bd_firefly.down.global_sync", "true" }, { "bd_firefly.down.EDITOR", "RocksElements.pcx" }, { "bd_firefly.down.EDITOR.xpos", "15" }, { "bd_firefly.down.EDITOR.ypos", "12" }, /* images for Supaplex style elements and actions */ { "[sp_default].exploding", "RocksSP.pcx" }, { "[sp_default].exploding.xpos", "8" }, { "[sp_default].exploding.ypos", "3" }, { "[sp_default].exploding.frames", "8" }, { "[sp_default].exploding.delay", "4" }, { "[sp_default].exploding.anim_mode", "linear" }, { "sp_zonk", "RocksSP.pcx" }, { "sp_zonk.xpos", "1" }, { "sp_zonk.ypos", "0" }, { "sp_zonk.frames", "1" }, { "sp_zonk.moving.left", "RocksSP.pcx" }, { "sp_zonk.moving.left.xpos", "0" }, { "sp_zonk.moving.left.ypos", "6" }, { "sp_zonk.moving.left.frames", "4" }, { "sp_zonk.moving.left.delay", "1" }, { "sp_zonk.moving.left.anim_mode", "reverse" }, { "sp_zonk.moving.right", "RocksSP.pcx" }, { "sp_zonk.moving.right.xpos", "0" }, { "sp_zonk.moving.right.ypos", "6" }, { "sp_zonk.moving.right.frames", "4" }, { "sp_zonk.moving.right.start_frame", "1" }, { "sp_zonk.moving.right.delay", "1" }, { "sp_zonk.pushing.left", "RocksSP.pcx" }, { "sp_zonk.pushing.left.xpos", "0" }, { "sp_zonk.pushing.left.ypos", "6" }, { "sp_zonk.pushing.left.frames", "4" }, { "sp_zonk.pushing.left.delay", "1" }, { "sp_zonk.pushing.left.anim_mode", "reverse" }, { "sp_zonk.pushing.right", "RocksSP.pcx" }, { "sp_zonk.pushing.right.xpos", "0" }, { "sp_zonk.pushing.right.ypos", "6" }, { "sp_zonk.pushing.right.frames", "4" }, { "sp_zonk.pushing.right.start_frame", "1" }, { "sp_zonk.pushing.right.delay", "1" }, { "sp_base", "RocksSP.pcx" }, { "sp_base.xpos", "2" }, { "sp_base.ypos", "0" }, { "sp_base.frames", "1" }, { "sp_base.digging", "RocksSP.pcx" }, { "sp_base.digging.xpos", "2" }, { "sp_base.digging.ypos", "0" }, { "sp_base.digging.frames", "1" }, { "sp_base.digging.anim_mode", "opaque_player" }, { "sp_base.snapping", "RocksSP.pcx" }, { "sp_base.snapping.xpos", "8" }, { "sp_base.snapping.ypos", "2" }, { "sp_base.snapping.frames", "7" }, { "sp_base.snapping.anim_mode", "linear" }, { "sp_murphy", "RocksSP.pcx" }, { "sp_murphy.xpos", "3" }, { "sp_murphy.ypos", "0" }, { "sp_murphy.frames", "1" }, { "sp_murphy.moving.left", "RocksSP.pcx" }, { "sp_murphy.moving.left.xpos", "8" }, { "sp_murphy.moving.left.ypos", "0" }, { "sp_murphy.moving.left.frames", "3" }, { "sp_murphy.moving.left.anim_mode", "pingpong" }, { "sp_murphy.moving.left.delay", "2" }, { "sp_murphy.moving.left.start_frame", "1" }, { "sp_murphy.moving.right", "RocksSP.pcx" }, { "sp_murphy.moving.right.xpos", "11" }, { "sp_murphy.moving.right.ypos", "0" }, { "sp_murphy.moving.right.frames", "3" }, { "sp_murphy.moving.right.anim_mode", "pingpong" }, { "sp_murphy.moving.right.delay", "2" }, { "sp_murphy.moving.right.start_frame", "1" }, { "sp_murphy.digging.left", "RocksSP.pcx" }, { "sp_murphy.digging.left.xpos", "8" }, { "sp_murphy.digging.left.ypos", "0" }, { "sp_murphy.digging.left.frames", "3" }, { "sp_murphy.digging.left.anim_mode", "pingpong" }, { "sp_murphy.digging.left.delay", "2" }, { "sp_murphy.digging.left.start_frame", "1" }, { "sp_murphy.digging.right", "RocksSP.pcx" }, { "sp_murphy.digging.right.xpos", "11" }, { "sp_murphy.digging.right.ypos", "0" }, { "sp_murphy.digging.right.frames", "3" }, { "sp_murphy.digging.right.anim_mode", "pingpong" }, { "sp_murphy.digging.right.delay", "2" }, { "sp_murphy.digging.right.start_frame", "1" }, { "sp_murphy.collecting.left", "RocksSP.pcx" }, { "sp_murphy.collecting.left.xpos", "8" }, { "sp_murphy.collecting.left.ypos", "0" }, { "sp_murphy.collecting.left.frames", "3" }, { "sp_murphy.collecting.left.anim_mode", "pingpong" }, { "sp_murphy.collecting.left.delay", "2" }, { "sp_murphy.collecting.left.start_frame", "1" }, { "sp_murphy.collecting.right", "RocksSP.pcx" }, { "sp_murphy.collecting.right.xpos", "11" }, { "sp_murphy.collecting.right.ypos", "0" }, { "sp_murphy.collecting.right.frames", "3" }, { "sp_murphy.collecting.right.anim_mode", "pingpong" }, { "sp_murphy.collecting.right.delay", "2" }, { "sp_murphy.collecting.right.start_frame", "1" }, { "sp_murphy.pushing.left", "RocksSP.pcx" }, { "sp_murphy.pushing.left.xpos", "11" }, { "sp_murphy.pushing.left.ypos", "1" }, { "sp_murphy.pushing.left.frames", "1" }, { "sp_murphy.pushing.right", "RocksSP.pcx" }, { "sp_murphy.pushing.right.xpos", "10" }, { "sp_murphy.pushing.right.ypos", "1" }, { "sp_murphy.pushing.right.frames", "1" }, { "sp_murphy.snapping.left", "RocksSP.pcx" }, { "sp_murphy.snapping.left.xpos", "9" }, { "sp_murphy.snapping.left.ypos", "1" }, { "sp_murphy.snapping.left.frames", "1" }, { "sp_murphy.snapping.right", "RocksSP.pcx" }, { "sp_murphy.snapping.right.xpos", "8" }, { "sp_murphy.snapping.right.ypos", "1" }, { "sp_murphy.snapping.right.frames", "1" }, { "sp_murphy.snapping.up", "RocksSP.pcx" }, { "sp_murphy.snapping.up.xpos", "14" }, { "sp_murphy.snapping.up.ypos", "0" }, { "sp_murphy.snapping.up.frames", "1" }, { "sp_murphy.snapping.down", "RocksSP.pcx" }, { "sp_murphy.snapping.down.xpos", "15" }, { "sp_murphy.snapping.down.ypos", "0" }, { "sp_murphy.snapping.down.frames", "1" }, { "sp_murphy.boring", "RocksSP.pcx" }, { "sp_murphy.boring.xpos", "11" }, { "sp_murphy.boring.ypos", "12" }, { "sp_murphy.boring.frames", "1" }, { "sp_murphy.boring[1]", "RocksSP.pcx" }, { "sp_murphy.boring[1].xpos", "0" }, { "sp_murphy.boring[1].ypos", "12" }, { "sp_murphy.boring[1].frames", "12" }, { "sp_murphy.boring[1].delay", "10" }, { "sp_murphy.boring[1].anim_mode", "linear" }, { "sp_murphy.boring[1].anim_delay_fixed", "120" }, { "sp_murphy.boring[1].anim_delay_random", "0" }, { "sp_murphy.boring[1].post_delay_fixed", "500" }, { "sp_murphy.boring[1].post_delay_random", "500" }, { "sp_murphy.sleeping.left", "RocksSP.pcx" }, { "sp_murphy.sleeping.left.xpos", "4" }, { "sp_murphy.sleeping.left.ypos", "9" }, { "sp_murphy.sleeping.left.frames", "3" }, { "sp_murphy.sleeping.left.delay", "100" }, { "sp_murphy.sleeping.left.anim_mode", "linear,reverse" }, { "sp_murphy.sleeping.right", "RocksSP.pcx" }, { "sp_murphy.sleeping.right.xpos", "13" }, { "sp_murphy.sleeping.right.ypos", "12" }, { "sp_murphy.sleeping.right.frames", "3" }, { "sp_murphy.sleeping.right.delay", "100" }, { "sp_murphy.sleeping.right.anim_mode", "linear" }, { "sp_murphy.dropping", "RocksSP.pcx" }, { "sp_murphy.dropping.xpos", "11" }, { "sp_murphy.dropping.ypos", "12" }, { "sp_murphy.dropping.frames", "1" }, { "sp_murphy.shrinking", "RocksSP.pcx" }, { "sp_murphy.shrinking.xpos", "8" }, { "sp_murphy.shrinking.ypos", "14" }, { "sp_murphy.shrinking.frames", "8" }, { "sp_murphy.shrinking.delay", "4" }, { "sp_murphy.shrinking.anim_mode", "linear" }, { "sp_murphy_clone", "RocksSP.pcx" }, { "sp_murphy_clone.xpos", "3" }, { "sp_murphy_clone.ypos", "0" }, { "sp_murphy_clone.frames", "1" }, { "sp_infotron", "RocksSP.pcx" }, { "sp_infotron.xpos", "4" }, { "sp_infotron.ypos", "0" }, { "sp_infotron.frames", "1" }, { "sp_infotron.EDITOR", "RocksSP.pcx" }, { "sp_infotron.EDITOR.xpos", "8" }, { "sp_infotron.EDITOR.ypos", "11" }, { "sp_infotron.moving.left", "RocksSP.pcx" }, { "sp_infotron.moving.left.xpos", "8" }, { "sp_infotron.moving.left.ypos", "13" }, { "sp_infotron.moving.left.frames", "8" }, { "sp_infotron.moving.right", "RocksSP.pcx" }, { "sp_infotron.moving.right.xpos", "8" }, { "sp_infotron.moving.right.ypos", "13" }, { "sp_infotron.moving.right.frames", "8" }, { "sp_infotron.moving.right.start_frame", "6" }, { "sp_infotron.moving.right.anim_mode", "reverse" }, { "sp_infotron.collecting", "RocksSP.pcx" }, { "sp_infotron.collecting.xpos", "8" }, { "sp_infotron.collecting.ypos", "7" }, { "sp_infotron.collecting.frames", "8" }, { "sp_infotron.collecting.anim_mode", "linear" }, { "sp_chip_single", "RocksSP.pcx" }, { "sp_chip_single.xpos", "5" }, { "sp_chip_single.ypos", "0" }, { "sp_chip_single.frames", "1" }, { "sp_chip_left", "RocksSP.pcx" }, { "sp_chip_left.xpos", "2" }, { "sp_chip_left.ypos", "3" }, { "sp_chip_left.frames", "1" }, { "sp_chip_right", "RocksSP.pcx" }, { "sp_chip_right.xpos", "3" }, { "sp_chip_right.ypos", "3" }, { "sp_chip_right.frames", "1" }, { "sp_chip_top", "RocksSP.pcx" }, { "sp_chip_top.xpos", "6" }, { "sp_chip_top.ypos", "4" }, { "sp_chip_top.frames", "1" }, { "sp_chip_bottom", "RocksSP.pcx" }, { "sp_chip_bottom.xpos", "7" }, { "sp_chip_bottom.ypos", "4" }, { "sp_chip_bottom.frames", "1" }, { "sp_hardware_gray", "RocksSP.pcx" }, { "sp_hardware_gray.xpos", "6" }, { "sp_hardware_gray.ypos", "0" }, { "sp_hardware_gray.frames", "1" }, { "sp_hardware_green", "RocksSP.pcx" }, { "sp_hardware_green.xpos", "5" }, { "sp_hardware_green.ypos", "3" }, { "sp_hardware_green.frames", "1" }, { "sp_hardware_blue", "RocksSP.pcx" }, { "sp_hardware_blue.xpos", "6" }, { "sp_hardware_blue.ypos", "3" }, { "sp_hardware_blue.frames", "1" }, { "sp_hardware_red", "RocksSP.pcx" }, { "sp_hardware_red.xpos", "7" }, { "sp_hardware_red.ypos", "3" }, { "sp_hardware_red.frames", "1" }, { "sp_hardware_yellow", "RocksSP.pcx" }, { "sp_hardware_yellow.xpos", "0" }, { "sp_hardware_yellow.ypos", "4" }, { "sp_hardware_yellow.frames", "1" }, { "sp_exit_closed", "RocksSP.pcx" }, { "sp_exit_closed.xpos", "7" }, { "sp_exit_closed.ypos", "0" }, { "sp_exit_closed.frames", "1" }, { "sp_exit.opening", "RocksSP.pcx" }, { "sp_exit.opening.xpos", "7" }, { "sp_exit.opening.ypos", "0" }, { "sp_exit.opening.frames", "1" }, { "sp_exit_open", "RocksSP.pcx" }, { "sp_exit_open.xpos", "7" }, { "sp_exit_open.ypos", "0" }, { "sp_exit_open.frames", "1" }, { "sp_exit.closing", "RocksSP.pcx" }, { "sp_exit.closing.xpos", "7" }, { "sp_exit.closing.ypos", "0" }, { "sp_exit.closing.frames", "1" }, { "sp_disk_orange", "RocksSP.pcx" }, { "sp_disk_orange.xpos", "0" }, { "sp_disk_orange.ypos", "1" }, { "sp_disk_orange.frames", "1" }, { "sp_disk_yellow", "RocksSP.pcx" }, { "sp_disk_yellow.xpos", "2" }, { "sp_disk_yellow.ypos", "2" }, { "sp_disk_yellow.frames", "1" }, { "sp_disk_red", "RocksSP.pcx" }, { "sp_disk_red.xpos", "4" }, { "sp_disk_red.ypos", "2" }, { "sp_disk_red.frames", "1" }, { "sp_disk_red.collecting", "RocksSP.pcx" }, { "sp_disk_red.collecting.xpos", "9" }, { "sp_disk_red.collecting.ypos", "5" }, { "sp_disk_red.collecting.frames", "7" }, { "sp_disk_red.collecting.anim_mode", "linear" }, { "sp_disk_red.active", "RocksSP.pcx" }, { "sp_disk_red.active.xpos", "4" }, { "sp_disk_red.active.ypos", "2" }, { "sp_disk_red.active.frames", "1" }, { "sp_port_right", "RocksSP.pcx" }, { "sp_port_right.xpos", "1" }, { "sp_port_right.ypos", "1" }, { "sp_port_right.frames", "1" }, { "sp_port_down", "RocksSP.pcx" }, { "sp_port_down.xpos", "2" }, { "sp_port_down.ypos", "1" }, { "sp_port_down.frames", "1" }, { "sp_port_left", "RocksSP.pcx" }, { "sp_port_left.xpos", "3" }, { "sp_port_left.ypos", "1" }, { "sp_port_left.frames", "1" }, { "sp_port_up", "RocksSP.pcx" }, { "sp_port_up.xpos", "4" }, { "sp_port_up.ypos", "1" }, { "sp_port_up.frames", "1" }, { "sp_port_horizontal", "RocksSP.pcx" }, { "sp_port_horizontal.xpos", "6" }, { "sp_port_horizontal.ypos", "2" }, { "sp_port_horizontal.frames", "1" }, { "sp_port_vertical", "RocksSP.pcx" }, { "sp_port_vertical.xpos", "5" }, { "sp_port_vertical.ypos", "2" }, { "sp_port_vertical.frames", "1" }, { "sp_port_any", "RocksSP.pcx" }, { "sp_port_any.xpos", "7" }, { "sp_port_any.ypos", "2" }, { "sp_port_any.frames", "1" }, { "sp_gravity_port_right", "RocksSP.pcx" }, { "sp_gravity_port_right.xpos", "1" }, { "sp_gravity_port_right.ypos", "1" }, { "sp_gravity_port_right.frames", "1" }, { "sp_gravity_port_right.EDITOR", "RocksSP.pcx" }, { "sp_gravity_port_right.EDITOR.xpos", "0" }, { "sp_gravity_port_right.EDITOR.ypos", "14" }, { "sp_gravity_port_down", "RocksSP.pcx" }, { "sp_gravity_port_down.xpos", "2" }, { "sp_gravity_port_down.ypos", "1" }, { "sp_gravity_port_down.frames", "1" }, { "sp_gravity_port_down.EDITOR", "RocksSP.pcx" }, { "sp_gravity_port_down.EDITOR.xpos", "1" }, { "sp_gravity_port_down.EDITOR.ypos", "14" }, { "sp_gravity_port_left", "RocksSP.pcx" }, { "sp_gravity_port_left.xpos", "3" }, { "sp_gravity_port_left.ypos", "1" }, { "sp_gravity_port_left.frames", "1" }, { "sp_gravity_port_left.EDITOR", "RocksSP.pcx" }, { "sp_gravity_port_left.EDITOR.xpos", "2" }, { "sp_gravity_port_left.EDITOR.ypos", "14" }, { "sp_gravity_port_up", "RocksSP.pcx" }, { "sp_gravity_port_up.xpos", "4" }, { "sp_gravity_port_up.ypos", "1" }, { "sp_gravity_port_up.frames", "1" }, { "sp_gravity_port_up.EDITOR", "RocksSP.pcx" }, { "sp_gravity_port_up.EDITOR.xpos", "3" }, { "sp_gravity_port_up.EDITOR.ypos", "14" }, { "sp_gravity_on_port_right", "RocksSP.pcx" }, { "sp_gravity_on_port_right.xpos", "1" }, { "sp_gravity_on_port_right.ypos", "1" }, { "sp_gravity_on_port_right.frames", "1" }, { "sp_gravity_on_port_right.EDITOR", "RocksSP.pcx" }, { "sp_gravity_on_port_right.EDITOR.xpos", "0" }, { "sp_gravity_on_port_right.EDITOR.ypos", "13" }, { "sp_gravity_on_port_down", "RocksSP.pcx" }, { "sp_gravity_on_port_down.xpos", "2" }, { "sp_gravity_on_port_down.ypos", "1" }, { "sp_gravity_on_port_down.frames", "1" }, { "sp_gravity_on_port_down.EDITOR", "RocksSP.pcx" }, { "sp_gravity_on_port_down.EDITOR.xpos", "1" }, { "sp_gravity_on_port_down.EDITOR.ypos", "13" }, { "sp_gravity_on_port_left", "RocksSP.pcx" }, { "sp_gravity_on_port_left.xpos", "3" }, { "sp_gravity_on_port_left.ypos", "1" }, { "sp_gravity_on_port_left.frames", "1" }, { "sp_gravity_on_port_left.EDITOR", "RocksSP.pcx" }, { "sp_gravity_on_port_left.EDITOR.xpos", "2" }, { "sp_gravity_on_port_left.EDITOR.ypos", "13" }, { "sp_gravity_on_port_up", "RocksSP.pcx" }, { "sp_gravity_on_port_up.xpos", "4" }, { "sp_gravity_on_port_up.ypos", "1" }, { "sp_gravity_on_port_up.frames", "1" }, { "sp_gravity_on_port_up.EDITOR", "RocksSP.pcx" }, { "sp_gravity_on_port_up.EDITOR.xpos", "3" }, { "sp_gravity_on_port_up.EDITOR.ypos", "13" }, { "sp_gravity_off_port_right", "RocksSP.pcx" }, { "sp_gravity_off_port_right.xpos", "1" }, { "sp_gravity_off_port_right.ypos", "1" }, { "sp_gravity_off_port_right.frames", "1" }, { "sp_gravity_off_port_right.EDITOR", "RocksSP.pcx" }, { "sp_gravity_off_port_right.EDITOR.xpos", "4" }, { "sp_gravity_off_port_right.EDITOR.ypos", "13" }, { "sp_gravity_off_port_down", "RocksSP.pcx" }, { "sp_gravity_off_port_down.xpos", "2" }, { "sp_gravity_off_port_down.ypos", "1" }, { "sp_gravity_off_port_down.frames", "1" }, { "sp_gravity_off_port_down.EDITOR", "RocksSP.pcx" }, { "sp_gravity_off_port_down.EDITOR.xpos", "5" }, { "sp_gravity_off_port_down.EDITOR.ypos", "13" }, { "sp_gravity_off_port_left", "RocksSP.pcx" }, { "sp_gravity_off_port_left.xpos", "3" }, { "sp_gravity_off_port_left.ypos", "1" }, { "sp_gravity_off_port_left.frames", "1" }, { "sp_gravity_off_port_left.EDITOR", "RocksSP.pcx" }, { "sp_gravity_off_port_left.EDITOR.xpos", "6" }, { "sp_gravity_off_port_left.EDITOR.ypos", "13" }, { "sp_gravity_off_port_up", "RocksSP.pcx" }, { "sp_gravity_off_port_up.xpos", "4" }, { "sp_gravity_off_port_up.ypos", "1" }, { "sp_gravity_off_port_up.frames", "1" }, { "sp_gravity_off_port_up.EDITOR", "RocksSP.pcx" }, { "sp_gravity_off_port_up.EDITOR.xpos", "7" }, { "sp_gravity_off_port_up.EDITOR.ypos", "13" }, { "sp_sniksnak", "RocksSP.pcx" }, { "sp_sniksnak.xpos", "1" }, { "sp_sniksnak.ypos", "2" }, { "sp_sniksnak.frames", "1" }, { "sp_sniksnak.left", "RocksSP.pcx" }, { "sp_sniksnak.left.xpos", "8" }, { "sp_sniksnak.left.ypos", "8" }, { "sp_sniksnak.left.frames", "4" }, { "sp_sniksnak.left.anim_mode", "pingpong2" }, { "sp_sniksnak.right", "RocksSP.pcx" }, { "sp_sniksnak.right.xpos", "12" }, { "sp_sniksnak.right.ypos", "8" }, { "sp_sniksnak.right.frames", "4" }, { "sp_sniksnak.right.anim_mode", "pingpong2" }, { "sp_sniksnak.up", "RocksSP.pcx" }, { "sp_sniksnak.up.xpos", "8" }, { "sp_sniksnak.up.ypos", "9" }, { "sp_sniksnak.up.frames", "4" }, { "sp_sniksnak.up.anim_mode", "pingpong2" }, { "sp_sniksnak.down", "RocksSP.pcx" }, { "sp_sniksnak.down.xpos", "12" }, { "sp_sniksnak.down.ypos", "9" }, { "sp_sniksnak.down.frames", "4" }, { "sp_sniksnak.down.anim_mode", "pingpong2" }, { "sp_sniksnak.turning_from_left.up", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_left.up.xpos", "12" }, { "sp_sniksnak.turning_from_left.up.ypos", "6" }, { "sp_sniksnak.turning_from_left.up.frames", "2" }, { "sp_sniksnak.turning_from_left.up.delay", "4" }, { "sp_sniksnak.turning_from_left.up.offset", "1408" }, { "sp_sniksnak.turning_from_left.up.anim_mode","linear" }, { "sp_sniksnak.turning_from_left.down", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_left.down.xpos", "13" }, { "sp_sniksnak.turning_from_left.down.ypos", "6" }, { "sp_sniksnak.turning_from_left.down.frames","2" }, { "sp_sniksnak.turning_from_left.down.delay", "4" }, { "sp_sniksnak.turning_from_left.down.offset","1504" }, { "sp_sniksnak.turning_from_left.down.anim_mode","linear" }, { "sp_sniksnak.turning_from_right.up", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_right.up.xpos", "15" }, { "sp_sniksnak.turning_from_right.up.ypos", "6" }, { "sp_sniksnak.turning_from_right.up.frames", "2" }, { "sp_sniksnak.turning_from_right.up.delay", "4" }, { "sp_sniksnak.turning_from_right.up.offset", "1312" }, { "sp_sniksnak.turning_from_right.up.anim_mode","linear" }, { "sp_sniksnak.turning_from_right.down", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_right.down.xpos", "14" }, { "sp_sniksnak.turning_from_right.down.ypos", "6" }, { "sp_sniksnak.turning_from_right.down.frames","2" }, { "sp_sniksnak.turning_from_right.down.delay","4" }, { "sp_sniksnak.turning_from_right.down.offset","1472" }, { "sp_sniksnak.turning_from_right.down.anim_mode","linear" }, { "sp_sniksnak.turning_from_up.left", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_up.left.xpos", "12" }, { "sp_sniksnak.turning_from_up.left.ypos", "6" }, { "sp_sniksnak.turning_from_up.left.frames", "2" }, { "sp_sniksnak.turning_from_up.left.delay", "4" }, { "sp_sniksnak.turning_from_up.left.offset", "896" }, { "sp_sniksnak.turning_from_up.left.anim_mode","linear" }, { "sp_sniksnak.turning_from_up.right", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_up.right.xpos", "15" }, { "sp_sniksnak.turning_from_up.right.ypos", "6" }, { "sp_sniksnak.turning_from_up.right.frames", "2" }, { "sp_sniksnak.turning_from_up.right.delay", "4" }, { "sp_sniksnak.turning_from_up.right.offset", "928" }, { "sp_sniksnak.turning_from_up.right.anim_mode","linear" }, { "sp_sniksnak.turning_from_down.left", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_down.left.xpos", "13" }, { "sp_sniksnak.turning_from_down.left.ypos", "6" }, { "sp_sniksnak.turning_from_down.left.frames","2" }, { "sp_sniksnak.turning_from_down.left.delay", "4" }, { "sp_sniksnak.turning_from_down.left.offset","864" }, { "sp_sniksnak.turning_from_down.left.anim_mode","linear" }, { "sp_sniksnak.turning_from_down.right", "RocksSP.pcx" }, { "sp_sniksnak.turning_from_down.right.xpos", "14" }, { "sp_sniksnak.turning_from_down.right.ypos", "6" }, { "sp_sniksnak.turning_from_down.right.frames","2" }, { "sp_sniksnak.turning_from_down.right.delay","4" }, { "sp_sniksnak.turning_from_down.right.offset","960" }, { "sp_sniksnak.turning_from_down.right.anim_mode","linear" }, { "sp_electron", "RocksSP.pcx" }, { "sp_electron.xpos", "8" }, { "sp_electron.ypos", "10" }, { "sp_electron.frames", "8" }, { "sp_electron.delay", "4" }, { "sp_electron.global_sync", "true" }, { "sp_electron.EDITOR", "RocksSP.pcx" }, { "sp_electron.EDITOR.xpos", "10" }, { "sp_electron.EDITOR.ypos", "11" }, { "sp_electron.exploding", "RocksSP.pcx" }, { "sp_electron.exploding.xpos", "8" }, { "sp_electron.exploding.ypos", "4" }, { "sp_electron.exploding.frames", "8" }, { "sp_electron.exploding.delay", "4" }, { "sp_electron.exploding.anim_mode", "linear" }, { "sp_terminal", "RocksSP.pcx" }, { "sp_terminal.xpos", "0" }, { "sp_terminal.ypos", "10" }, { "sp_terminal.frames", "7" }, { "sp_terminal.delay", "12" }, { "sp_terminal.EDITOR", "RocksSP.pcx" }, { "sp_terminal.EDITOR.xpos", "9" }, { "sp_terminal.EDITOR.ypos", "11" }, { "sp_terminal.active", "RocksSP.pcx" }, { "sp_terminal.active.xpos", "0" }, { "sp_terminal.active.ypos", "11" }, { "sp_terminal.active.frames", "7" }, { "sp_terminal.active.delay", "4" }, { "sp_buggy_base", "RocksSP.pcx" }, { "sp_buggy_base.xpos", "1" }, { "sp_buggy_base.ypos", "3" }, { "sp_buggy_base.frames", "1" }, { "sp_buggy_base.EDITOR", "RocksSP.pcx" }, { "sp_buggy_base.EDITOR.xpos", "9" }, { "sp_buggy_base.EDITOR.ypos", "6" }, { "sp_buggy_base.activating", "RocksSP.pcx" }, { "sp_buggy_base.activating.xpos", "15" }, { "sp_buggy_base.activating.ypos", "2" }, { "sp_buggy_base.activating.frames", "1" }, { "sp_buggy_base.active", "RocksSP.pcx" }, { "sp_buggy_base.active.xpos", "8" }, { "sp_buggy_base.active.ypos", "6" }, { "sp_buggy_base.active.frames", "4" }, { "sp_buggy_base.active.delay", "4" }, { "sp_buggy_base.active.anim_mode", "pingpong" }, { "sp_hardware_base_1", "RocksSP.pcx" }, { "sp_hardware_base_1.xpos", "4" }, { "sp_hardware_base_1.ypos", "3" }, { "sp_hardware_base_1.frames", "1" }, { "sp_hardware_base_2", "RocksSP.pcx" }, { "sp_hardware_base_2.xpos", "1" }, { "sp_hardware_base_2.ypos", "4" }, { "sp_hardware_base_2.frames", "1" }, { "sp_hardware_base_3", "RocksSP.pcx" }, { "sp_hardware_base_3.xpos", "2" }, { "sp_hardware_base_3.ypos", "4" }, { "sp_hardware_base_3.frames", "1" }, { "sp_hardware_base_4", "RocksSP.pcx" }, { "sp_hardware_base_4.xpos", "3" }, { "sp_hardware_base_4.ypos", "4" }, { "sp_hardware_base_4.frames", "1" }, { "sp_hardware_base_5", "RocksSP.pcx" }, { "sp_hardware_base_5.xpos", "4" }, { "sp_hardware_base_5.ypos", "4" }, { "sp_hardware_base_5.frames", "1" }, { "sp_hardware_base_6", "RocksSP.pcx" }, { "sp_hardware_base_6.xpos", "5" }, { "sp_hardware_base_6.ypos", "4" }, { "sp_hardware_base_6.frames", "1" }, /* images for Sokoban style elements and actions */ { "sokoban_object", "RocksElements.pcx" }, { "sokoban_object.xpos", "9" }, { "sokoban_object.ypos", "7" }, { "sokoban_object.frames", "1" }, { "sokoban_object.EDITOR", "RocksElements.pcx" }, { "sokoban_object.EDITOR.xpos", "2" }, { "sokoban_object.EDITOR.ypos", "14" }, { "sokoban_field_empty", "RocksElements.pcx" }, { "sokoban_field_empty.xpos", "10" }, { "sokoban_field_empty.ypos", "7" }, { "sokoban_field_empty.frames", "1" }, { "sokoban_field_full", "RocksElements.pcx" }, { "sokoban_field_full.xpos", "11" }, { "sokoban_field_full.ypos", "7" }, { "sokoban_field_full.frames", "1" }, { "sokoban_field_player", "RocksHeroes.pcx" }, { "sokoban_field_player.xpos", "0" }, { "sokoban_field_player.ypos", "15" }, { "sokoban_field_player.frames", "1" }, { "sokoban_field_player.EDITOR", "RocksHeroes.pcx" }, { "sokoban_field_player.EDITOR.xpos", "1" }, { "sokoban_field_player.EDITOR.ypos", "15" }, /* images for Emerald Mine style elements and actions */ { "empty_space", "RocksSP.pcx" }, { "empty_space.xpos", "0" }, { "empty_space.ypos", "0" }, { "empty_space.frames", "1" }, { "sand", "RocksElements.pcx" }, { "sand.xpos", "0" }, { "sand.ypos", "0" }, { "sand.frames", "1" }, { "sand.CRUMBLED", "RocksElements.pcx" }, { "sand.CRUMBLED.xpos", "1" }, { "sand.CRUMBLED.ypos", "0" }, { "sand.CRUMBLED.frames", "1" }, { "sand.digging.left", "RocksMore.pcx" }, { "sand.digging.left.xpos", "6" }, { "sand.digging.left.ypos", "3" }, { "sand.digging.left.frames", "3" }, { "sand.digging.left.delay", "2" }, { "sand.digging.left.anim_mode", "linear" }, { "sand.digging.right", "RocksMore.pcx" }, { "sand.digging.right.xpos", "9" }, { "sand.digging.right.ypos", "3" }, { "sand.digging.right.frames", "3" }, { "sand.digging.right.delay", "2" }, { "sand.digging.right.anim_mode", "linear" }, { "sand.digging.up", "RocksMore.pcx" }, { "sand.digging.up.xpos", "0" }, { "sand.digging.up.ypos", "3" }, { "sand.digging.up.frames", "3" }, { "sand.digging.up.delay", "2" }, { "sand.digging.up.anim_mode", "linear" }, { "sand.digging.down", "RocksMore.pcx" }, { "sand.digging.down.xpos", "3" }, { "sand.digging.down.ypos", "3" }, { "sand.digging.down.frames", "3" }, { "sand.digging.down.delay", "2" }, { "sand.digging.down.anim_mode", "linear" }, { "sand.digging.left.CRUMBLED", "RocksMore.pcx" }, { "sand.digging.left.CRUMBLED.xpos", "6" }, { "sand.digging.left.CRUMBLED.ypos", "0" }, { "sand.digging.left.CRUMBLED.frames", "3" }, { "sand.digging.left.CRUMBLED.delay", "2" }, { "sand.digging.left.CRUMBLED.anim_mode", "linear" }, { "sand.digging.right.CRUMBLED", "RocksMore.pcx" }, { "sand.digging.right.CRUMBLED.xpos", "9" }, { "sand.digging.right.CRUMBLED.ypos", "0" }, { "sand.digging.right.CRUMBLED.frames", "3" }, { "sand.digging.right.CRUMBLED.delay", "2" }, { "sand.digging.right.CRUMBLED.anim_mode", "linear" }, { "sand.digging.up.CRUMBLED", "RocksMore.pcx" }, { "sand.digging.up.CRUMBLED.xpos", "0" }, { "sand.digging.up.CRUMBLED.ypos", "0" }, { "sand.digging.up.CRUMBLED.frames", "3" }, { "sand.digging.up.CRUMBLED.delay", "2" }, { "sand.digging.up.CRUMBLED.anim_mode", "linear" }, { "sand.digging.down.CRUMBLED", "RocksMore.pcx" }, { "sand.digging.down.CRUMBLED.xpos", "3" }, { "sand.digging.down.CRUMBLED.ypos", "0" }, { "sand.digging.down.CRUMBLED.frames", "3" }, { "sand.digging.down.CRUMBLED.delay", "2" }, { "sand.digging.down.CRUMBLED.anim_mode", "linear" }, { "wall", "RocksElements.pcx" }, { "wall.xpos", "5" }, { "wall.ypos", "0" }, { "wall.frames", "1" }, { "wall_slippery", "RocksElements.pcx" }, { "wall_slippery.xpos", "6" }, { "wall_slippery.ypos", "0" }, { "wall_slippery.frames", "1" }, { "steelwall", "RocksElements.pcx" }, { "steelwall.xpos", "4" }, { "steelwall.ypos", "0" }, { "steelwall.frames", "1" }, { "rock", "RocksElements.pcx" }, { "rock.xpos", "12" }, { "rock.ypos", "0" }, { "rock.frames", "1" }, { "rock.moving.left", "RocksElements.pcx" }, { "rock.moving.left.xpos", "12" }, { "rock.moving.left.ypos", "0" }, { "rock.moving.left.frames", "4" }, { "rock.moving.left.delay", "2" }, { "rock.moving.left.anim_mode", "reverse" }, { "rock.moving.right", "RocksElements.pcx" }, { "rock.moving.right.xpos", "12" }, { "rock.moving.right.ypos", "0" }, { "rock.moving.right.frames", "4" }, { "rock.moving.right.start_frame", "1" }, { "rock.moving.right.delay", "2" }, { "rock.pushing.left", "RocksElements.pcx" }, { "rock.pushing.left.xpos", "12" }, { "rock.pushing.left.ypos", "0" }, { "rock.pushing.left.frames", "4" }, { "rock.pushing.left.delay", "2" }, { "rock.pushing.left.anim_mode", "reverse" }, { "rock.pushing.right", "RocksElements.pcx" }, { "rock.pushing.right.xpos", "12" }, { "rock.pushing.right.ypos", "0" }, { "rock.pushing.right.frames", "4" }, { "rock.pushing.right.start_frame", "1" }, { "rock.pushing.right.delay", "2" }, { "emerald", "RocksElements.pcx" }, { "emerald.xpos", "8" }, { "emerald.ypos", "0" }, { "emerald.frames", "1" }, { "emerald.moving", "RocksElements.pcx" }, { "emerald.moving.xpos", "8" }, { "emerald.moving.ypos", "0" }, { "emerald.moving.frames", "2" }, { "emerald.moving.delay", "4" }, { "emerald.falling", "RocksElements.pcx" }, { "emerald.falling.xpos", "8" }, { "emerald.falling.ypos", "0" }, { "emerald.falling.frames", "2" }, { "emerald.falling.delay", "4" }, { "emerald.collecting", "RocksMore.pcx" }, { "emerald.collecting.xpos", "3" }, { "emerald.collecting.ypos", "2" }, { "emerald.collecting.frames", "3" }, { "emerald.collecting.delay", "2" }, { "emerald.collecting.anim_mode", "linear" }, { "diamond", "RocksElements.pcx" }, { "diamond.xpos", "10" }, { "diamond.ypos", "0" }, { "diamond.frames", "1" }, { "diamond.moving", "RocksElements.pcx" }, { "diamond.moving.xpos", "10" }, { "diamond.moving.ypos", "0" }, { "diamond.moving.frames", "2" }, { "diamond.moving.delay", "4" }, { "diamond.falling", "RocksElements.pcx" }, { "diamond.falling.xpos", "10" }, { "diamond.falling.ypos", "0" }, { "diamond.falling.frames", "2" }, { "diamond.falling.delay", "4" }, { "diamond.collecting", "RocksMore.pcx" }, { "diamond.collecting.xpos", "7" }, { "diamond.collecting.ypos", "2" }, { "diamond.collecting.frames", "3" }, { "diamond.collecting.delay", "2" }, { "diamond.collecting.anim_mode", "linear" }, { "bomb", "RocksElements.pcx" }, { "bomb.xpos", "11" }, { "bomb.ypos", "1" }, { "bomb.frames", "1" }, { "nut", "RocksElements.pcx" }, { "nut.xpos", "12" }, { "nut.ypos", "1" }, { "nut.frames", "1" }, { "nut.breaking", "RocksElements.pcx" }, { "nut.breaking.xpos", "13" }, { "nut.breaking.ypos", "1" }, { "nut.breaking.frames", "3" }, { "nut.breaking.delay", "2" }, { "nut.breaking.anim_mode", "linear" }, { "dynamite", "RocksElements.pcx" }, { "dynamite.xpos", "0" }, { "dynamite.ypos", "3" }, { "dynamite.frames", "1" }, { "dynamite.EDITOR", "RocksElements.pcx" }, { "dynamite.EDITOR.xpos", "0" }, { "dynamite.EDITOR.ypos", "14" }, { "dynamite.active", "RocksElements.pcx" }, { "dynamite.active.xpos", "1" }, { "dynamite.active.ypos", "3" }, { "dynamite.active.frames", "7" }, { "dynamite.active.delay", "12" }, { "dynamite.active.anim_mode", "linear" }, { "dynamite.active.EDITOR", "RocksElements.pcx" }, { "dynamite.active.EDITOR.xpos", "1" }, { "dynamite.active.EDITOR.ypos", "14" }, { "em_dynamite", "RocksEMC.pcx" }, { "em_dynamite.xpos", "0" }, { "em_dynamite.ypos", "15" }, { "em_dynamite.frames", "1" }, { "em_dynamite.active", "RocksEMC.pcx" }, { "em_dynamite.active.xpos", "1" }, { "em_dynamite.active.ypos", "15" }, { "em_dynamite.active.frames", "4" }, { "em_dynamite.active.delay", "8" }, { "em_dynamite.active.anim_mode", "linear" }, { "em_dynamite.active.EDITOR", "RocksEMC.pcx" }, { "em_dynamite.active.EDITOR.xpos", "2" }, { "em_dynamite.active.EDITOR.ypos", "15" }, { "wall_emerald", "RocksElements.pcx" }, { "wall_emerald.xpos", "4" }, { "wall_emerald.ypos", "8" }, { "wall_emerald.frames", "1" }, { "wall_diamond", "RocksElements.pcx" }, { "wall_diamond.xpos", "5" }, { "wall_diamond.ypos", "8" }, { "wall_diamond.frames", "1" }, { "bug", "RocksElements.pcx" }, { "bug.xpos", "8" }, { "bug.ypos", "4" }, { "bug.frames", "4" }, { "bug.delay", "8" }, { "bug.right", "RocksElements.pcx" }, { "bug.right.xpos", "8" }, { "bug.right.ypos", "4" }, { "bug.right.frames", "1" }, { "bug.up", "RocksElements.pcx" }, { "bug.up.xpos", "9" }, { "bug.up.ypos", "4" }, { "bug.up.frames", "1" }, { "bug.left", "RocksElements.pcx" }, { "bug.left.xpos", "10" }, { "bug.left.ypos", "4" }, { "bug.left.frames", "1" }, { "bug.down", "RocksElements.pcx" }, { "bug.down.xpos", "11" }, { "bug.down.ypos", "4" }, { "bug.down.frames", "1" }, { "bug.moving.right", "RocksElements.pcx" }, { "bug.moving.right.xpos", "8" }, { "bug.moving.right.ypos", "4" }, { "bug.moving.right.frames", "2" }, { "bug.moving.right.delay", "4" }, { "bug.moving.right.offset", "128" }, { "bug.moving.up", "RocksElements.pcx" }, { "bug.moving.up.xpos", "9" }, { "bug.moving.up.ypos", "4" }, { "bug.moving.up.frames", "2" }, { "bug.moving.up.delay", "4" }, { "bug.moving.up.offset", "128" }, { "bug.moving.left", "RocksElements.pcx" }, { "bug.moving.left.xpos", "10" }, { "bug.moving.left.ypos", "4" }, { "bug.moving.left.frames", "2" }, { "bug.moving.left.delay", "4" }, { "bug.moving.left.offset", "128" }, { "bug.moving.down", "RocksElements.pcx" }, { "bug.moving.down.xpos", "11" }, { "bug.moving.down.ypos", "4" }, { "bug.moving.down.frames", "2" }, { "bug.moving.down.delay", "4" }, { "bug.moving.down.offset", "128" }, { "bug.turning_from_right.up", "RocksMore.pcx" }, { "bug.turning_from_right.up.xpos", "0" }, { "bug.turning_from_right.up.ypos", "6" }, { "bug.turning_from_right.up.frames", "4" }, { "bug.turning_from_right.up.delay", "2" }, { "bug.turning_from_right.up.anim_mode", "linear,reverse" }, { "bug.turning_from_up.left", "RocksMore.pcx" }, { "bug.turning_from_up.left.xpos", "12" }, { "bug.turning_from_up.left.ypos", "6" }, { "bug.turning_from_up.left.frames", "4" }, { "bug.turning_from_up.left.delay", "2" }, { "bug.turning_from_up.left.anim_mode", "linear,reverse" }, { "bug.turning_from_left.down", "RocksMore.pcx" }, { "bug.turning_from_left.down.xpos", "8" }, { "bug.turning_from_left.down.ypos", "6" }, { "bug.turning_from_left.down.frames", "4" }, { "bug.turning_from_left.down.delay", "2" }, { "bug.turning_from_left.down.anim_mode", "linear,reverse" }, { "bug.turning_from_down.right", "RocksMore.pcx" }, { "bug.turning_from_down.right.xpos", "4" }, { "bug.turning_from_down.right.ypos", "6" }, { "bug.turning_from_down.right.frames", "4" }, { "bug.turning_from_down.right.delay", "2" }, { "bug.turning_from_down.right.anim_mode", "linear,reverse" }, { "bug.turning_from_right.down", "RocksMore.pcx" }, { "bug.turning_from_right.down.xpos", "5" }, { "bug.turning_from_right.down.ypos", "6" }, { "bug.turning_from_right.down.frames", "4" }, { "bug.turning_from_right.down.delay", "2" }, { "bug.turning_from_right.down.anim_mode", "linear" }, { "bug.turning_from_up.right", "RocksMore.pcx" }, { "bug.turning_from_up.right.xpos", "1" }, { "bug.turning_from_up.right.ypos", "6" }, { "bug.turning_from_up.right.frames", "4" }, { "bug.turning_from_up.right.delay", "2" }, { "bug.turning_from_up.right.anim_mode", "linear" }, { "bug.turning_from_left.up", "RocksMore.pcx" }, { "bug.turning_from_left.up.xpos", "13" }, { "bug.turning_from_left.up.ypos", "6" }, { "bug.turning_from_left.up.frames", "4" }, { "bug.turning_from_left.up.delay", "2" }, { "bug.turning_from_left.up.anim_mode", "linear" }, { "bug.turning_from_down.left", "RocksMore.pcx" }, { "bug.turning_from_down.left.xpos", "9" }, { "bug.turning_from_down.left.ypos", "6" }, { "bug.turning_from_down.left.frames", "4" }, { "bug.turning_from_down.left.delay", "2" }, { "bug.turning_from_down.left.anim_mode", "linear" }, { "spaceship", "RocksElements.pcx" }, { "spaceship.xpos", "8" }, { "spaceship.ypos", "3" }, { "spaceship.frames", "4" }, { "spaceship.delay", "8" }, { "spaceship.right", "RocksElements.pcx" }, { "spaceship.right.xpos", "8" }, { "spaceship.right.ypos", "3" }, { "spaceship.right.frames", "1" }, { "spaceship.up", "RocksElements.pcx" }, { "spaceship.up.xpos", "9" }, { "spaceship.up.ypos", "3" }, { "spaceship.up.frames", "1" }, { "spaceship.left", "RocksElements.pcx" }, { "spaceship.left.xpos", "10" }, { "spaceship.left.ypos", "3" }, { "spaceship.left.frames", "1" }, { "spaceship.down", "RocksElements.pcx" }, { "spaceship.down.xpos", "11" }, { "spaceship.down.ypos", "3" }, { "spaceship.down.frames", "1" }, { "spaceship.moving.right", "RocksElements.pcx" }, { "spaceship.moving.right.xpos", "8" }, { "spaceship.moving.right.ypos", "3" }, { "spaceship.moving.right.frames", "2" }, { "spaceship.moving.right.delay", "4" }, { "spaceship.moving.right.offset", "128" }, { "spaceship.moving.up", "RocksElements.pcx" }, { "spaceship.moving.up.xpos", "9" }, { "spaceship.moving.up.ypos", "3" }, { "spaceship.moving.up.frames", "2" }, { "spaceship.moving.up.delay", "4" }, { "spaceship.moving.up.offset", "128" }, { "spaceship.moving.left", "RocksElements.pcx" }, { "spaceship.moving.left.xpos", "10" }, { "spaceship.moving.left.ypos", "3" }, { "spaceship.moving.left.frames", "2" }, { "spaceship.moving.left.delay", "4" }, { "spaceship.moving.left.offset", "128" }, { "spaceship.moving.down", "RocksElements.pcx" }, { "spaceship.moving.down.xpos", "11" }, { "spaceship.moving.down.ypos", "3" }, { "spaceship.moving.down.frames", "2" }, { "spaceship.moving.down.delay", "4" }, { "spaceship.moving.down.offset", "128" }, { "spaceship.turning_from_right.up", "RocksMore.pcx" }, { "spaceship.turning_from_right.up.xpos", "0" }, { "spaceship.turning_from_right.up.ypos", "5" }, { "spaceship.turning_from_right.up.frames", "4" }, { "spaceship.turning_from_right.up.delay", "2" }, { "spaceship.turning_from_right.up.anim_mode","linear,reverse" }, { "spaceship.turning_from_up.left", "RocksMore.pcx" }, { "spaceship.turning_from_up.left.xpos", "12" }, { "spaceship.turning_from_up.left.ypos", "5" }, { "spaceship.turning_from_up.left.frames", "4" }, { "spaceship.turning_from_up.left.delay", "2" }, { "spaceship.turning_from_up.left.anim_mode", "linear,reverse" }, { "spaceship.turning_from_left.down", "RocksMore.pcx" }, { "spaceship.turning_from_left.down.xpos", "8" }, { "spaceship.turning_from_left.down.ypos", "5" }, { "spaceship.turning_from_left.down.frames", "4" }, { "spaceship.turning_from_left.down.delay", "2" }, { "spaceship.turning_from_left.down.anim_mode","linear,reverse" }, { "spaceship.turning_from_down.right", "RocksMore.pcx" }, { "spaceship.turning_from_down.right.xpos", "4" }, { "spaceship.turning_from_down.right.ypos", "5" }, { "spaceship.turning_from_down.right.frames", "4" }, { "spaceship.turning_from_down.right.delay", "2" }, { "spaceship.turning_from_down.right.anim_mode","linear,reverse" }, { "spaceship.turning_from_right.down", "RocksMore.pcx" }, { "spaceship.turning_from_right.down.xpos", "5" }, { "spaceship.turning_from_right.down.ypos", "5" }, { "spaceship.turning_from_right.down.frames", "4" }, { "spaceship.turning_from_right.down.delay", "2" }, { "spaceship.turning_from_right.down.anim_mode","linear" }, { "spaceship.turning_from_up.right", "RocksMore.pcx" }, { "spaceship.turning_from_up.right.xpos", "1" }, { "spaceship.turning_from_up.right.ypos", "5" }, { "spaceship.turning_from_up.right.frames", "4" }, { "spaceship.turning_from_up.right.delay", "2" }, { "spaceship.turning_from_up.right.anim_mode","linear" }, { "spaceship.turning_from_left.up", "RocksMore.pcx" }, { "spaceship.turning_from_left.up.xpos", "13" }, { "spaceship.turning_from_left.up.ypos", "5" }, { "spaceship.turning_from_left.up.frames", "4" }, { "spaceship.turning_from_left.up.delay", "2" }, { "spaceship.turning_from_left.up.anim_mode", "linear" }, { "spaceship.turning_from_down.left", "RocksMore.pcx" }, { "spaceship.turning_from_down.left.xpos", "9" }, { "spaceship.turning_from_down.left.ypos", "5" }, { "spaceship.turning_from_down.left.frames", "4" }, { "spaceship.turning_from_down.left.delay", "2" }, { "spaceship.turning_from_down.left.anim_mode","linear" }, { "yamyam", "RocksElements.pcx" }, { "yamyam.xpos", "0" }, { "yamyam.ypos", "5" }, { "yamyam.frames", "4" }, { "yamyam.anim_mode", "pingpong2" }, { "yamyam.left", "RocksElements.pcx" }, { "yamyam.left.xpos", "0" }, { "yamyam.left.ypos", "5" }, { "yamyam.left.frames", "4" }, { "yamyam.left.anim_mode", "pingpong2" }, { "yamyam.left.EDITOR", "RocksEMC.pcx" }, { "yamyam.left.EDITOR.xpos", "7" }, { "yamyam.left.EDITOR.ypos", "15" }, { "yamyam.right", "RocksElements.pcx" }, { "yamyam.right.xpos", "0" }, { "yamyam.right.ypos", "5" }, { "yamyam.right.frames", "4" }, { "yamyam.right.anim_mode", "pingpong2" }, { "yamyam.right.EDITOR", "RocksEMC.pcx" }, { "yamyam.right.EDITOR.xpos", "8" }, { "yamyam.right.EDITOR.ypos", "15" }, { "yamyam.up", "RocksElements.pcx" }, { "yamyam.up.xpos", "0" }, { "yamyam.up.ypos", "5" }, { "yamyam.up.frames", "4" }, { "yamyam.up.anim_mode", "pingpong2" }, { "yamyam.up.EDITOR", "RocksEMC.pcx" }, { "yamyam.up.EDITOR.xpos", "5" }, { "yamyam.up.EDITOR.ypos", "15" }, { "yamyam.down", "RocksElements.pcx" }, { "yamyam.down.xpos", "0" }, { "yamyam.down.ypos", "5" }, { "yamyam.down.frames", "4" }, { "yamyam.down.anim_mode", "pingpong2" }, { "yamyam.down.EDITOR", "RocksEMC.pcx" }, { "yamyam.down.EDITOR.xpos", "6" }, { "yamyam.down.EDITOR.ypos", "15" }, { "yamyam.moving", "RocksElements.pcx" }, { "yamyam.moving.xpos", "0" }, { "yamyam.moving.ypos", "5" }, { "yamyam.moving.frames", "1" }, { "robot", "RocksElements.pcx" }, { "robot.xpos", "4" }, { "robot.ypos", "5" }, { "robot.frames", "4" }, { "robot.anim_mode", "pingpong2" }, { "robot.moving", "RocksElements.pcx" }, { "robot.moving.xpos", "4" }, { "robot.moving.ypos", "5" }, { "robot.moving.frames", "1" }, { "robot_wheel", "RocksElements.pcx" }, { "robot_wheel.xpos", "0" }, { "robot_wheel.ypos", "6" }, { "robot_wheel.frames", "1" }, { "robot_wheel.active", "RocksElements.pcx" }, { "robot_wheel.active.xpos", "0" }, { "robot_wheel.active.ypos", "6" }, { "robot_wheel.active.frames", "4" }, { "magic_wall", "RocksElements.pcx" }, { "magic_wall.xpos", "0" }, { "magic_wall.ypos", "8" }, { "magic_wall.frames", "1" }, { "magic_wall.active", "RocksElements.pcx" }, { "magic_wall.active.xpos", "0" }, { "magic_wall.active.ypos", "8" }, { "magic_wall.active.frames", "4" }, { "magic_wall.active.anim_mode", "reverse" }, { "magic_wall.active.delay", "4" }, { "magic_wall.active.global_sync", "true" }, { "magic_wall.filling", "RocksElements.pcx" }, { "magic_wall.filling.xpos", "0" }, { "magic_wall.filling.ypos", "8" }, { "magic_wall.filling.frames", "4" }, { "magic_wall.filling.anim_mode", "reverse" }, { "magic_wall.filling.delay", "4" }, { "magic_wall.filling.global_sync", "true" }, { "magic_wall_full", "RocksElements.pcx" }, { "magic_wall_full.xpos", "0" }, { "magic_wall_full.ypos", "8" }, { "magic_wall_full.frames", "4" }, { "magic_wall_full.anim_mode", "reverse" }, { "magic_wall_full.delay", "4" }, { "magic_wall_full.global_sync", "true" }, { "magic_wall.emptying", "RocksElements.pcx" }, { "magic_wall.emptying.xpos", "0" }, { "magic_wall.emptying.ypos", "8" }, { "magic_wall.emptying.frames", "4" }, { "magic_wall.emptying.anim_mode", "reverse" }, { "magic_wall.emptying.delay", "4" }, { "magic_wall.emptying.global_sync", "true" }, { "magic_wall_dead", "RocksElements.pcx" }, { "magic_wall_dead.xpos", "0" }, { "magic_wall_dead.ypos", "8" }, { "magic_wall_dead.frames", "1" }, { "dc_magic_wall", "RocksDC2.pcx" }, { "dc_magic_wall.xpos", "0" }, { "dc_magic_wall.ypos", "3" }, { "dc_magic_wall.frames", "1" }, { "dc_magic_wall.active", "RocksDC2.pcx" }, { "dc_magic_wall.active.xpos", "0" }, { "dc_magic_wall.active.ypos", "3" }, { "dc_magic_wall.active.frames", "4" }, { "dc_magic_wall.active.anim_mode", "reverse" }, { "dc_magic_wall.active.delay", "4" }, { "dc_magic_wall.active.global_sync", "true" }, { "dc_magic_wall.filling", "RocksDC2.pcx" }, { "dc_magic_wall.filling.xpos", "0" }, { "dc_magic_wall.filling.ypos", "3" }, { "dc_magic_wall.filling.frames", "4" }, { "dc_magic_wall.filling.anim_mode", "reverse" }, { "dc_magic_wall.filling.delay", "4" }, { "dc_magic_wall.filling.global_sync", "true" }, { "dc_magic_wall_full", "RocksDC2.pcx" }, { "dc_magic_wall_full.xpos", "0" }, { "dc_magic_wall_full.ypos", "3" }, { "dc_magic_wall_full.frames", "4" }, { "dc_magic_wall_full.anim_mode", "reverse" }, { "dc_magic_wall_full.delay", "4" }, { "dc_magic_wall_full.global_sync", "true" }, { "dc_magic_wall.emptying", "RocksDC2.pcx" }, { "dc_magic_wall.emptying.xpos", "0" }, { "dc_magic_wall.emptying.ypos", "3" }, { "dc_magic_wall.emptying.frames", "4" }, { "dc_magic_wall.emptying.anim_mode", "reverse" }, { "dc_magic_wall.emptying.delay", "4" }, { "dc_magic_wall.emptying.global_sync", "true" }, { "dc_magic_wall_dead", "RocksDC2.pcx" }, { "dc_magic_wall_dead.xpos", "0" }, { "dc_magic_wall_dead.ypos", "3" }, { "dc_magic_wall_dead.frames", "1" }, { "quicksand_empty", "RocksElements.pcx" }, { "quicksand_empty.xpos", "2" }, { "quicksand_empty.ypos", "0" }, { "quicksand_empty.frames", "1" }, { "quicksand.filling", "RocksElements.pcx" }, { "quicksand.filling.xpos", "3" }, { "quicksand.filling.ypos", "0" }, { "quicksand.filling.frames", "1" }, { "quicksand_full", "RocksElements.pcx" }, { "quicksand_full.xpos", "3" }, { "quicksand_full.ypos", "0" }, { "quicksand_full.frames", "1" }, { "quicksand_full.EDITOR", "RocksElements.pcx" }, { "quicksand_full.EDITOR.xpos", "3" }, { "quicksand_full.EDITOR.ypos", "14" }, { "quicksand.emptying", "RocksElements.pcx" }, { "quicksand.emptying.xpos", "3" }, { "quicksand.emptying.ypos", "0" }, { "quicksand.emptying.frames", "1" }, { "quicksand_fast_empty", "RocksDC2.pcx" }, { "quicksand_fast_empty.xpos", "4" }, { "quicksand_fast_empty.ypos", "3" }, { "quicksand_fast_empty.frames", "1" }, { "quicksand_fast.filling", "RocksDC2.pcx" }, { "quicksand_fast.filling.xpos", "4" }, { "quicksand_fast.filling.ypos", "3" }, { "quicksand_fast.filling.frames", "1" }, { "quicksand_fast_full", "RocksDC2.pcx" }, { "quicksand_fast_full.xpos", "4" }, { "quicksand_fast_full.ypos", "3" }, { "quicksand_fast_full.frames", "1" }, { "quicksand_fast_full.EDITOR", "RocksDC2.pcx" }, { "quicksand_fast_full.EDITOR.xpos", "5" }, { "quicksand_fast_full.EDITOR.ypos", "3" }, { "quicksand_fast.emptying", "RocksDC2.pcx" }, { "quicksand_fast.emptying.xpos", "4" }, { "quicksand_fast.emptying.ypos", "3" }, { "quicksand_fast.emptying.frames", "1" }, { "acid_pool_topleft", "RocksElements.pcx" }, { "acid_pool_topleft.xpos", "0" }, { "acid_pool_topleft.ypos", "1" }, { "acid_pool_topleft.frames", "1" }, { "acid_pool_topright", "RocksElements.pcx" }, { "acid_pool_topright.xpos", "2" }, { "acid_pool_topright.ypos", "1" }, { "acid_pool_topright.frames", "1" }, { "acid_pool_bottomleft", "RocksElements.pcx" }, { "acid_pool_bottomleft.xpos", "0" }, { "acid_pool_bottomleft.ypos", "2" }, { "acid_pool_bottomleft.frames", "1" }, { "acid_pool_bottom", "RocksElements.pcx" }, { "acid_pool_bottom.xpos", "1" }, { "acid_pool_bottom.ypos", "2" }, { "acid_pool_bottom.frames", "1" }, { "acid_pool_bottomright", "RocksElements.pcx" }, { "acid_pool_bottomright.xpos", "2" }, { "acid_pool_bottomright.ypos", "2" }, { "acid_pool_bottomright.frames", "1" }, { "acid", "RocksElements.pcx" }, { "acid.xpos", "12" }, { "acid.ypos", "7" }, { "acid.frames", "4" }, { "acid.delay", "10" }, { "acid.global_sync", "true" }, { "acid_splash_left", "RocksHeroes.pcx" }, { "acid_splash_left.xpos", "8" }, { "acid_splash_left.ypos", "10" }, { "acid_splash_left.frames", "4" }, { "acid_splash_left.delay", "2" }, { "acid_splash_left.anim_mode", "linear" }, { "acid_splash_right", "RocksHeroes.pcx" }, { "acid_splash_right.xpos", "12" }, { "acid_splash_right.ypos", "10" }, { "acid_splash_right.frames", "4" }, { "acid_splash_right.delay", "2" }, { "acid_splash_right.anim_mode", "linear" }, { "amoeba_drop", "RocksElements.pcx" }, { "amoeba_drop.xpos", "5" }, { "amoeba_drop.ypos", "6" }, { "amoeba_drop.frames", "1" }, { "amoeba.growing", "RocksElements.pcx" }, { "amoeba.growing.xpos", "5" }, { "amoeba.growing.ypos", "6" }, { "amoeba.growing.frames", "3" }, { "amoeba.growing.delay", "2" }, { "amoeba.growing.anim_mode", "linear" }, { "amoeba.shrinking", "RocksElements.pcx" }, { "amoeba.shrinking.xpos", "5" }, { "amoeba.shrinking.ypos", "6" }, { "amoeba.shrinking.frames", "3" }, { "amoeba.shrinking.delay", "2" }, { "amoeba.shrinking.anim_mode", "linear,reverse" }, { "amoeba_wet", "RocksElements.pcx" }, { "amoeba_wet.xpos", "8" }, { "amoeba_wet.ypos", "6" }, { "amoeba_wet.frames", "4" }, { "amoeba_wet.delay", "1000000" }, { "amoeba_wet.anim_mode", "random" }, { "amoeba_wet.EDITOR", "RocksElements.pcx" }, { "amoeba_wet.EDITOR.xpos", "4" }, { "amoeba_wet.EDITOR.ypos", "6" }, { "amoeba.dropping", "RocksElements.pcx" }, { "amoeba.dropping.xpos", "8" }, { "amoeba.dropping.ypos", "6" }, { "amoeba.dropping.frames", "4" }, { "amoeba.dropping.delay", "1000000" }, { "amoeba.dropping.anim_mode", "random" }, { "amoeba_dry", "RocksElements.pcx" }, { "amoeba_dry.xpos", "8" }, { "amoeba_dry.ypos", "6" }, { "amoeba_dry.frames", "4" }, { "amoeba_dry.delay", "1000000" }, { "amoeba_dry.anim_mode", "random" }, { "amoeba_full", "RocksElements.pcx" }, { "amoeba_full.xpos", "8" }, { "amoeba_full.ypos", "6" }, { "amoeba_full.frames", "4" }, { "amoeba_full.delay", "1000000" }, { "amoeba_full.anim_mode", "random" }, { "amoeba_full.EDITOR", "RocksElements.pcx" }, { "amoeba_full.EDITOR.xpos", "8" }, { "amoeba_full.EDITOR.ypos", "7" }, { "amoeba_dead", "RocksElements.pcx" }, { "amoeba_dead.xpos", "12" }, { "amoeba_dead.ypos", "6" }, { "amoeba_dead.frames", "4" }, { "amoeba_dead.delay", "1000000" }, { "amoeba_dead.anim_mode", "random" }, { "amoeba_dead.EDITOR", "RocksElements.pcx" }, { "amoeba_dead.EDITOR.xpos", "12" }, { "amoeba_dead.EDITOR.ypos", "6" }, { "em_key_1", "RocksSP.pcx" }, { "em_key_1.xpos", "4" }, { "em_key_1.ypos", "6" }, { "em_key_1.frames", "1" }, { "em_key_2", "RocksSP.pcx" }, { "em_key_2.xpos", "5" }, { "em_key_2.ypos", "6" }, { "em_key_2.frames", "1" }, { "em_key_3", "RocksSP.pcx" }, { "em_key_3.xpos", "6" }, { "em_key_3.ypos", "6" }, { "em_key_3.frames", "1" }, { "em_key_4", "RocksSP.pcx" }, { "em_key_4.xpos", "7" }, { "em_key_4.ypos", "6" }, { "em_key_4.frames", "1" }, { "dc_key_white", "RocksSP.pcx" }, { "dc_key_white.xpos", "13" }, { "dc_key_white.ypos", "1" }, { "dc_key_white.frames", "1" }, { "em_gate_1", "RocksSP.pcx" }, { "em_gate_1.xpos", "0" }, { "em_gate_1.ypos", "7" }, { "em_gate_1.frames", "1" }, { "em_gate_2", "RocksSP.pcx" }, { "em_gate_2.xpos", "1" }, { "em_gate_2.ypos", "7" }, { "em_gate_2.frames", "1" }, { "em_gate_3", "RocksSP.pcx" }, { "em_gate_3.xpos", "2" }, { "em_gate_3.ypos", "7" }, { "em_gate_3.frames", "1" }, { "em_gate_4", "RocksSP.pcx" }, { "em_gate_4.xpos", "3" }, { "em_gate_4.ypos", "7" }, { "em_gate_4.frames", "1" }, { "dc_gate_white", "RocksSP.pcx" }, { "dc_gate_white.xpos", "14" }, { "dc_gate_white.ypos", "1" }, { "dc_gate_white.frames", "1" }, { "em_gate_1_gray", "RocksSP.pcx" }, { "em_gate_1_gray.xpos", "4" }, { "em_gate_1_gray.ypos", "7" }, { "em_gate_1_gray.frames", "1" }, { "em_gate_1_gray.EDITOR", "RocksSP.pcx" }, { "em_gate_1_gray.EDITOR.xpos", "12" }, { "em_gate_1_gray.EDITOR.ypos", "11" }, { "em_gate_1_gray.active", "RocksSP.pcx" }, { "em_gate_1_gray.active.xpos", "0" }, { "em_gate_1_gray.active.ypos", "7" }, { "em_gate_1_gray.active.frames", "1" }, { "em_gate_2_gray", "RocksSP.pcx" }, { "em_gate_2_gray.xpos", "5" }, { "em_gate_2_gray.ypos", "7" }, { "em_gate_2_gray.frames", "1" }, { "em_gate_2_gray.EDITOR", "RocksSP.pcx" }, { "em_gate_2_gray.EDITOR.xpos", "13" }, { "em_gate_2_gray.EDITOR.ypos", "11" }, { "em_gate_2_gray.active", "RocksSP.pcx" }, { "em_gate_2_gray.active.xpos", "1" }, { "em_gate_2_gray.active.ypos", "7" }, { "em_gate_2_gray.active.frames", "1" }, { "em_gate_3_gray", "RocksSP.pcx" }, { "em_gate_3_gray.xpos", "6" }, { "em_gate_3_gray.ypos", "7" }, { "em_gate_3_gray.frames", "1" }, { "em_gate_3_gray.EDITOR", "RocksSP.pcx" }, { "em_gate_3_gray.EDITOR.xpos", "14" }, { "em_gate_3_gray.EDITOR.ypos", "11" }, { "em_gate_3_gray.active", "RocksSP.pcx" }, { "em_gate_3_gray.active.xpos", "2" }, { "em_gate_3_gray.active.ypos", "7" }, { "em_gate_3_gray.active.frames", "1" }, { "em_gate_4_gray", "RocksSP.pcx" }, { "em_gate_4_gray.xpos", "7" }, { "em_gate_4_gray.ypos", "7" }, { "em_gate_4_gray.frames", "1" }, { "em_gate_4_gray.EDITOR", "RocksSP.pcx" }, { "em_gate_4_gray.EDITOR.xpos", "15" }, { "em_gate_4_gray.EDITOR.ypos", "11" }, { "em_gate_4_gray.active", "RocksSP.pcx" }, { "em_gate_4_gray.active.xpos", "3" }, { "em_gate_4_gray.active.ypos", "7" }, { "em_gate_4_gray.active.frames", "1" }, { "dc_gate_white_gray", "RocksSP.pcx" }, { "dc_gate_white_gray.xpos", "7" }, { "dc_gate_white_gray.ypos", "7" }, { "dc_gate_white_gray.frames", "1" }, { "dc_gate_white_gray.EDITOR", "RocksSP.pcx" }, { "dc_gate_white_gray.EDITOR.xpos", "15" }, { "dc_gate_white_gray.EDITOR.ypos", "1" }, { "dc_gate_white_gray.active", "RocksSP.pcx" }, { "dc_gate_white_gray.active.xpos", "14" }, { "dc_gate_white_gray.active.ypos", "1" }, { "dc_gate_white_gray.active.frames", "1" }, { "dc_gate_fake_gray", "RocksSP.pcx" }, { "dc_gate_fake_gray.xpos", "7" }, { "dc_gate_fake_gray.ypos", "7" }, { "dc_gate_fake_gray.frames", "1" }, { "exit_closed", "RocksElements.pcx" }, { "exit_closed.xpos", "0" }, { "exit_closed.ypos", "11" }, { "exit_closed.frames", "1" }, { "exit.opening", "RocksElements.pcx" }, { "exit.opening.xpos", "0" }, { "exit.opening.ypos", "11" }, { "exit.opening.frames", "5" }, { "exit.opening.delay", "6" }, { "exit.opening.anim_mode", "linear" }, { "exit_open", "RocksElements.pcx" }, { "exit_open.xpos", "4" }, { "exit_open.ypos", "11" }, { "exit_open.frames", "4" }, { "exit_open.delay", "4" }, { "exit_open.anim_mode", "pingpong" }, { "exit.closing", "RocksElements.pcx" }, { "exit.closing.xpos", "0" }, { "exit.closing.ypos", "11" }, { "exit.closing.frames", "5" }, { "exit.closing.delay", "6" }, { "exit.closing.anim_mode", "linear,reverse" }, { "steel_exit_closed", "RocksDC2.pcx" }, { "steel_exit_closed.xpos", "8" }, { "steel_exit_closed.ypos", "0" }, { "steel_exit_closed.frames", "1" }, { "steel_exit.opening", "RocksDC2.pcx" }, { "steel_exit.opening.xpos", "8" }, { "steel_exit.opening.ypos", "0" }, { "steel_exit.opening.frames", "5" }, { "steel_exit.opening.delay", "6" }, { "steel_exit.opening.anim_mode", "linear" }, { "steel_exit_open", "RocksDC2.pcx" }, { "steel_exit_open.xpos", "12" }, { "steel_exit_open.ypos", "0" }, { "steel_exit_open.frames", "4" }, { "steel_exit_open.delay", "4" }, { "steel_exit_open.anim_mode", "pingpong" }, { "steel_exit.closing", "RocksDC2.pcx" }, { "steel_exit.closing.xpos", "8" }, { "steel_exit.closing.ypos", "0" }, { "steel_exit.closing.frames", "5" }, { "steel_exit.closing.delay", "6" }, { "steel_exit.closing.anim_mode", "linear,reverse" }, { "em_exit_closed", "RocksDC2.pcx" }, { "em_exit_closed.xpos", "0" }, { "em_exit_closed.ypos", "4" }, { "em_exit_closed.frames", "1" }, { "em_exit.opening", "RocksDC2.pcx" }, { "em_exit.opening.xpos", "0" }, { "em_exit.opening.ypos", "4" }, { "em_exit.opening.frames", "5" }, { "em_exit.opening.delay", "6" }, { "em_exit.opening.anim_mode", "linear" }, { "em_exit_open", "RocksDC2.pcx" }, { "em_exit_open.xpos", "4" }, { "em_exit_open.ypos", "4" }, { "em_exit_open.frames", "4" }, { "em_exit_open.delay", "4" }, { "em_exit_open.anim_mode", "pingpong" }, { "em_exit.closing", "RocksDC2.pcx" }, { "em_exit.closing.xpos", "0" }, { "em_exit.closing.ypos", "6" }, { "em_exit.closing.frames", "5" }, { "em_exit.closing.delay", "6" }, { "em_exit.closing.anim_mode", "linear" }, { "em_steel_exit_closed", "RocksDC2.pcx" }, { "em_steel_exit_closed.xpos", "0" }, { "em_steel_exit_closed.ypos", "5" }, { "em_steel_exit_closed.frames", "1" }, { "em_steel_exit.opening", "RocksDC2.pcx" }, { "em_steel_exit.opening.xpos", "0" }, { "em_steel_exit.opening.ypos", "5" }, { "em_steel_exit.opening.frames", "5" }, { "em_steel_exit.opening.delay", "6" }, { "em_steel_exit.opening.anim_mode", "linear" }, { "em_steel_exit_open", "RocksDC2.pcx" }, { "em_steel_exit_open.xpos", "4" }, { "em_steel_exit_open.ypos", "5" }, { "em_steel_exit_open.frames", "4" }, { "em_steel_exit_open.delay", "4" }, { "em_steel_exit_open.anim_mode", "pingpong" }, { "em_steel_exit.closing", "RocksDC2.pcx" }, { "em_steel_exit.closing.xpos", "0" }, { "em_steel_exit.closing.ypos", "7" }, { "em_steel_exit.closing.frames", "5" }, { "em_steel_exit.closing.delay", "6" }, { "em_steel_exit.closing.anim_mode", "linear" }, /* images for Emerald Mine Club style elements and actions */ { "balloon", "RocksDC.pcx" }, { "balloon.xpos", "12" }, { "balloon.ypos", "7" }, { "balloon.frames", "1" }, { "balloon.moving", "RocksDC.pcx" }, { "balloon.moving.xpos", "12" }, { "balloon.moving.ypos", "7" }, { "balloon.moving.frames", "4" }, { "balloon.moving.anim_mode", "pingpong" }, { "balloon.moving.delay", "2" }, { "balloon.pushing", "RocksDC.pcx" }, { "balloon.pushing.xpos", "12" }, { "balloon.pushing.ypos", "7" }, { "balloon.pushing.frames", "4" }, { "balloon.pushing.anim_mode", "pingpong" }, { "balloon.pushing.delay", "2" }, { "balloon_switch_left", "RocksDC.pcx" }, { "balloon_switch_left.xpos", "8" }, { "balloon_switch_left.ypos", "7" }, { "balloon_switch_left.frames", "1" }, { "balloon_switch_right", "RocksDC.pcx" }, { "balloon_switch_right.xpos", "9" }, { "balloon_switch_right.ypos", "7" }, { "balloon_switch_right.frames", "1" }, { "balloon_switch_up", "RocksDC.pcx" }, { "balloon_switch_up.xpos", "10" }, { "balloon_switch_up.ypos", "7" }, { "balloon_switch_up.frames", "1" }, { "balloon_switch_down", "RocksDC.pcx" }, { "balloon_switch_down.xpos", "11" }, { "balloon_switch_down.ypos", "7" }, { "balloon_switch_down.frames", "1" }, { "balloon_switch_any", "RocksDC.pcx" }, { "balloon_switch_any.xpos", "15" }, { "balloon_switch_any.ypos", "0" }, { "balloon_switch_any.frames", "1" }, { "balloon_switch_none", "RocksDC.pcx" }, { "balloon_switch_none.xpos", "13" }, { "balloon_switch_none.ypos", "5" }, { "balloon_switch_none.frames", "1" }, { "spring", "RocksDC.pcx" }, { "spring.xpos", "8" }, { "spring.ypos", "13" }, { "spring.frames", "1" }, { "emc_steelwall_1", "RocksDC.pcx" }, { "emc_steelwall_1.xpos", "14" }, { "emc_steelwall_1.ypos", "0" }, { "emc_steelwall_1.frames", "1" }, { "emc_steelwall_2", "RocksEMC.pcx" }, { "emc_steelwall_2.xpos", "9" }, { "emc_steelwall_2.ypos", "8" }, { "emc_steelwall_2.frames", "1" }, { "emc_steelwall_3", "RocksEMC.pcx" }, { "emc_steelwall_3.xpos", "9" }, { "emc_steelwall_3.ypos", "9" }, { "emc_steelwall_3.frames", "1" }, { "emc_steelwall_4", "RocksEMC.pcx" }, { "emc_steelwall_4.xpos", "9" }, { "emc_steelwall_4.ypos", "10" }, { "emc_steelwall_4.frames", "1" }, { "emc_wall_1", "RocksDC.pcx" }, { "emc_wall_1.xpos", "13" }, { "emc_wall_1.ypos", "6" }, { "emc_wall_1.frames", "1" }, { "emc_wall_2", "RocksDC.pcx" }, { "emc_wall_2.xpos", "14" }, { "emc_wall_2.ypos", "6" }, { "emc_wall_2.frames", "1" }, { "emc_wall_3", "RocksDC.pcx" }, { "emc_wall_3.xpos", "15" }, { "emc_wall_3.ypos", "6" }, { "emc_wall_3.frames", "1" }, { "emc_wall_4", "RocksDC.pcx" }, { "emc_wall_4.xpos", "14" }, { "emc_wall_4.ypos", "1" }, { "emc_wall_4.frames", "1" }, { "emc_wall_5", "RocksDC.pcx" }, { "emc_wall_5.xpos", "15" }, { "emc_wall_5.ypos", "1" }, { "emc_wall_5.frames", "1" }, { "emc_wall_6", "RocksDC.pcx" }, { "emc_wall_6.xpos", "14" }, { "emc_wall_6.ypos", "2" }, { "emc_wall_6.frames", "1" }, { "emc_wall_7", "RocksDC.pcx" }, { "emc_wall_7.xpos", "15" }, { "emc_wall_7.ypos", "2" }, { "emc_wall_7.frames", "1" }, { "emc_wall_8", "RocksEMC.pcx" }, { "emc_wall_8.xpos", "8" }, { "emc_wall_8.ypos", "7" }, { "emc_wall_8.frames", "1" }, /* images for Diamond Caves style elements and actions */ { "invisible_steelwall", "RocksSP.pcx" }, { "invisible_steelwall.xpos", "3" }, { "invisible_steelwall.ypos", "5" }, { "invisible_steelwall.frames", "1" }, { "invisible_steelwall.EDITOR", "RocksSP.pcx" }, { "invisible_steelwall.EDITOR.xpos", "1" }, { "invisible_steelwall.EDITOR.ypos", "5" }, { "invisible_steelwall.active", "RocksSP.pcx" }, { "invisible_steelwall.active.xpos", "1" }, { "invisible_steelwall.active.ypos", "5" }, { "invisible_steelwall.active.frames", "1" }, { "invisible_wall", "RocksSP.pcx" }, { "invisible_wall.xpos", "7" }, { "invisible_wall.ypos", "5" }, { "invisible_wall.frames", "1" }, { "invisible_wall.EDITOR", "RocksSP.pcx" }, { "invisible_wall.EDITOR.xpos", "5" }, { "invisible_wall.EDITOR.ypos", "5" }, { "invisible_wall.active", "RocksSP.pcx" }, { "invisible_wall.active.xpos", "5" }, { "invisible_wall.active.ypos", "5" }, { "invisible_wall.active.frames", "1" }, { "invisible_sand", "RocksSP.pcx" }, { "invisible_sand.xpos", "0" }, { "invisible_sand.ypos", "0" }, { "invisible_sand.frames", "1" }, { "invisible_sand.EDITOR", "RocksEMC.pcx" }, { "invisible_sand.EDITOR.xpos", "2" }, { "invisible_sand.EDITOR.ypos", "4" }, { "invisible_sand.active", "RocksEMC.pcx" }, { "invisible_sand.active.xpos", "2" }, { "invisible_sand.active.ypos", "4" }, { "invisible_sand.active.frames", "1" }, { "invisible_sand.active.CRUMBLED", "RocksEMC.pcx" }, { "invisible_sand.active.CRUMBLED.xpos", "3" }, { "invisible_sand.active.CRUMBLED.ypos", "4" }, { "invisible_sand.active.CRUMBLED.frames", "1" }, { "invisible_sand.active.digging.left", "RocksEMC.pcx" }, { "invisible_sand.active.digging.left.xpos", "6" }, { "invisible_sand.active.digging.left.ypos", "2" }, { "invisible_sand.active.digging.left.frames","3" }, { "invisible_sand.active.digging.left.delay", "2" }, { "invisible_sand.active.digging.left.anim_mode","linear" }, { "invisible_sand.active.digging.right", "RocksEMC.pcx" }, { "invisible_sand.active.digging.right.xpos", "9" }, { "invisible_sand.active.digging.right.ypos", "2" }, { "invisible_sand.active.digging.right.frames","3" }, { "invisible_sand.active.digging.right.delay","2" }, { "invisible_sand.active.digging.right.anim_mode","linear" }, { "invisible_sand.active.digging.up", "RocksEMC.pcx" }, { "invisible_sand.active.digging.up.xpos", "0" }, { "invisible_sand.active.digging.up.ypos", "2" }, { "invisible_sand.active.digging.up.frames", "3" }, { "invisible_sand.active.digging.up.delay", "2" }, { "invisible_sand.active.digging.up.anim_mode","linear" }, { "invisible_sand.active.digging.down", "RocksEMC.pcx" }, { "invisible_sand.active.digging.down.xpos", "3" }, { "invisible_sand.active.digging.down.ypos", "2" }, { "invisible_sand.active.digging.down.frames","3" }, { "invisible_sand.active.digging.down.delay", "2" }, { "invisible_sand.active.digging.down.anim_mode","linear" }, { "invisible_sand.active.digging.left.CRUMBLED", "RocksEMC.pcx" }, { "invisible_sand.active.digging.left.CRUMBLED.xpos", "6" }, { "invisible_sand.active.digging.left.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.left.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.left.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.left.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.right.CRUMBLED", "RocksEMC.pcx" }, { "invisible_sand.active.digging.right.CRUMBLED.xpos","9" }, { "invisible_sand.active.digging.right.CRUMBLED.ypos","3" }, { "invisible_sand.active.digging.right.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.right.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.right.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.up.CRUMBLED", "RocksEMC.pcx" }, { "invisible_sand.active.digging.up.CRUMBLED.xpos", "0" }, { "invisible_sand.active.digging.up.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.up.CRUMBLED.frames", "3" }, { "invisible_sand.active.digging.up.CRUMBLED.delay", "2" }, { "invisible_sand.active.digging.up.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.down.CRUMBLED", "RocksEMC.pcx" }, { "invisible_sand.active.digging.down.CRUMBLED.xpos", "3" }, { "invisible_sand.active.digging.down.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.down.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.down.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.down.CRUMBLED.anim_mode","linear" }, { "conveyor_belt_1_middle", "RocksDC.pcx" }, { "conveyor_belt_1_middle.xpos", "0" }, { "conveyor_belt_1_middle.ypos", "0" }, { "conveyor_belt_1_middle.frames", "1" }, { "conveyor_belt_1_middle.active", "RocksDC.pcx" }, { "conveyor_belt_1_middle.active.xpos", "0" }, { "conveyor_belt_1_middle.active.ypos", "0" }, { "conveyor_belt_1_middle.active.frames", "8" }, { "conveyor_belt_1_middle.active.delay", "2" }, { "conveyor_belt_1_left", "RocksDC.pcx" }, { "conveyor_belt_1_left.xpos", "0" }, { "conveyor_belt_1_left.ypos", "1" }, { "conveyor_belt_1_left.frames", "1" }, { "conveyor_belt_1_left.active", "RocksDC.pcx" }, { "conveyor_belt_1_left.active.xpos", "0" }, { "conveyor_belt_1_left.active.ypos", "1" }, { "conveyor_belt_1_left.active.frames", "8" }, { "conveyor_belt_1_left.active.delay", "2" }, { "conveyor_belt_1_right", "RocksDC.pcx" }, { "conveyor_belt_1_right.xpos", "0" }, { "conveyor_belt_1_right.ypos", "2" }, { "conveyor_belt_1_right.frames", "1" }, { "conveyor_belt_1_right.active", "RocksDC.pcx" }, { "conveyor_belt_1_right.active.xpos", "0" }, { "conveyor_belt_1_right.active.ypos", "2" }, { "conveyor_belt_1_right.active.frames", "8" }, { "conveyor_belt_1_right.active.delay", "2" }, { "conveyor_belt_1_switch_left", "RocksDC.pcx" }, { "conveyor_belt_1_switch_left.xpos", "0" }, { "conveyor_belt_1_switch_left.ypos", "12" }, { "conveyor_belt_1_switch_left.frames", "1" }, { "conveyor_belt_1_switch_middle", "RocksDC.pcx" }, { "conveyor_belt_1_switch_middle.xpos", "0" }, { "conveyor_belt_1_switch_middle.ypos", "13" }, { "conveyor_belt_1_switch_middle.frames", "1" }, { "conveyor_belt_1_switch_right", "RocksDC.pcx" }, { "conveyor_belt_1_switch_right.xpos", "0" }, { "conveyor_belt_1_switch_right.ypos", "14" }, { "conveyor_belt_1_switch_right.frames", "1" }, { "conveyor_belt_2_middle", "RocksDC.pcx" }, { "conveyor_belt_2_middle.xpos", "0" }, { "conveyor_belt_2_middle.ypos", "3" }, { "conveyor_belt_2_middle.frames", "1" }, { "conveyor_belt_2_middle.active", "RocksDC.pcx" }, { "conveyor_belt_2_middle.active.xpos", "0" }, { "conveyor_belt_2_middle.active.ypos", "3" }, { "conveyor_belt_2_middle.active.frames", "8" }, { "conveyor_belt_2_middle.active.delay", "2" }, { "conveyor_belt_2_left", "RocksDC.pcx" }, { "conveyor_belt_2_left.xpos", "0" }, { "conveyor_belt_2_left.ypos", "4" }, { "conveyor_belt_2_left.frames", "1" }, { "conveyor_belt_2_left.active", "RocksDC.pcx" }, { "conveyor_belt_2_left.active.xpos", "0" }, { "conveyor_belt_2_left.active.ypos", "4" }, { "conveyor_belt_2_left.active.frames", "8" }, { "conveyor_belt_2_left.active.delay", "2" }, { "conveyor_belt_2_right", "RocksDC.pcx" }, { "conveyor_belt_2_right.xpos", "0" }, { "conveyor_belt_2_right.ypos", "5" }, { "conveyor_belt_2_right.frames", "1" }, { "conveyor_belt_2_right.active", "RocksDC.pcx" }, { "conveyor_belt_2_right.active.xpos", "0" }, { "conveyor_belt_2_right.active.ypos", "5" }, { "conveyor_belt_2_right.active.frames", "8" }, { "conveyor_belt_2_right.active.delay", "2" }, { "conveyor_belt_2_switch_left", "RocksDC.pcx" }, { "conveyor_belt_2_switch_left.xpos", "1" }, { "conveyor_belt_2_switch_left.ypos", "12" }, { "conveyor_belt_2_switch_left.frames", "1" }, { "conveyor_belt_2_switch_middle", "RocksDC.pcx" }, { "conveyor_belt_2_switch_middle.xpos", "1" }, { "conveyor_belt_2_switch_middle.ypos", "13" }, { "conveyor_belt_2_switch_middle.frames", "1" }, { "conveyor_belt_2_switch_right", "RocksDC.pcx" }, { "conveyor_belt_2_switch_right.xpos", "1" }, { "conveyor_belt_2_switch_right.ypos", "14" }, { "conveyor_belt_2_switch_right.frames", "1" }, { "conveyor_belt_3_middle", "RocksDC.pcx" }, { "conveyor_belt_3_middle.xpos", "0" }, { "conveyor_belt_3_middle.ypos", "6" }, { "conveyor_belt_3_middle.frames", "1" }, { "conveyor_belt_3_middle.active", "RocksDC.pcx" }, { "conveyor_belt_3_middle.active.xpos", "0" }, { "conveyor_belt_3_middle.active.ypos", "6" }, { "conveyor_belt_3_middle.active.frames", "8" }, { "conveyor_belt_3_middle.active.delay", "2" }, { "conveyor_belt_3_left", "RocksDC.pcx" }, { "conveyor_belt_3_left.xpos", "0" }, { "conveyor_belt_3_left.ypos", "7" }, { "conveyor_belt_3_left.frames", "1" }, { "conveyor_belt_3_left.active", "RocksDC.pcx" }, { "conveyor_belt_3_left.active.xpos", "0" }, { "conveyor_belt_3_left.active.ypos", "7" }, { "conveyor_belt_3_left.active.frames", "8" }, { "conveyor_belt_3_left.active.delay", "2" }, { "conveyor_belt_3_right", "RocksDC.pcx" }, { "conveyor_belt_3_right.xpos", "0" }, { "conveyor_belt_3_right.ypos", "8" }, { "conveyor_belt_3_right.frames", "1" }, { "conveyor_belt_3_right.active", "RocksDC.pcx" }, { "conveyor_belt_3_right.active.xpos", "0" }, { "conveyor_belt_3_right.active.ypos", "8" }, { "conveyor_belt_3_right.active.frames", "8" }, { "conveyor_belt_3_right.active.delay", "2" }, { "conveyor_belt_3_switch_left", "RocksDC.pcx" }, { "conveyor_belt_3_switch_left.xpos", "2" }, { "conveyor_belt_3_switch_left.ypos", "12" }, { "conveyor_belt_3_switch_left.frames", "1" }, { "conveyor_belt_3_switch_middle", "RocksDC.pcx" }, { "conveyor_belt_3_switch_middle.xpos", "2" }, { "conveyor_belt_3_switch_middle.ypos", "13" }, { "conveyor_belt_3_switch_middle.frames", "1" }, { "conveyor_belt_3_switch_right", "RocksDC.pcx" }, { "conveyor_belt_3_switch_right.xpos", "2" }, { "conveyor_belt_3_switch_right.ypos", "14" }, { "conveyor_belt_3_switch_right.frames", "1" }, { "conveyor_belt_4_middle", "RocksDC.pcx" }, { "conveyor_belt_4_middle.xpos", "0" }, { "conveyor_belt_4_middle.ypos", "9" }, { "conveyor_belt_4_middle.frames", "1" }, { "conveyor_belt_4_middle.active", "RocksDC.pcx" }, { "conveyor_belt_4_middle.active.xpos", "0" }, { "conveyor_belt_4_middle.active.ypos", "9" }, { "conveyor_belt_4_middle.active.frames", "8" }, { "conveyor_belt_4_middle.active.delay", "2" }, { "conveyor_belt_4_left", "RocksDC.pcx" }, { "conveyor_belt_4_left.xpos", "0" }, { "conveyor_belt_4_left.ypos", "10" }, { "conveyor_belt_4_left.frames", "1" }, { "conveyor_belt_4_left.active", "RocksDC.pcx" }, { "conveyor_belt_4_left.active.xpos", "0" }, { "conveyor_belt_4_left.active.ypos", "10" }, { "conveyor_belt_4_left.active.frames", "8" }, { "conveyor_belt_4_left.active.delay", "2" }, { "conveyor_belt_4_right", "RocksDC.pcx" }, { "conveyor_belt_4_right.xpos", "0" }, { "conveyor_belt_4_right.ypos", "11" }, { "conveyor_belt_4_right.frames", "1" }, { "conveyor_belt_4_right.active", "RocksDC.pcx" }, { "conveyor_belt_4_right.active.xpos", "0" }, { "conveyor_belt_4_right.active.ypos", "11" }, { "conveyor_belt_4_right.active.frames", "8" }, { "conveyor_belt_4_right.active.delay", "2" }, { "conveyor_belt_4_switch_left", "RocksDC.pcx" }, { "conveyor_belt_4_switch_left.xpos", "3" }, { "conveyor_belt_4_switch_left.ypos", "12" }, { "conveyor_belt_4_switch_left.frames", "1" }, { "conveyor_belt_4_switch_middle", "RocksDC.pcx" }, { "conveyor_belt_4_switch_middle.xpos", "3" }, { "conveyor_belt_4_switch_middle.ypos", "13" }, { "conveyor_belt_4_switch_middle.frames", "1" }, { "conveyor_belt_4_switch_right", "RocksDC.pcx" }, { "conveyor_belt_4_switch_right.xpos", "3" }, { "conveyor_belt_4_switch_right.ypos", "14" }, { "conveyor_belt_4_switch_right.frames", "1" }, { "switchgate_switch_up", "RocksDC.pcx" }, { "switchgate_switch_up.xpos", "4" }, { "switchgate_switch_up.ypos", "12" }, { "switchgate_switch_up.frames", "1" }, { "switchgate_switch_down", "RocksDC.pcx" }, { "switchgate_switch_down.xpos", "5" }, { "switchgate_switch_down.ypos", "12" }, { "switchgate_switch_down.frames", "1" }, { "dc_switchgate_switch_up", "RocksDC2.pcx" }, { "dc_switchgate_switch_up.xpos", "10" }, { "dc_switchgate_switch_up.ypos", "1" }, { "dc_switchgate_switch_up.frames", "1" }, { "dc_switchgate_switch_down", "RocksDC2.pcx" }, { "dc_switchgate_switch_down.xpos", "11" }, { "dc_switchgate_switch_down.ypos", "1" }, { "dc_switchgate_switch_down.frames", "1" }, { "light_switch", "RocksDC.pcx" }, { "light_switch.xpos", "6" }, { "light_switch.ypos", "12" }, { "light_switch.frames", "1" }, { "light_switch.active", "RocksDC.pcx" }, { "light_switch.active.xpos", "7" }, { "light_switch.active.ypos", "12" }, { "light_switch.active.frames", "1" }, { "timegate_switch", "RocksDC.pcx" }, { "timegate_switch.xpos", "0" }, { "timegate_switch.ypos", "15" }, { "timegate_switch.frames", "1" }, { "timegate_switch.active", "RocksDC.pcx" }, { "timegate_switch.active.xpos", "0" }, { "timegate_switch.active.ypos", "15" }, { "timegate_switch.active.frames", "4" }, { "dc_timegate_switch", "RocksDC2.pcx" }, { "dc_timegate_switch.xpos", "12" }, { "dc_timegate_switch.ypos", "1" }, { "dc_timegate_switch.frames", "1" }, { "dc_timegate_switch.active", "RocksDC2.pcx" }, { "dc_timegate_switch.active.xpos", "12" }, { "dc_timegate_switch.active.ypos", "1" }, { "dc_timegate_switch.active.frames", "4" }, { "envelope_1", "RocksMore.pcx" }, { "envelope_1.xpos", "0" }, { "envelope_1.ypos", "4" }, { "envelope_1.frames", "1" }, { "envelope_1.collecting", "RocksMore.pcx" }, { "envelope_1.collecting.xpos", "5" }, { "envelope_1.collecting.ypos", "4" }, { "envelope_1.collecting.frames", "3" }, { "envelope_1.collecting.delay", "2" }, { "envelope_1.collecting.anim_mode", "linear" }, { "envelope_2", "RocksMore.pcx" }, { "envelope_2.xpos", "1" }, { "envelope_2.ypos", "4" }, { "envelope_2.frames", "1" }, { "envelope_2.collecting", "RocksMore.pcx" }, { "envelope_2.collecting.xpos", "5" }, { "envelope_2.collecting.ypos", "4" }, { "envelope_2.collecting.frames", "3" }, { "envelope_2.collecting.delay", "2" }, { "envelope_2.collecting.anim_mode", "linear" }, { "envelope_3", "RocksMore.pcx" }, { "envelope_3.xpos", "2" }, { "envelope_3.ypos", "4" }, { "envelope_3.frames", "1" }, { "envelope_3.collecting", "RocksMore.pcx" }, { "envelope_3.collecting.xpos", "5" }, { "envelope_3.collecting.ypos", "4" }, { "envelope_3.collecting.frames", "3" }, { "envelope_3.collecting.delay", "2" }, { "envelope_3.collecting.anim_mode", "linear" }, { "envelope_4", "RocksMore.pcx" }, { "envelope_4.xpos", "3" }, { "envelope_4.ypos", "4" }, { "envelope_4.frames", "1" }, { "envelope_4.collecting", "RocksMore.pcx" }, { "envelope_4.collecting.xpos", "5" }, { "envelope_4.collecting.ypos", "4" }, { "envelope_4.collecting.frames", "3" }, { "envelope_4.collecting.delay", "2" }, { "envelope_4.collecting.anim_mode", "linear" }, { "sign_radioactivity", "RocksDC.pcx" }, { "sign_radioactivity.xpos", "4" }, { "sign_radioactivity.ypos", "13" }, { "sign_radioactivity.frames", "1" }, { "sign_give_way", "RocksDC.pcx" }, { "sign_give_way.xpos", "5" }, { "sign_give_way.ypos", "13" }, { "sign_give_way.frames", "1" }, { "sign_no_entry", "RocksDC.pcx" }, { "sign_no_entry.xpos", "6" }, { "sign_no_entry.ypos", "13" }, { "sign_no_entry.frames", "1" }, { "sign_emergency_exit", "RocksDC.pcx" }, { "sign_emergency_exit.xpos", "7" }, { "sign_emergency_exit.ypos", "13" }, { "sign_emergency_exit.frames", "1" }, { "sign_yin_yang", "RocksDC.pcx" }, { "sign_yin_yang.xpos", "4" }, { "sign_yin_yang.ypos", "14" }, { "sign_yin_yang.frames", "1" }, { "sign_exclamation", "RocksDC.pcx" }, { "sign_exclamation.xpos", "5" }, { "sign_exclamation.ypos", "14" }, { "sign_exclamation.frames", "1" }, { "sign_stop", "RocksDC.pcx" }, { "sign_stop.xpos", "6" }, { "sign_stop.ypos", "14" }, { "sign_stop.frames", "1" }, { "sign_parking", "RocksDC.pcx" }, { "sign_parking.xpos", "6" }, { "sign_parking.ypos", "15" }, { "sign_parking.frames", "1" }, { "sign_wheelchair", "RocksDC.pcx" }, { "sign_wheelchair.xpos", "7" }, { "sign_wheelchair.ypos", "15" }, { "sign_wheelchair.frames", "1" }, { "sign_entry_forbidden", "RocksDC.pcx" }, { "sign_entry_forbidden.xpos", "12" }, { "sign_entry_forbidden.ypos", "15" }, { "sign_entry_forbidden.frames", "1" }, { "sperms", "RocksDC2.pcx" }, { "sperms.xpos", "11" }, { "sperms.ypos", "3" }, { "sperms.frames", "1" }, { "bullet", "RocksDC2.pcx" }, { "bullet.xpos", "12" }, { "bullet.ypos", "3" }, { "bullet.frames", "1" }, { "heart", "RocksDC2.pcx" }, { "heart.xpos", "13" }, { "heart.ypos", "3" }, { "heart.frames", "1" }, { "cross", "RocksDC2.pcx" }, { "cross.xpos", "14" }, { "cross.ypos", "3" }, { "cross.frames", "1" }, { "frankie", "RocksDC2.pcx" }, { "frankie.xpos", "15" }, { "frankie.ypos", "3" }, { "frankie.frames", "1" }, { "sign_sperms", "RocksDC2.pcx" }, { "sign_sperms.xpos", "11" }, { "sign_sperms.ypos", "2" }, { "sign_sperms.frames", "1" }, { "sign_bullet", "RocksDC2.pcx" }, { "sign_bullet.xpos", "12" }, { "sign_bullet.ypos", "2" }, { "sign_bullet.frames", "1" }, { "sign_heart", "RocksDC2.pcx" }, { "sign_heart.xpos", "13" }, { "sign_heart.ypos", "2" }, { "sign_heart.frames", "1" }, { "sign_cross", "RocksDC2.pcx" }, { "sign_cross.xpos", "14" }, { "sign_cross.ypos", "2" }, { "sign_cross.frames", "1" }, { "sign_frankie", "RocksDC2.pcx" }, { "sign_frankie.xpos", "15" }, { "sign_frankie.ypos", "2" }, { "sign_frankie.frames", "1" }, { "landmine", "RocksDC.pcx" }, { "landmine.xpos", "7" }, { "landmine.ypos", "14" }, { "landmine.frames", "1" }, { "landmine.crumbled_like", "sand" }, { "dc_landmine", "RocksDC.pcx" }, { "dc_landmine.xpos", "14" }, { "dc_landmine.ypos", "5" }, { "dc_landmine.frames", "1" }, { "dc_landmine.crumbled_like", "sand" }, { "steelwall_slippery", "RocksDC.pcx" }, { "steelwall_slippery.xpos", "5" }, { "steelwall_slippery.ypos", "15" }, { "steelwall_slippery.frames", "1" }, { "extra_time", "RocksDC.pcx" }, { "extra_time.xpos", "8" }, { "extra_time.ypos", "0" }, { "extra_time.frames", "6" }, { "extra_time.delay", "4" }, { "shield_normal", "RocksDC.pcx" }, { "shield_normal.xpos", "8" }, { "shield_normal.ypos", "2" }, { "shield_normal.frames", "6" }, { "shield_normal.delay", "4" }, { "shield_normal.active", "RocksHeroes.pcx" }, { "shield_normal.active.xpos", "1" }, { "shield_normal.active.ypos", "13" }, { "shield_normal.active.frames", "3" }, { "shield_normal.active.delay", "8" }, { "shield_normal.active.anim_mode", "pingpong" }, { "shield_deadly", "RocksDC.pcx" }, { "shield_deadly.xpos", "8" }, { "shield_deadly.ypos", "1" }, { "shield_deadly.frames", "6" }, { "shield_deadly.delay", "4" }, { "shield_deadly.active", "RocksHeroes.pcx" }, { "shield_deadly.active.xpos", "5" }, { "shield_deadly.active.ypos", "13" }, { "shield_deadly.active.frames", "3" }, { "shield_deadly.active.delay", "8" }, { "shield_deadly.active.anim_mode", "pingpong" }, { "switchgate_closed", "RocksDC.pcx" }, { "switchgate_closed.xpos", "8" }, { "switchgate_closed.ypos", "5" }, { "switchgate_closed.frames", "1" }, { "switchgate.opening", "RocksDC.pcx" }, { "switchgate.opening.xpos", "8" }, { "switchgate.opening.ypos", "5" }, { "switchgate.opening.frames", "5" }, { "switchgate.opening.delay", "6" }, { "switchgate_open", "RocksDC.pcx" }, { "switchgate_open.xpos", "12" }, { "switchgate_open.ypos", "5" }, { "switchgate_open.frames", "1" }, { "switchgate.closing", "RocksDC.pcx" }, { "switchgate.closing.xpos", "8" }, { "switchgate.closing.ypos", "5" }, { "switchgate.closing.frames", "5" }, { "switchgate.closing.delay", "6" }, { "switchgate.closing.anim_mode", "reverse" }, { "timegate_closed", "RocksDC.pcx" }, { "timegate_closed.xpos", "8" }, { "timegate_closed.ypos", "6" }, { "timegate_closed.frames", "1" }, { "timegate.opening", "RocksDC.pcx" }, { "timegate.opening.xpos", "8" }, { "timegate.opening.ypos", "6" }, { "timegate.opening.frames", "5" }, { "timegate.opening.delay", "6" }, { "timegate_open", "RocksDC.pcx" }, { "timegate_open.xpos", "12" }, { "timegate_open.ypos", "6" }, { "timegate_open.frames", "1" }, { "timegate.closing", "RocksDC.pcx" }, { "timegate.closing.xpos", "8" }, { "timegate.closing.ypos", "6" }, { "timegate.closing.frames", "5" }, { "timegate.closing.delay", "6" }, { "timegate.closing.anim_mode", "reverse" }, { "pearl", "RocksDC.pcx" }, { "pearl.xpos", "8" }, { "pearl.ypos", "11" }, { "pearl.frames", "1" }, { "pearl.breaking", "RocksDC.pcx" }, { "pearl.breaking.xpos", "8" }, { "pearl.breaking.ypos", "12" }, { "pearl.breaking.frames", "4" }, { "pearl.breaking.delay", "2" }, { "pearl.breaking.anim_mode", "linear" }, { "crystal", "RocksDC.pcx" }, { "crystal.xpos", "9" }, { "crystal.ypos", "11" }, { "crystal.frames", "1" }, { "wall_pearl", "RocksDC.pcx" }, { "wall_pearl.xpos", "10" }, { "wall_pearl.ypos", "11" }, { "wall_pearl.frames", "1" }, { "wall_crystal", "RocksDC.pcx" }, { "wall_crystal.xpos", "11" }, { "wall_crystal.ypos", "11" }, { "wall_crystal.frames", "1" }, { "dc_steelwall_1_left", "RocksDC2.pcx" }, { "dc_steelwall_1_left.xpos", "5" }, { "dc_steelwall_1_left.ypos", "1" }, { "dc_steelwall_1_left.frames", "1" }, { "dc_steelwall_1_right", "RocksDC2.pcx" }, { "dc_steelwall_1_right.xpos", "3" }, { "dc_steelwall_1_right.ypos", "1" }, { "dc_steelwall_1_right.frames", "1" }, { "dc_steelwall_1_top", "RocksDC2.pcx" }, { "dc_steelwall_1_top.xpos", "4" }, { "dc_steelwall_1_top.ypos", "2" }, { "dc_steelwall_1_top.frames", "1" }, { "dc_steelwall_1_bottom", "RocksDC2.pcx" }, { "dc_steelwall_1_bottom.xpos", "4" }, { "dc_steelwall_1_bottom.ypos", "0" }, { "dc_steelwall_1_bottom.frames", "1" }, { "dc_steelwall_1_horizontal", "RocksDC2.pcx" }, { "dc_steelwall_1_horizontal.xpos", "1" }, { "dc_steelwall_1_horizontal.ypos", "0" }, { "dc_steelwall_1_horizontal.frames", "1" }, { "dc_steelwall_1_vertical", "RocksDC2.pcx" }, { "dc_steelwall_1_vertical.xpos", "0" }, { "dc_steelwall_1_vertical.ypos", "1" }, { "dc_steelwall_1_vertical.frames", "1" }, { "dc_steelwall_1_topleft", "RocksDC2.pcx" }, { "dc_steelwall_1_topleft.xpos", "0" }, { "dc_steelwall_1_topleft.ypos", "0" }, { "dc_steelwall_1_topleft.frames", "1" }, { "dc_steelwall_1_topright", "RocksDC2.pcx" }, { "dc_steelwall_1_topright.xpos", "2" }, { "dc_steelwall_1_topright.ypos", "0" }, { "dc_steelwall_1_topright.frames", "1" }, { "dc_steelwall_1_bottomleft", "RocksDC2.pcx" }, { "dc_steelwall_1_bottomleft.xpos", "0" }, { "dc_steelwall_1_bottomleft.ypos", "2" }, { "dc_steelwall_1_bottomleft.frames", "1" }, { "dc_steelwall_1_bottomright", "RocksDC2.pcx" }, { "dc_steelwall_1_bottomright.xpos", "2" }, { "dc_steelwall_1_bottomright.ypos", "2" }, { "dc_steelwall_1_bottomright.frames", "1" }, { "dc_steelwall_1_topleft_2", "RocksDC2.pcx" }, { "dc_steelwall_1_topleft_2.xpos", "5" }, { "dc_steelwall_1_topleft_2.ypos", "2" }, { "dc_steelwall_1_topleft_2.frames", "1" }, { "dc_steelwall_1_topright_2", "RocksDC2.pcx" }, { "dc_steelwall_1_topright_2.xpos", "3" }, { "dc_steelwall_1_topright_2.ypos", "2" }, { "dc_steelwall_1_topright_2.frames", "1" }, { "dc_steelwall_1_bottomleft_2", "RocksDC2.pcx" }, { "dc_steelwall_1_bottomleft_2.xpos", "5" }, { "dc_steelwall_1_bottomleft_2.ypos", "0" }, { "dc_steelwall_1_bottomleft_2.frames", "1" }, { "dc_steelwall_1_bottomright_2", "RocksDC2.pcx" }, { "dc_steelwall_1_bottomright_2.xpos", "3" }, { "dc_steelwall_1_bottomright_2.ypos", "0" }, { "dc_steelwall_1_bottomright_2.frames", "1" }, { "dc_steelwall_2_left", "RocksDC2.pcx" }, { "dc_steelwall_2_left.xpos", "6" }, { "dc_steelwall_2_left.ypos", "1" }, { "dc_steelwall_2_left.frames", "1" }, { "dc_steelwall_2_right", "RocksDC2.pcx" }, { "dc_steelwall_2_right.xpos", "9" }, { "dc_steelwall_2_right.ypos", "1" }, { "dc_steelwall_2_right.frames", "1" }, { "dc_steelwall_2_top", "RocksDC2.pcx" }, { "dc_steelwall_2_top.xpos", "7" }, { "dc_steelwall_2_top.ypos", "0" }, { "dc_steelwall_2_top.frames", "1" }, { "dc_steelwall_2_bottom", "RocksDC2.pcx" }, { "dc_steelwall_2_bottom.xpos", "7" }, { "dc_steelwall_2_bottom.ypos", "3" }, { "dc_steelwall_2_bottom.frames", "1" }, { "dc_steelwall_2_horizontal", "RocksDC2.pcx" }, { "dc_steelwall_2_horizontal.xpos", "8" }, { "dc_steelwall_2_horizontal.ypos", "1" }, { "dc_steelwall_2_horizontal.frames", "1" }, { "dc_steelwall_2_vertical", "RocksDC2.pcx" }, { "dc_steelwall_2_vertical.xpos", "7" }, { "dc_steelwall_2_vertical.ypos", "2" }, { "dc_steelwall_2_vertical.frames", "1" }, { "dc_steelwall_2_middle", "RocksDC2.pcx" }, { "dc_steelwall_2_middle.xpos", "7" }, { "dc_steelwall_2_middle.ypos", "1" }, { "dc_steelwall_2_middle.frames", "1" }, { "dc_steelwall_2_single", "RocksDC2.pcx" }, { "dc_steelwall_2_single.xpos", "6" }, { "dc_steelwall_2_single.ypos", "0" }, { "dc_steelwall_2_single.frames", "1" }, /* images for DX Boulderdash style elements and actions */ { "tube_right_down", "RocksDC.pcx" }, { "tube_right_down.xpos", "9" }, { "tube_right_down.ypos", "13" }, { "tube_right_down.frames", "1" }, { "tube_horizontal_down", "RocksDC.pcx" }, { "tube_horizontal_down.xpos", "10" }, { "tube_horizontal_down.ypos", "13" }, { "tube_horizontal_down.frames", "1" }, { "tube_left_down", "RocksDC.pcx" }, { "tube_left_down.xpos", "11" }, { "tube_left_down.ypos", "13" }, { "tube_left_down.frames", "1" }, { "tube_horizontal", "RocksDC.pcx" }, { "tube_horizontal.xpos", "8" }, { "tube_horizontal.ypos", "14" }, { "tube_horizontal.frames", "1" }, { "tube_vertical_right", "RocksDC.pcx" }, { "tube_vertical_right.xpos", "9" }, { "tube_vertical_right.ypos", "14" }, { "tube_vertical_right.frames", "1" }, { "tube_any", "RocksDC.pcx" }, { "tube_any.xpos", "10" }, { "tube_any.ypos", "14" }, { "tube_any.frames", "1" }, { "tube_vertical_left", "RocksDC.pcx" }, { "tube_vertical_left.xpos", "11" }, { "tube_vertical_left.ypos", "14" }, { "tube_vertical_left.frames", "1" }, { "tube_vertical", "RocksDC.pcx" }, { "tube_vertical.xpos", "8" }, { "tube_vertical.ypos", "15" }, { "tube_vertical.frames", "1" }, { "tube_right_up", "RocksDC.pcx" }, { "tube_right_up.xpos", "9" }, { "tube_right_up.ypos", "15" }, { "tube_right_up.frames", "1" }, { "tube_horizontal_up", "RocksDC.pcx" }, { "tube_horizontal_up.xpos", "10" }, { "tube_horizontal_up.ypos", "15" }, { "tube_horizontal_up.frames", "1" }, { "tube_left_up", "RocksDC.pcx" }, { "tube_left_up.xpos", "11" }, { "tube_left_up.ypos", "15" }, { "tube_left_up.frames", "1" }, { "trap", "RocksDC.pcx" }, { "trap.xpos", "12" }, { "trap.ypos", "8" }, { "trap.frames", "1" }, { "trap.crumbled_like", "sand" }, { "trap.diggable_like", "sand" }, { "trap.active", "RocksDC.pcx" }, { "trap.active.xpos", "12" }, { "trap.active.ypos", "8" }, { "trap.active.frames", "4" }, { "trap.active.delay", "4" }, { "trap.active.anim_mode", "pingpong2" }, { "trap.active.crumbled_like", "sand" }, { "dx_supabomb", "RocksDC.pcx" }, { "dx_supabomb.xpos", "15" }, { "dx_supabomb.ypos", "9" }, { "dx_supabomb.frames", "1" }, /* images for Rocks'n'Diamonds style elements and actions */ { "key_1", "RocksElements.pcx" }, { "key_1.xpos", "4" }, { "key_1.ypos", "1" }, { "key_1.frames", "1" }, { "key_1.EDITOR", "RocksElements.pcx" }, { "key_1.EDITOR.xpos", "4" }, { "key_1.EDITOR.ypos", "14" }, { "key_2", "RocksElements.pcx" }, { "key_2.xpos", "5" }, { "key_2.ypos", "1" }, { "key_2.frames", "1" }, { "key_2.EDITOR", "RocksElements.pcx" }, { "key_2.EDITOR.xpos", "5" }, { "key_2.EDITOR.ypos", "14" }, { "key_3", "RocksElements.pcx" }, { "key_3.xpos", "6" }, { "key_3.ypos", "1" }, { "key_3.frames", "1" }, { "key_3.EDITOR", "RocksElements.pcx" }, { "key_3.EDITOR.xpos", "6" }, { "key_3.EDITOR.ypos", "14" }, { "key_4", "RocksElements.pcx" }, { "key_4.xpos", "7" }, { "key_4.ypos", "1" }, { "key_4.frames", "1" }, { "key_4.EDITOR", "RocksElements.pcx" }, { "key_4.EDITOR.xpos", "7" }, { "key_4.EDITOR.ypos", "14" }, { "gate_1", "RocksElements.pcx" }, { "gate_1.xpos", "4" }, { "gate_1.ypos", "2" }, { "gate_1.frames", "1" }, { "gate_2", "RocksElements.pcx" }, { "gate_2.xpos", "5" }, { "gate_2.ypos", "2" }, { "gate_2.frames", "1" }, { "gate_3", "RocksElements.pcx" }, { "gate_3.xpos", "6" }, { "gate_3.ypos", "2" }, { "gate_3.frames", "1" }, { "gate_4", "RocksElements.pcx" }, { "gate_4.xpos", "7" }, { "gate_4.ypos", "2" }, { "gate_4.frames", "1" }, { "gate_1_gray", "RocksElements.pcx" }, { "gate_1_gray.xpos", "8" }, { "gate_1_gray.ypos", "2" }, { "gate_1_gray.frames", "1" }, { "gate_1_gray.EDITOR", "RocksElements.pcx" }, { "gate_1_gray.EDITOR.xpos", "8" }, { "gate_1_gray.EDITOR.ypos", "14" }, { "gate_1_gray.active", "RocksElements.pcx" }, { "gate_1_gray.active.xpos", "4" }, { "gate_1_gray.active.ypos", "2" }, { "gate_1_gray.active.frames", "1" }, { "gate_2_gray", "RocksElements.pcx" }, { "gate_2_gray.xpos", "9" }, { "gate_2_gray.ypos", "2" }, { "gate_2_gray.frames", "1" }, { "gate_2_gray.EDITOR", "RocksElements.pcx" }, { "gate_2_gray.EDITOR.xpos", "9" }, { "gate_2_gray.EDITOR.ypos", "14" }, { "gate_2_gray.active", "RocksElements.pcx" }, { "gate_2_gray.active.xpos", "5" }, { "gate_2_gray.active.ypos", "2" }, { "gate_2_gray.active.frames", "1" }, { "gate_3_gray", "RocksElements.pcx" }, { "gate_3_gray.xpos", "10" }, { "gate_3_gray.ypos", "2" }, { "gate_3_gray.frames", "1" }, { "gate_3_gray.EDITOR", "RocksElements.pcx" }, { "gate_3_gray.EDITOR.xpos", "10" }, { "gate_3_gray.EDITOR.ypos", "14" }, { "gate_3_gray.active", "RocksElements.pcx" }, { "gate_3_gray.active.xpos", "6" }, { "gate_3_gray.active.ypos", "2" }, { "gate_3_gray.active.frames", "1" }, { "gate_4_gray", "RocksElements.pcx" }, { "gate_4_gray.xpos", "11" }, { "gate_4_gray.ypos", "2" }, { "gate_4_gray.frames", "1" }, { "gate_4_gray.EDITOR", "RocksElements.pcx" }, { "gate_4_gray.EDITOR.xpos", "11" }, { "gate_4_gray.EDITOR.ypos", "14" }, { "gate_4_gray.active", "RocksElements.pcx" }, { "gate_4_gray.active.xpos", "7" }, { "gate_4_gray.active.ypos", "2" }, { "gate_4_gray.active.frames", "1" }, { "game_of_life", "RocksElements.pcx" }, { "game_of_life.xpos", "8" }, { "game_of_life.ypos", "1" }, { "game_of_life.frames", "1" }, { "biomaze", "RocksElements.pcx" }, { "biomaze.xpos", "9" }, { "biomaze.ypos", "1" }, { "biomaze.frames", "1" }, { "pacman", "RocksElements.pcx" }, { "pacman.xpos", "8" }, { "pacman.ypos", "5" }, { "pacman.frames", "1" }, { "pacman.right", "RocksElements.pcx" }, { "pacman.right.xpos", "8" }, { "pacman.right.ypos", "5" }, { "pacman.right.frames", "2" }, { "pacman.right.delay", "4" }, { "pacman.right.offset", "128" }, { "pacman.up", "RocksElements.pcx" }, { "pacman.up.xpos", "9" }, { "pacman.up.ypos", "5" }, { "pacman.up.frames", "2" }, { "pacman.up.delay", "4" }, { "pacman.up.offset", "128" }, { "pacman.left", "RocksElements.pcx" }, { "pacman.left.xpos", "10" }, { "pacman.left.ypos", "5" }, { "pacman.left.frames", "2" }, { "pacman.left.delay", "4" }, { "pacman.left.offset", "128" }, { "pacman.down", "RocksElements.pcx" }, { "pacman.down.xpos", "11" }, { "pacman.down.ypos", "5" }, { "pacman.down.frames", "2" }, { "pacman.down.delay", "4" }, { "pacman.down.offset", "128" }, { "pacman.turning_from_right", "RocksElements.pcx" }, { "pacman.turning_from_right.xpos", "12" }, { "pacman.turning_from_right.ypos", "5" }, { "pacman.turning_from_right.frames", "1" }, { "pacman.turning_from_up", "RocksElements.pcx" }, { "pacman.turning_from_up.xpos", "13" }, { "pacman.turning_from_up.ypos", "5" }, { "pacman.turning_from_up.frames", "1" }, { "pacman.turning_from_left", "RocksElements.pcx" }, { "pacman.turning_from_left.xpos", "14" }, { "pacman.turning_from_left.ypos", "5" }, { "pacman.turning_from_left.frames", "1" }, { "pacman.turning_from_down", "RocksElements.pcx" }, { "pacman.turning_from_down.xpos", "15" }, { "pacman.turning_from_down.ypos", "5" }, { "pacman.turning_from_down.frames", "1" }, { "lamp", "RocksElements.pcx" }, { "lamp.xpos", "0" }, { "lamp.ypos", "7" }, { "lamp.frames", "1" }, { "lamp.EDITOR", "RocksElements.pcx" }, { "lamp.EDITOR.xpos", "2" }, { "lamp.EDITOR.ypos", "14" }, { "lamp.active", "RocksElements.pcx" }, { "lamp.active.xpos", "1" }, { "lamp.active.ypos", "7" }, { "lamp.active.frames", "1" }, { "time_orb_full", "RocksElements.pcx" }, { "time_orb_full.xpos", "2" }, { "time_orb_full.ypos", "7" }, { "time_orb_full.frames", "1" }, { "time_orb_empty", "RocksElements.pcx" }, { "time_orb_empty.xpos", "3" }, { "time_orb_empty.ypos", "7" }, { "time_orb_empty.frames", "1" }, { "emerald_yellow", "RocksElements.pcx" }, { "emerald_yellow.xpos", "10" }, { "emerald_yellow.ypos", "8" }, { "emerald_yellow.frames", "1" }, { "emerald_yellow.moving", "RocksElements.pcx" }, { "emerald_yellow.moving.xpos", "10" }, { "emerald_yellow.moving.ypos", "8" }, { "emerald_yellow.moving.frames", "2" }, { "emerald_yellow.moving.delay", "4" }, { "emerald_yellow.falling", "RocksElements.pcx" }, { "emerald_yellow.falling.xpos", "10" }, { "emerald_yellow.falling.ypos", "8" }, { "emerald_yellow.falling.frames", "2" }, { "emerald_yellow.falling.delay", "4" }, { "emerald_red", "RocksElements.pcx" }, { "emerald_red.xpos", "8" }, { "emerald_red.ypos", "9" }, { "emerald_red.frames", "1" }, { "emerald_red.moving", "RocksElements.pcx" }, { "emerald_red.moving.xpos", "8" }, { "emerald_red.moving.ypos", "9" }, { "emerald_red.moving.frames", "2" }, { "emerald_red.moving.delay", "4" }, { "emerald_red.falling", "RocksElements.pcx" }, { "emerald_red.falling.xpos", "8" }, { "emerald_red.falling.ypos", "9" }, { "emerald_red.falling.frames", "2" }, { "emerald_red.falling.delay", "4" }, { "emerald_purple", "RocksElements.pcx" }, { "emerald_purple.xpos", "10" }, { "emerald_purple.ypos", "9" }, { "emerald_purple.frames", "1" }, { "emerald_purple.moving", "RocksElements.pcx" }, { "emerald_purple.moving.xpos", "10" }, { "emerald_purple.moving.ypos", "9" }, { "emerald_purple.moving.frames", "2" }, { "emerald_purple.moving.delay", "4" }, { "emerald_purple.falling", "RocksElements.pcx" }, { "emerald_purple.falling.xpos", "10" }, { "emerald_purple.falling.ypos", "9" }, { "emerald_purple.falling.frames", "2" }, { "emerald_purple.falling.delay", "4" }, { "wall_emerald_yellow", "RocksElements.pcx" }, { "wall_emerald_yellow.xpos", "8" }, { "wall_emerald_yellow.ypos", "8" }, { "wall_emerald_yellow.frames", "1" }, { "wall_emerald_red", "RocksElements.pcx" }, { "wall_emerald_red.xpos", "6" }, { "wall_emerald_red.ypos", "8" }, { "wall_emerald_red.frames", "1" }, { "wall_emerald_purple", "RocksElements.pcx" }, { "wall_emerald_purple.xpos", "7" }, { "wall_emerald_purple.ypos", "8" }, { "wall_emerald_purple.frames", "1" }, { "wall_bd_diamond", "RocksElements.pcx" }, { "wall_bd_diamond.xpos", "9" }, { "wall_bd_diamond.ypos", "8" }, { "wall_bd_diamond.frames", "1" }, { "expandable_wall", "RocksElements.pcx" }, { "expandable_wall.xpos", "11" }, { "expandable_wall.ypos", "10" }, { "expandable_wall.frames", "1" }, { "expandable_wall_horizontal", "RocksElements.pcx" }, { "expandable_wall_horizontal.xpos", "5" }, { "expandable_wall_horizontal.ypos", "9" }, { "expandable_wall_horizontal.frames", "1" }, { "expandable_wall_horizontal.EDITOR", "RocksElements.pcx" }, { "expandable_wall_horizontal.EDITOR.xpos", "13" }, { "expandable_wall_horizontal.EDITOR.ypos", "13" }, { "expandable_wall_vertical", "RocksElements.pcx" }, { "expandable_wall_vertical.xpos", "6" }, { "expandable_wall_vertical.ypos", "9" }, { "expandable_wall_vertical.frames", "1" }, { "expandable_wall_vertical.EDITOR", "RocksElements.pcx" }, { "expandable_wall_vertical.EDITOR.xpos", "14" }, { "expandable_wall_vertical.EDITOR.ypos", "13" }, { "expandable_wall_any", "RocksElements.pcx" }, { "expandable_wall_any.xpos", "4" }, { "expandable_wall_any.ypos", "9" }, { "expandable_wall_any.frames", "1" }, { "expandable_wall_any.EDITOR", "RocksElements.pcx" }, { "expandable_wall_any.EDITOR.xpos", "12" }, { "expandable_wall_any.EDITOR.ypos", "13" }, { "expandable_steelwall_horizontal", "RocksDC2.pcx" }, { "expandable_steelwall_horizontal.xpos", "6" }, { "expandable_steelwall_horizontal.ypos", "2" }, { "expandable_steelwall_horizontal.frames", "1" }, { "expandable_steelwall_horizontal.EDITOR", "RocksDC2.pcx" }, { "expandable_steelwall_horizontal.EDITOR.xpos","9" }, { "expandable_steelwall_horizontal.EDITOR.ypos","2" }, { "expandable_steelwall_vertical", "RocksDC2.pcx" }, { "expandable_steelwall_vertical.xpos", "6" }, { "expandable_steelwall_vertical.ypos", "2" }, { "expandable_steelwall_vertical.frames", "1" }, { "expandable_steelwall_vertical.EDITOR", "RocksDC2.pcx" }, { "expandable_steelwall_vertical.EDITOR.xpos","10" }, { "expandable_steelwall_vertical.EDITOR.ypos","2" }, { "expandable_steelwall_any", "RocksDC2.pcx" }, { "expandable_steelwall_any.xpos", "6" }, { "expandable_steelwall_any.ypos", "2" }, { "expandable_steelwall_any.frames", "1" }, { "expandable_steelwall_any.EDITOR", "RocksDC2.pcx" }, { "expandable_steelwall_any.EDITOR.xpos", "8" }, { "expandable_steelwall_any.EDITOR.ypos", "2" }, { "bd_expandable_wall", "RocksElements.pcx" }, { "bd_expandable_wall.xpos", "5" }, { "bd_expandable_wall.ypos", "9" }, { "bd_expandable_wall.frames", "1" }, { "bd_expandable_wall.EDITOR", "RocksDC.pcx" }, { "bd_expandable_wall.EDITOR.xpos", "15" }, { "bd_expandable_wall.EDITOR.ypos", "15" }, { "expandable_wall.growing.left", "RocksElements.pcx" }, { "expandable_wall.growing.left.xpos", "8" }, { "expandable_wall.growing.left.ypos", "10" }, { "expandable_wall.growing.left.frames", "3" }, { "expandable_wall.growing.left.delay", "6" }, { "expandable_wall.growing.left.anim_mode", "linear" }, { "expandable_wall.growing.right", "RocksElements.pcx" }, { "expandable_wall.growing.right.xpos", "5" }, { "expandable_wall.growing.right.ypos", "10" }, { "expandable_wall.growing.right.frames", "3" }, { "expandable_wall.growing.right.delay", "6" }, { "expandable_wall.growing.right.anim_mode", "linear" }, { "expandable_wall.growing.up", "RocksHeroes.pcx" }, { "expandable_wall.growing.up.xpos", "3" }, { "expandable_wall.growing.up.ypos", "12" }, { "expandable_wall.growing.up.frames", "3" }, { "expandable_wall.growing.up.delay", "6" }, { "expandable_wall.growing.up.anim_mode", "linear" }, { "expandable_wall.growing.down", "RocksHeroes.pcx" }, { "expandable_wall.growing.down.xpos", "0" }, { "expandable_wall.growing.down.ypos", "12" }, { "expandable_wall.growing.down.frames", "3" }, { "expandable_wall.growing.down.delay", "6" }, { "expandable_wall.growing.down.anim_mode", "linear" }, { "expandable_steelwall.growing.left", "RocksDC2.pcx" }, { "expandable_steelwall.growing.left.xpos", "8" }, { "expandable_steelwall.growing.left.ypos", "4" }, { "expandable_steelwall.growing.left.frames", "4" }, { "expandable_steelwall.growing.left.delay", "4" }, { "expandable_steelwall.growing.left.anim_mode","linear" }, { "expandable_steelwall.growing.right", "RocksDC2.pcx" }, { "expandable_steelwall.growing.right.xpos", "12" }, { "expandable_steelwall.growing.right.ypos", "4" }, { "expandable_steelwall.growing.right.frames","4" }, { "expandable_steelwall.growing.right.delay", "4" }, { "expandable_steelwall.growing.right.anim_mode","linear" }, { "expandable_steelwall.growing.up", "RocksDC2.pcx" }, { "expandable_steelwall.growing.up.xpos", "8" }, { "expandable_steelwall.growing.up.ypos", "5" }, { "expandable_steelwall.growing.up.frames", "4" }, { "expandable_steelwall.growing.up.delay", "4" }, { "expandable_steelwall.growing.up.anim_mode","linear" }, { "expandable_steelwall.growing.down", "RocksDC2.pcx" }, { "expandable_steelwall.growing.down.xpos", "12" }, { "expandable_steelwall.growing.down.ypos", "5" }, { "expandable_steelwall.growing.down.frames", "4" }, { "expandable_steelwall.growing.down.delay", "4" }, { "expandable_steelwall.growing.down.anim_mode","linear" }, { "black_orb", "RocksElements.pcx" }, { "black_orb.xpos", "13" }, { "black_orb.ypos", "9" }, { "black_orb.frames", "1" }, { "speed_pill", "RocksElements.pcx" }, { "speed_pill.xpos", "14" }, { "speed_pill.ypos", "9" }, { "speed_pill.frames", "1" }, { "dark_yamyam", "RocksElements.pcx" }, { "dark_yamyam.xpos", "8" }, { "dark_yamyam.ypos", "11" }, { "dark_yamyam.frames", "4" }, { "dark_yamyam.anim_mode", "pingpong2" }, { "dynabomb", "RocksElements.pcx" }, { "dynabomb.xpos", "12" }, { "dynabomb.ypos", "11" }, { "dynabomb.frames", "1" }, { "dynabomb.active", "RocksElements.pcx" }, { "dynabomb.active.xpos", "12" }, { "dynabomb.active.ypos", "11" }, { "dynabomb.active.frames", "4" }, { "dynabomb.active.delay", "6" }, { "dynabomb.active.anim_mode", "pingpong" }, { "dynabomb_player_1", "RocksElements.pcx" }, { "dynabomb_player_1.xpos", "12" }, { "dynabomb_player_1.ypos", "11" }, { "dynabomb_player_1.frames", "1" }, { "dynabomb_player_1.active", "RocksElements.pcx" }, { "dynabomb_player_1.active.xpos", "12" }, { "dynabomb_player_1.active.ypos", "11" }, { "dynabomb_player_1.active.frames", "4" }, { "dynabomb_player_1.active.delay", "6" }, { "dynabomb_player_1.active.anim_mode", "pingpong" }, { "dynabomb_player_2", "RocksElements.pcx" }, { "dynabomb_player_2.xpos", "12" }, { "dynabomb_player_2.ypos", "11" }, { "dynabomb_player_2.frames", "1" }, { "dynabomb_player_2.active", "RocksElements.pcx" }, { "dynabomb_player_2.active.xpos", "12" }, { "dynabomb_player_2.active.ypos", "11" }, { "dynabomb_player_2.active.frames", "4" }, { "dynabomb_player_2.active.delay", "6" }, { "dynabomb_player_2.active.anim_mode", "pingpong" }, { "dynabomb_player_3", "RocksElements.pcx" }, { "dynabomb_player_3.xpos", "12" }, { "dynabomb_player_3.ypos", "11" }, { "dynabomb_player_3.frames", "1" }, { "dynabomb_player_3.active", "RocksElements.pcx" }, { "dynabomb_player_3.active.xpos", "12" }, { "dynabomb_player_3.active.ypos", "11" }, { "dynabomb_player_3.active.frames", "4" }, { "dynabomb_player_3.active.delay", "6" }, { "dynabomb_player_3.active.anim_mode", "pingpong" }, { "dynabomb_player_4", "RocksElements.pcx" }, { "dynabomb_player_4.xpos", "12" }, { "dynabomb_player_4.ypos", "11" }, { "dynabomb_player_4.frames", "1" }, { "dynabomb_player_4.active", "RocksElements.pcx" }, { "dynabomb_player_4.active.xpos", "12" }, { "dynabomb_player_4.active.ypos", "11" }, { "dynabomb_player_4.active.frames", "4" }, { "dynabomb_player_4.active.delay", "6" }, { "dynabomb_player_4.active.anim_mode", "pingpong" }, { "dynabomb_increase_number", "RocksElements.pcx" }, { "dynabomb_increase_number.xpos", "12" }, { "dynabomb_increase_number.ypos", "11" }, { "dynabomb_increase_number.frames", "1" }, { "dynabomb_increase_size", "RocksElements.pcx" }, { "dynabomb_increase_size.xpos", "15" }, { "dynabomb_increase_size.ypos", "11" }, { "dynabomb_increase_size.frames", "1" }, { "dynabomb_increase_power", "RocksElements.pcx" }, { "dynabomb_increase_power.xpos", "12" }, { "dynabomb_increase_power.ypos", "9" }, { "dynabomb_increase_power.frames", "1" }, { "pig", "RocksHeroes.pcx" }, { "pig.xpos", "8" }, { "pig.ypos", "0" }, { "pig.frames", "1" }, { "pig.down", "RocksHeroes.pcx" }, { "pig.down.xpos", "8" }, { "pig.down.ypos", "0" }, { "pig.down.frames", "1" }, { "pig.up", "RocksHeroes.pcx" }, { "pig.up.xpos", "12" }, { "pig.up.ypos", "0" }, { "pig.up.frames", "1" }, { "pig.left", "RocksHeroes.pcx" }, { "pig.left.xpos", "8" }, { "pig.left.ypos", "1" }, { "pig.left.frames", "1" }, { "pig.right", "RocksHeroes.pcx" }, { "pig.right.xpos", "12" }, { "pig.right.ypos", "1" }, { "pig.right.frames", "1" }, { "pig.moving.down", "RocksHeroes.pcx" }, { "pig.moving.down.xpos", "8" }, { "pig.moving.down.ypos", "0" }, { "pig.moving.down.frames", "4" }, { "pig.moving.down.delay", "2" }, { "pig.moving.up", "RocksHeroes.pcx" }, { "pig.moving.up.xpos", "12" }, { "pig.moving.up.ypos", "0" }, { "pig.moving.up.frames", "4" }, { "pig.moving.up.delay", "2" }, { "pig.moving.left", "RocksHeroes.pcx" }, { "pig.moving.left.xpos", "8" }, { "pig.moving.left.ypos", "1" }, { "pig.moving.left.frames", "4" }, { "pig.moving.left.delay", "2" }, { "pig.moving.right", "RocksHeroes.pcx" }, { "pig.moving.right.xpos", "12" }, { "pig.moving.right.ypos", "1" }, { "pig.moving.right.frames", "4" }, { "pig.moving.right.delay", "2" }, { "pig.digging.down", "RocksHeroes.pcx" }, { "pig.digging.down.xpos", "8" }, { "pig.digging.down.ypos", "0" }, { "pig.digging.down.frames", "4" }, { "pig.digging.down.delay", "2" }, { "pig.digging.up", "RocksHeroes.pcx" }, { "pig.digging.up.xpos", "12" }, { "pig.digging.up.ypos", "0" }, { "pig.digging.up.frames", "4" }, { "pig.digging.up.delay", "2" }, { "pig.digging.left", "RocksHeroes.pcx" }, { "pig.digging.left.xpos", "8" }, { "pig.digging.left.ypos", "1" }, { "pig.digging.left.frames", "4" }, { "pig.digging.left.delay", "2" }, { "pig.digging.right", "RocksHeroes.pcx" }, { "pig.digging.right.xpos", "12" }, { "pig.digging.right.ypos", "1" }, { "pig.digging.right.frames", "4" }, { "pig.digging.right.delay", "2" }, { "dragon", "RocksHeroes.pcx" }, { "dragon.xpos", "8" }, { "dragon.ypos", "2" }, { "dragon.frames", "1" }, { "dragon.down", "RocksHeroes.pcx" }, { "dragon.down.xpos", "8" }, { "dragon.down.ypos", "2" }, { "dragon.down.frames", "1" }, { "dragon.up", "RocksHeroes.pcx" }, { "dragon.up.xpos", "12" }, { "dragon.up.ypos", "2" }, { "dragon.up.frames", "1" }, { "dragon.left", "RocksHeroes.pcx" }, { "dragon.left.xpos", "8" }, { "dragon.left.ypos", "3" }, { "dragon.left.frames", "1" }, { "dragon.right", "RocksHeroes.pcx" }, { "dragon.right.xpos", "12" }, { "dragon.right.ypos", "3" }, { "dragon.right.frames", "1" }, { "dragon.moving.down", "RocksHeroes.pcx" }, { "dragon.moving.down.xpos", "8" }, { "dragon.moving.down.ypos", "2" }, { "dragon.moving.down.frames", "4" }, { "dragon.moving.down.delay", "2" }, { "dragon.moving.up", "RocksHeroes.pcx" }, { "dragon.moving.up.xpos", "12" }, { "dragon.moving.up.ypos", "2" }, { "dragon.moving.up.frames", "4" }, { "dragon.moving.up.delay", "2" }, { "dragon.moving.left", "RocksHeroes.pcx" }, { "dragon.moving.left.xpos", "8" }, { "dragon.moving.left.ypos", "3" }, { "dragon.moving.left.frames", "4" }, { "dragon.moving.left.delay", "2" }, { "dragon.moving.right", "RocksHeroes.pcx" }, { "dragon.moving.right.xpos", "12" }, { "dragon.moving.right.ypos", "3" }, { "dragon.moving.right.frames", "4" }, { "dragon.moving.right.delay", "2" }, { "dragon.attacking.down", "RocksHeroes.pcx" }, { "dragon.attacking.down.xpos", "8" }, { "dragon.attacking.down.ypos", "2" }, { "dragon.attacking.down.frames", "1" }, { "dragon.attacking.up", "RocksHeroes.pcx" }, { "dragon.attacking.up.xpos", "12" }, { "dragon.attacking.up.ypos", "2" }, { "dragon.attacking.up.frames", "1" }, { "dragon.attacking.left", "RocksHeroes.pcx" }, { "dragon.attacking.left.xpos", "8" }, { "dragon.attacking.left.ypos", "3" }, { "dragon.attacking.left.frames", "1" }, { "dragon.attacking.right", "RocksHeroes.pcx" }, { "dragon.attacking.right.xpos", "12" }, { "dragon.attacking.right.ypos", "3" }, { "dragon.attacking.right.frames", "1" }, { "mole", "RocksHeroes.pcx" }, { "mole.xpos", "8" }, { "mole.ypos", "4" }, { "mole.frames", "1" }, { "mole.down", "RocksHeroes.pcx" }, { "mole.down.xpos", "8" }, { "mole.down.ypos", "4" }, { "mole.down.frames", "1" }, { "mole.up", "RocksHeroes.pcx" }, { "mole.up.xpos", "12" }, { "mole.up.ypos", "4" }, { "mole.up.frames", "1" }, { "mole.left", "RocksHeroes.pcx" }, { "mole.left.xpos", "8" }, { "mole.left.ypos", "5" }, { "mole.left.frames", "1" }, { "mole.right", "RocksHeroes.pcx" }, { "mole.right.xpos", "12" }, { "mole.right.ypos", "5" }, { "mole.right.frames", "1" }, { "mole.moving.down", "RocksHeroes.pcx" }, { "mole.moving.down.xpos", "8" }, { "mole.moving.down.ypos", "4" }, { "mole.moving.down.frames", "4" }, { "mole.moving.down.delay", "2" }, { "mole.moving.up", "RocksHeroes.pcx" }, { "mole.moving.up.xpos", "12" }, { "mole.moving.up.ypos", "4" }, { "mole.moving.up.frames", "4" }, { "mole.moving.up.delay", "2" }, { "mole.moving.left", "RocksHeroes.pcx" }, { "mole.moving.left.xpos", "8" }, { "mole.moving.left.ypos", "5" }, { "mole.moving.left.frames", "4" }, { "mole.moving.left.delay", "2" }, { "mole.moving.right", "RocksHeroes.pcx" }, { "mole.moving.right.xpos", "12" }, { "mole.moving.right.ypos", "5" }, { "mole.moving.right.frames", "4" }, { "mole.moving.right.delay", "2" }, { "mole.digging.down", "RocksHeroes.pcx" }, { "mole.digging.down.xpos", "8" }, { "mole.digging.down.ypos", "4" }, { "mole.digging.down.frames", "4" }, { "mole.digging.down.delay", "2" }, { "mole.digging.up", "RocksHeroes.pcx" }, { "mole.digging.up.xpos", "12" }, { "mole.digging.up.ypos", "4" }, { "mole.digging.up.frames", "4" }, { "mole.digging.up.delay", "2" }, { "mole.digging.left", "RocksHeroes.pcx" }, { "mole.digging.left.xpos", "8" }, { "mole.digging.left.ypos", "5" }, { "mole.digging.left.frames", "4" }, { "mole.digging.left.delay", "2" }, { "mole.digging.right", "RocksHeroes.pcx" }, { "mole.digging.right.xpos", "12" }, { "mole.digging.right.ypos", "5" }, { "mole.digging.right.frames", "4" }, { "mole.digging.right.delay", "2" }, { "penguin", "RocksHeroes.pcx" }, { "penguin.xpos", "8" }, { "penguin.ypos", "6" }, { "penguin.frames", "1" }, { "penguin.EDITOR", "RocksElements.pcx" }, { "penguin.EDITOR.xpos", "12" }, { "penguin.EDITOR.ypos", "14" }, { "penguin.down", "RocksHeroes.pcx" }, { "penguin.down.xpos", "8" }, { "penguin.down.ypos", "6" }, { "penguin.down.frames", "1" }, { "penguin.up", "RocksHeroes.pcx" }, { "penguin.up.xpos", "12" }, { "penguin.up.ypos", "6" }, { "penguin.up.frames", "1" }, { "penguin.left", "RocksHeroes.pcx" }, { "penguin.left.xpos", "8" }, { "penguin.left.ypos", "7" }, { "penguin.left.frames", "1" }, { "penguin.right", "RocksHeroes.pcx" }, { "penguin.right.xpos", "12" }, { "penguin.right.ypos", "7" }, { "penguin.right.frames", "1" }, { "penguin.moving.down", "RocksHeroes.pcx" }, { "penguin.moving.down.xpos", "8" }, { "penguin.moving.down.ypos", "6" }, { "penguin.moving.down.frames", "4" }, { "penguin.moving.down.delay", "2" }, { "penguin.moving.up", "RocksHeroes.pcx" }, { "penguin.moving.up.xpos", "12" }, { "penguin.moving.up.ypos", "6" }, { "penguin.moving.up.frames", "4" }, { "penguin.moving.up.delay", "2" }, { "penguin.moving.left", "RocksHeroes.pcx" }, { "penguin.moving.left.xpos", "8" }, { "penguin.moving.left.ypos", "7" }, { "penguin.moving.left.frames", "4" }, { "penguin.moving.left.delay", "2" }, { "penguin.moving.right", "RocksHeroes.pcx" }, { "penguin.moving.right.xpos", "12" }, { "penguin.moving.right.ypos", "7" }, { "penguin.moving.right.frames", "4" }, { "penguin.moving.right.delay", "2" }, { "satellite", "RocksHeroes.pcx" }, { "satellite.xpos", "8" }, { "satellite.ypos", "9" }, { "satellite.frames", "8" }, { "satellite.delay", "2" }, { "satellite.global_sync", "true" }, { "flames_1_left", "RocksHeroes.pcx" }, { "flames_1_left.xpos", "8" }, { "flames_1_left.ypos", "12" }, { "flames_1_left.frames", "2" }, { "flames_1_left.offset", "96" }, { "flames_2_left", "RocksHeroes.pcx" }, { "flames_2_left.xpos", "9" }, { "flames_2_left.ypos", "12" }, { "flames_2_left.frames", "2" }, { "flames_2_left.offset", "96" }, { "flames_3_left", "RocksHeroes.pcx" }, { "flames_3_left.xpos", "10" }, { "flames_3_left.ypos", "12" }, { "flames_3_left.frames", "2" }, { "flames_3_left.offset", "96" }, { "flames_1_right", "RocksHeroes.pcx" }, { "flames_1_right.xpos", "8" }, { "flames_1_right.ypos", "13" }, { "flames_1_right.frames", "2" }, { "flames_1_right.offset", "96" }, { "flames_2_right", "RocksHeroes.pcx" }, { "flames_2_right.xpos", "9" }, { "flames_2_right.ypos", "13" }, { "flames_2_right.frames", "2" }, { "flames_2_right.offset", "96" }, { "flames_3_right", "RocksHeroes.pcx" }, { "flames_3_right.xpos", "10" }, { "flames_3_right.ypos", "13" }, { "flames_3_right.frames", "2" }, { "flames_3_right.offset", "96" }, { "flames_1_up", "RocksHeroes.pcx" }, { "flames_1_up.xpos", "8" }, { "flames_1_up.ypos", "14" }, { "flames_1_up.frames", "2" }, { "flames_1_up.offset", "96" }, { "flames_2_up", "RocksHeroes.pcx" }, { "flames_2_up.xpos", "9" }, { "flames_2_up.ypos", "14" }, { "flames_2_up.frames", "2" }, { "flames_2_up.offset", "96" }, { "flames_3_up", "RocksHeroes.pcx" }, { "flames_3_up.xpos", "10" }, { "flames_3_up.ypos", "14" }, { "flames_3_up.frames", "2" }, { "flames_3_up.offset", "96" }, { "flames_1_down", "RocksHeroes.pcx" }, { "flames_1_down.xpos", "8" }, { "flames_1_down.ypos", "15" }, { "flames_1_down.frames", "2" }, { "flames_1_down.offset", "96" }, { "flames_2_down", "RocksHeroes.pcx" }, { "flames_2_down.xpos", "9" }, { "flames_2_down.ypos", "15" }, { "flames_2_down.frames", "2" }, { "flames_2_down.offset", "96" }, { "flames_3_down", "RocksHeroes.pcx" }, { "flames_3_down.xpos", "10" }, { "flames_3_down.ypos", "15" }, { "flames_3_down.frames", "2" }, { "flames_3_down.offset", "96" }, { "stoneblock", "RocksElements.pcx" }, { "stoneblock.xpos", "10" }, { "stoneblock.ypos", "1" }, { "stoneblock.frames", "1" }, /* images for other elements and actions */ { "player_1", "RocksHeroes.pcx" }, { "player_1.xpos", "0" }, { "player_1.ypos", "0" }, { "player_1.frames", "1" }, { "player_1.EDITOR", "RocksElements.pcx" }, { "player_1.EDITOR.xpos", "4" }, { "player_1.EDITOR.ypos", "7" }, { "player_1.down", "RocksHeroes.pcx" }, { "player_1.down.xpos", "0" }, { "player_1.down.ypos", "0" }, { "player_1.down.frames", "1" }, { "player_1.up", "RocksHeroes.pcx" }, { "player_1.up.xpos", "4" }, { "player_1.up.ypos", "0" }, { "player_1.up.frames", "1" }, { "player_1.left", "RocksHeroes.pcx" }, { "player_1.left.xpos", "0" }, { "player_1.left.ypos", "1" }, { "player_1.left.frames", "1" }, { "player_1.right", "RocksHeroes.pcx" }, { "player_1.right.xpos", "4" }, { "player_1.right.ypos", "1" }, { "player_1.right.frames", "1" }, { "player_1.moving.down", "RocksHeroes.pcx" }, { "player_1.moving.down.xpos", "0" }, { "player_1.moving.down.ypos", "0" }, { "player_1.moving.down.frames", "4" }, { "player_1.moving.down.start_frame", "1" }, { "player_1.moving.down.delay", "4" }, { "player_1.moving.up", "RocksHeroes.pcx" }, { "player_1.moving.up.xpos", "4" }, { "player_1.moving.up.ypos", "0" }, { "player_1.moving.up.frames", "4" }, { "player_1.moving.up.start_frame", "1" }, { "player_1.moving.up.delay", "4" }, { "player_1.moving.left", "RocksHeroes.pcx" }, { "player_1.moving.left.xpos", "0" }, { "player_1.moving.left.ypos", "1" }, { "player_1.moving.left.frames", "4" }, { "player_1.moving.left.start_frame", "1" }, { "player_1.moving.left.delay", "4" }, { "player_1.moving.right", "RocksHeroes.pcx" }, { "player_1.moving.right.xpos", "4" }, { "player_1.moving.right.ypos", "1" }, { "player_1.moving.right.frames", "4" }, { "player_1.moving.right.start_frame", "1" }, { "player_1.moving.right.delay", "4" }, { "player_1.digging.down", "RocksHeroes.pcx" }, { "player_1.digging.down.xpos", "0" }, { "player_1.digging.down.ypos", "0" }, { "player_1.digging.down.frames", "4" }, { "player_1.digging.down.start_frame", "1" }, { "player_1.digging.down.delay", "4" }, { "player_1.digging.up", "RocksHeroes.pcx" }, { "player_1.digging.up.xpos", "4" }, { "player_1.digging.up.ypos", "0" }, { "player_1.digging.up.frames", "4" }, { "player_1.digging.up.start_frame", "1" }, { "player_1.digging.up.delay", "4" }, { "player_1.digging.left", "RocksHeroes.pcx" }, { "player_1.digging.left.xpos", "0" }, { "player_1.digging.left.ypos", "1" }, { "player_1.digging.left.frames", "4" }, { "player_1.digging.left.start_frame", "1" }, { "player_1.digging.left.delay", "4" }, { "player_1.digging.right", "RocksHeroes.pcx" }, { "player_1.digging.right.xpos", "4" }, { "player_1.digging.right.ypos", "1" }, { "player_1.digging.right.frames", "4" }, { "player_1.digging.right.start_frame", "1" }, { "player_1.digging.right.delay", "4" }, { "player_1.collecting.down", "RocksHeroes.pcx" }, { "player_1.collecting.down.xpos", "0" }, { "player_1.collecting.down.ypos", "0" }, { "player_1.collecting.down.frames", "4" }, { "player_1.collecting.down.start_frame", "1" }, { "player_1.collecting.down.delay", "4" }, { "player_1.collecting.up", "RocksHeroes.pcx" }, { "player_1.collecting.up.xpos", "4" }, { "player_1.collecting.up.ypos", "0" }, { "player_1.collecting.up.frames", "4" }, { "player_1.collecting.up.start_frame", "1" }, { "player_1.collecting.up.delay", "4" }, { "player_1.collecting.left", "RocksHeroes.pcx" }, { "player_1.collecting.left.xpos", "0" }, { "player_1.collecting.left.ypos", "1" }, { "player_1.collecting.left.frames", "4" }, { "player_1.collecting.left.start_frame", "1" }, { "player_1.collecting.left.delay", "4" }, { "player_1.collecting.right", "RocksHeroes.pcx" }, { "player_1.collecting.right.xpos", "4" }, { "player_1.collecting.right.ypos", "1" }, { "player_1.collecting.right.frames", "4" }, { "player_1.collecting.right.start_frame", "1" }, { "player_1.collecting.right.delay", "4" }, { "player_1.pushing.down", "RocksHeroes.pcx" }, { "player_1.pushing.down.xpos", "0" }, { "player_1.pushing.down.ypos", "0" }, { "player_1.pushing.down.frames", "4" }, { "player_1.pushing.down.delay", "4" }, { "player_1.pushing.up", "RocksHeroes.pcx" }, { "player_1.pushing.up.xpos", "4" }, { "player_1.pushing.up.ypos", "0" }, { "player_1.pushing.up.frames", "4" }, { "player_1.pushing.up.delay", "4" }, { "player_1.pushing.left", "RocksHeroes.pcx" }, { "player_1.pushing.left.xpos", "4" }, { "player_1.pushing.left.ypos", "2" }, { "player_1.pushing.left.frames", "4" }, { "player_1.pushing.left.delay", "4" }, { "player_1.pushing.right", "RocksHeroes.pcx" }, { "player_1.pushing.right.xpos", "0" }, { "player_1.pushing.right.ypos", "2" }, { "player_1.pushing.right.frames", "4" }, { "player_1.pushing.right.delay", "4" }, { "player_1.snapping.down", "RocksHeroes.pcx" }, { "player_1.snapping.down.xpos", "0" }, { "player_1.snapping.down.ypos", "0" }, { "player_1.snapping.down.frames", "1" }, { "player_1.snapping.up", "RocksHeroes.pcx" }, { "player_1.snapping.up.xpos", "4" }, { "player_1.snapping.up.ypos", "0" }, { "player_1.snapping.up.frames", "1" }, { "player_1.snapping.left", "RocksHeroes.pcx" }, { "player_1.snapping.left.xpos", "0" }, { "player_1.snapping.left.ypos", "1" }, { "player_1.snapping.left.frames", "1" }, { "player_1.snapping.right", "RocksHeroes.pcx" }, { "player_1.snapping.right.xpos", "4" }, { "player_1.snapping.right.ypos", "1" }, { "player_1.snapping.right.frames", "1" }, { "player_2", "RocksHeroes.pcx" }, { "player_2.xpos", "0" }, { "player_2.ypos", "3" }, { "player_2.frames", "1" }, { "player_2.EDITOR", "RocksElements.pcx" }, { "player_2.EDITOR.xpos", "5" }, { "player_2.EDITOR.ypos", "7" }, { "player_2.down", "RocksHeroes.pcx" }, { "player_2.down.xpos", "0" }, { "player_2.down.ypos", "3" }, { "player_2.down.frames", "1" }, { "player_2.up", "RocksHeroes.pcx" }, { "player_2.up.xpos", "4" }, { "player_2.up.ypos", "3" }, { "player_2.up.frames", "1" }, { "player_2.left", "RocksHeroes.pcx" }, { "player_2.left.xpos", "0" }, { "player_2.left.ypos", "4" }, { "player_2.left.frames", "1" }, { "player_2.right", "RocksHeroes.pcx" }, { "player_2.right.xpos", "4" }, { "player_2.right.ypos", "4" }, { "player_2.right.frames", "1" }, { "player_2.moving.down", "RocksHeroes.pcx" }, { "player_2.moving.down.xpos", "0" }, { "player_2.moving.down.ypos", "3" }, { "player_2.moving.down.frames", "4" }, { "player_2.moving.down.start_frame", "1" }, { "player_2.moving.down.delay", "4" }, { "player_2.moving.up", "RocksHeroes.pcx" }, { "player_2.moving.up.xpos", "4" }, { "player_2.moving.up.ypos", "3" }, { "player_2.moving.up.frames", "4" }, { "player_2.moving.up.start_frame", "1" }, { "player_2.moving.up.delay", "4" }, { "player_2.moving.left", "RocksHeroes.pcx" }, { "player_2.moving.left.xpos", "0" }, { "player_2.moving.left.ypos", "4" }, { "player_2.moving.left.frames", "4" }, { "player_2.moving.left.start_frame", "1" }, { "player_2.moving.left.delay", "4" }, { "player_2.moving.right", "RocksHeroes.pcx" }, { "player_2.moving.right.xpos", "4" }, { "player_2.moving.right.ypos", "4" }, { "player_2.moving.right.frames", "4" }, { "player_2.moving.right.start_frame", "1" }, { "player_2.moving.right.delay", "4" }, { "player_2.digging.down", "RocksHeroes.pcx" }, { "player_2.digging.down.xpos", "0" }, { "player_2.digging.down.ypos", "3" }, { "player_2.digging.down.frames", "4" }, { "player_2.digging.down.start_frame", "1" }, { "player_2.digging.down.delay", "4" }, { "player_2.digging.up", "RocksHeroes.pcx" }, { "player_2.digging.up.xpos", "4" }, { "player_2.digging.up.ypos", "3" }, { "player_2.digging.up.frames", "4" }, { "player_2.digging.up.start_frame", "1" }, { "player_2.digging.up.delay", "4" }, { "player_2.digging.left", "RocksHeroes.pcx" }, { "player_2.digging.left.xpos", "0" }, { "player_2.digging.left.ypos", "4" }, { "player_2.digging.left.frames", "4" }, { "player_2.digging.left.start_frame", "1" }, { "player_2.digging.left.delay", "4" }, { "player_2.digging.right", "RocksHeroes.pcx" }, { "player_2.digging.right.xpos", "4" }, { "player_2.digging.right.ypos", "4" }, { "player_2.digging.right.frames", "4" }, { "player_2.digging.right.start_frame", "1" }, { "player_2.digging.right.delay", "4" }, { "player_2.collecting.down", "RocksHeroes.pcx" }, { "player_2.collecting.down.xpos", "0" }, { "player_2.collecting.down.ypos", "3" }, { "player_2.collecting.down.frames", "4" }, { "player_2.collecting.down.start_frame", "1" }, { "player_2.collecting.down.delay", "4" }, { "player_2.collecting.up", "RocksHeroes.pcx" }, { "player_2.collecting.up.xpos", "4" }, { "player_2.collecting.up.ypos", "3" }, { "player_2.collecting.up.frames", "4" }, { "player_2.collecting.up.start_frame", "1" }, { "player_2.collecting.up.delay", "4" }, { "player_2.collecting.left", "RocksHeroes.pcx" }, { "player_2.collecting.left.xpos", "0" }, { "player_2.collecting.left.ypos", "4" }, { "player_2.collecting.left.frames", "4" }, { "player_2.collecting.left.start_frame", "1" }, { "player_2.collecting.left.delay", "4" }, { "player_2.collecting.right", "RocksHeroes.pcx" }, { "player_2.collecting.right.xpos", "4" }, { "player_2.collecting.right.ypos", "4" }, { "player_2.collecting.right.frames", "4" }, { "player_2.collecting.right.start_frame", "1" }, { "player_2.collecting.right.delay", "4" }, { "player_2.pushing.down", "RocksHeroes.pcx" }, { "player_2.pushing.down.xpos", "0" }, { "player_2.pushing.down.ypos", "3" }, { "player_2.pushing.down.frames", "4" }, { "player_2.pushing.down.delay", "4" }, { "player_2.pushing.up", "RocksHeroes.pcx" }, { "player_2.pushing.up.xpos", "4" }, { "player_2.pushing.up.ypos", "3" }, { "player_2.pushing.up.frames", "4" }, { "player_2.pushing.up.delay", "4" }, { "player_2.pushing.left", "RocksHeroes.pcx" }, { "player_2.pushing.left.xpos", "4" }, { "player_2.pushing.left.ypos", "5" }, { "player_2.pushing.left.frames", "4" }, { "player_2.pushing.left.delay", "4" }, { "player_2.pushing.right", "RocksHeroes.pcx" }, { "player_2.pushing.right.xpos", "0" }, { "player_2.pushing.right.ypos", "5" }, { "player_2.pushing.right.frames", "4" }, { "player_2.pushing.right.delay", "4" }, { "player_2.snapping.down", "RocksHeroes.pcx" }, { "player_2.snapping.down.xpos", "0" }, { "player_2.snapping.down.ypos", "3" }, { "player_2.snapping.down.frames", "1" }, { "player_2.snapping.up", "RocksHeroes.pcx" }, { "player_2.snapping.up.xpos", "4" }, { "player_2.snapping.up.ypos", "3" }, { "player_2.snapping.up.frames", "1" }, { "player_2.snapping.left", "RocksHeroes.pcx" }, { "player_2.snapping.left.xpos", "0" }, { "player_2.snapping.left.ypos", "4" }, { "player_2.snapping.left.frames", "1" }, { "player_2.snapping.right", "RocksHeroes.pcx" }, { "player_2.snapping.right.xpos", "4" }, { "player_2.snapping.right.ypos", "4" }, { "player_2.snapping.right.frames", "1" }, { "player_3", "RocksHeroes.pcx" }, { "player_3.xpos", "0" }, { "player_3.ypos", "6" }, { "player_3.frames", "1" }, { "player_3.EDITOR", "RocksElements.pcx" }, { "player_3.EDITOR.xpos", "6" }, { "player_3.EDITOR.ypos", "7" }, { "player_3.down", "RocksHeroes.pcx" }, { "player_3.down.xpos", "0" }, { "player_3.down.ypos", "6" }, { "player_3.down.frames", "1" }, { "player_3.up", "RocksHeroes.pcx" }, { "player_3.up.xpos", "4" }, { "player_3.up.ypos", "6" }, { "player_3.up.frames", "1" }, { "player_3.left", "RocksHeroes.pcx" }, { "player_3.left.xpos", "0" }, { "player_3.left.ypos", "7" }, { "player_3.left.frames", "1" }, { "player_3.right", "RocksHeroes.pcx" }, { "player_3.right.xpos", "4" }, { "player_3.right.ypos", "7" }, { "player_3.right.frames", "1" }, { "player_3.moving.down", "RocksHeroes.pcx" }, { "player_3.moving.down.xpos", "0" }, { "player_3.moving.down.ypos", "6" }, { "player_3.moving.down.frames", "4" }, { "player_3.moving.down.start_frame", "1" }, { "player_3.moving.down.delay", "4" }, { "player_3.moving.up", "RocksHeroes.pcx" }, { "player_3.moving.up.xpos", "4" }, { "player_3.moving.up.ypos", "6" }, { "player_3.moving.up.frames", "4" }, { "player_3.moving.up.start_frame", "1" }, { "player_3.moving.up.delay", "4" }, { "player_3.moving.left", "RocksHeroes.pcx" }, { "player_3.moving.left.xpos", "0" }, { "player_3.moving.left.ypos", "7" }, { "player_3.moving.left.frames", "4" }, { "player_3.moving.left.start_frame", "1" }, { "player_3.moving.left.delay", "4" }, { "player_3.moving.right", "RocksHeroes.pcx" }, { "player_3.moving.right.xpos", "4" }, { "player_3.moving.right.ypos", "7" }, { "player_3.moving.right.frames", "4" }, { "player_3.moving.right.start_frame", "1" }, { "player_3.moving.right.delay", "4" }, { "player_3.digging.down", "RocksHeroes.pcx" }, { "player_3.digging.down.xpos", "0" }, { "player_3.digging.down.ypos", "6" }, { "player_3.digging.down.frames", "4" }, { "player_3.digging.down.start_frame", "1" }, { "player_3.digging.down.delay", "4" }, { "player_3.digging.up", "RocksHeroes.pcx" }, { "player_3.digging.up.xpos", "4" }, { "player_3.digging.up.ypos", "6" }, { "player_3.digging.up.frames", "4" }, { "player_3.digging.up.start_frame", "1" }, { "player_3.digging.up.delay", "4" }, { "player_3.digging.left", "RocksHeroes.pcx" }, { "player_3.digging.left.xpos", "0" }, { "player_3.digging.left.ypos", "7" }, { "player_3.digging.left.frames", "4" }, { "player_3.digging.left.start_frame", "1" }, { "player_3.digging.left.delay", "4" }, { "player_3.digging.right", "RocksHeroes.pcx" }, { "player_3.digging.right.xpos", "4" }, { "player_3.digging.right.ypos", "7" }, { "player_3.digging.right.frames", "4" }, { "player_3.digging.right.start_frame", "1" }, { "player_3.digging.right.delay", "4" }, { "player_3.collecting.down", "RocksHeroes.pcx" }, { "player_3.collecting.down.xpos", "0" }, { "player_3.collecting.down.ypos", "6" }, { "player_3.collecting.down.frames", "4" }, { "player_3.collecting.down.start_frame", "1" }, { "player_3.collecting.down.delay", "4" }, { "player_3.collecting.up", "RocksHeroes.pcx" }, { "player_3.collecting.up.xpos", "4" }, { "player_3.collecting.up.ypos", "6" }, { "player_3.collecting.up.frames", "4" }, { "player_3.collecting.up.start_frame", "1" }, { "player_3.collecting.up.delay", "4" }, { "player_3.collecting.left", "RocksHeroes.pcx" }, { "player_3.collecting.left.xpos", "0" }, { "player_3.collecting.left.ypos", "7" }, { "player_3.collecting.left.frames", "4" }, { "player_3.collecting.left.start_frame", "1" }, { "player_3.collecting.left.delay", "4" }, { "player_3.collecting.right", "RocksHeroes.pcx" }, { "player_3.collecting.right.xpos", "4" }, { "player_3.collecting.right.ypos", "7" }, { "player_3.collecting.right.frames", "4" }, { "player_3.collecting.right.start_frame", "1" }, { "player_3.collecting.right.delay", "4" }, { "player_3.pushing.down", "RocksHeroes.pcx" }, { "player_3.pushing.down.xpos", "0" }, { "player_3.pushing.down.ypos", "6" }, { "player_3.pushing.down.frames", "4" }, { "player_3.pushing.down.delay", "4" }, { "player_3.pushing.up", "RocksHeroes.pcx" }, { "player_3.pushing.up.xpos", "4" }, { "player_3.pushing.up.ypos", "6" }, { "player_3.pushing.up.frames", "4" }, { "player_3.pushing.up.delay", "4" }, { "player_3.pushing.left", "RocksHeroes.pcx" }, { "player_3.pushing.left.xpos", "4" }, { "player_3.pushing.left.ypos", "8" }, { "player_3.pushing.left.frames", "4" }, { "player_3.pushing.left.delay", "4" }, { "player_3.pushing.right", "RocksHeroes.pcx" }, { "player_3.pushing.right.xpos", "0" }, { "player_3.pushing.right.ypos", "8" }, { "player_3.pushing.right.frames", "4" }, { "player_3.pushing.right.delay", "4" }, { "player_3.snapping.down", "RocksHeroes.pcx" }, { "player_3.snapping.down.xpos", "0" }, { "player_3.snapping.down.ypos", "6" }, { "player_3.snapping.down.frames", "1" }, { "player_3.snapping.up", "RocksHeroes.pcx" }, { "player_3.snapping.up.xpos", "4" }, { "player_3.snapping.up.ypos", "6" }, { "player_3.snapping.up.frames", "1" }, { "player_3.snapping.left", "RocksHeroes.pcx" }, { "player_3.snapping.left.xpos", "0" }, { "player_3.snapping.left.ypos", "7" }, { "player_3.snapping.left.frames", "1" }, { "player_3.snapping.right", "RocksHeroes.pcx" }, { "player_3.snapping.right.xpos", "4" }, { "player_3.snapping.right.ypos", "7" }, { "player_3.snapping.right.frames", "1" }, { "player_4", "RocksHeroes.pcx" }, { "player_4.xpos", "0" }, { "player_4.ypos", "9" }, { "player_4.frames", "1" }, { "player_4.EDITOR", "RocksElements.pcx" }, { "player_4.EDITOR.xpos", "7" }, { "player_4.EDITOR.ypos", "7" }, { "player_4.down", "RocksHeroes.pcx" }, { "player_4.down.xpos", "0" }, { "player_4.down.ypos", "9" }, { "player_4.down.frames", "1" }, { "player_4.up", "RocksHeroes.pcx" }, { "player_4.up.xpos", "4" }, { "player_4.up.ypos", "9" }, { "player_4.up.frames", "1" }, { "player_4.left", "RocksHeroes.pcx" }, { "player_4.left.xpos", "0" }, { "player_4.left.ypos", "10" }, { "player_4.left.frames", "1" }, { "player_4.right", "RocksHeroes.pcx" }, { "player_4.right.xpos", "4" }, { "player_4.right.ypos", "10" }, { "player_4.right.frames", "1" }, { "player_4.moving.down", "RocksHeroes.pcx" }, { "player_4.moving.down.xpos", "0" }, { "player_4.moving.down.ypos", "9" }, { "player_4.moving.down.frames", "4" }, { "player_4.moving.down.start_frame", "1" }, { "player_4.moving.down.delay", "4" }, { "player_4.moving.up", "RocksHeroes.pcx" }, { "player_4.moving.up.xpos", "4" }, { "player_4.moving.up.ypos", "9" }, { "player_4.moving.up.frames", "4" }, { "player_4.moving.up.start_frame", "1" }, { "player_4.moving.up.delay", "4" }, { "player_4.moving.left", "RocksHeroes.pcx" }, { "player_4.moving.left.xpos", "0" }, { "player_4.moving.left.ypos", "10" }, { "player_4.moving.left.frames", "4" }, { "player_4.moving.left.start_frame", "1" }, { "player_4.moving.left.delay", "4" }, { "player_4.moving.right", "RocksHeroes.pcx" }, { "player_4.moving.right.xpos", "4" }, { "player_4.moving.right.ypos", "10" }, { "player_4.moving.right.frames", "4" }, { "player_4.moving.right.start_frame", "1" }, { "player_4.moving.right.delay", "4" }, { "player_4.digging.down", "RocksHeroes.pcx" }, { "player_4.digging.down.xpos", "0" }, { "player_4.digging.down.ypos", "9" }, { "player_4.digging.down.frames", "4" }, { "player_4.digging.down.start_frame", "1" }, { "player_4.digging.down.delay", "4" }, { "player_4.digging.up", "RocksHeroes.pcx" }, { "player_4.digging.up.xpos", "4" }, { "player_4.digging.up.ypos", "9" }, { "player_4.digging.up.frames", "4" }, { "player_4.digging.up.start_frame", "1" }, { "player_4.digging.up.delay", "4" }, { "player_4.digging.left", "RocksHeroes.pcx" }, { "player_4.digging.left.xpos", "0" }, { "player_4.digging.left.ypos", "10" }, { "player_4.digging.left.frames", "4" }, { "player_4.digging.left.start_frame", "1" }, { "player_4.digging.left.delay", "4" }, { "player_4.digging.right", "RocksHeroes.pcx" }, { "player_4.digging.right.xpos", "4" }, { "player_4.digging.right.ypos", "10" }, { "player_4.digging.right.frames", "4" }, { "player_4.digging.right.start_frame", "1" }, { "player_4.digging.right.delay", "4" }, { "player_4.collecting.down", "RocksHeroes.pcx" }, { "player_4.collecting.down.xpos", "0" }, { "player_4.collecting.down.ypos", "9" }, { "player_4.collecting.down.frames", "4" }, { "player_4.collecting.down.start_frame", "1" }, { "player_4.collecting.down.delay", "4" }, { "player_4.collecting.up", "RocksHeroes.pcx" }, { "player_4.collecting.up.xpos", "4" }, { "player_4.collecting.up.ypos", "9" }, { "player_4.collecting.up.frames", "4" }, { "player_4.collecting.up.start_frame", "1" }, { "player_4.collecting.up.delay", "4" }, { "player_4.collecting.left", "RocksHeroes.pcx" }, { "player_4.collecting.left.xpos", "0" }, { "player_4.collecting.left.ypos", "10" }, { "player_4.collecting.left.frames", "4" }, { "player_4.collecting.left.start_frame", "1" }, { "player_4.collecting.left.delay", "4" }, { "player_4.collecting.right", "RocksHeroes.pcx" }, { "player_4.collecting.right.xpos", "4" }, { "player_4.collecting.right.ypos", "10" }, { "player_4.collecting.right.frames", "4" }, { "player_4.collecting.right.start_frame", "1" }, { "player_4.collecting.right.delay", "4" }, { "player_4.pushing.down", "RocksHeroes.pcx" }, { "player_4.pushing.down.xpos", "0" }, { "player_4.pushing.down.ypos", "9" }, { "player_4.pushing.down.frames", "4" }, { "player_4.pushing.down.delay", "4" }, { "player_4.pushing.up", "RocksHeroes.pcx" }, { "player_4.pushing.up.xpos", "4" }, { "player_4.pushing.up.ypos", "9" }, { "player_4.pushing.up.frames", "4" }, { "player_4.pushing.up.delay", "4" }, { "player_4.pushing.left", "RocksHeroes.pcx" }, { "player_4.pushing.left.xpos", "4" }, { "player_4.pushing.left.ypos", "11" }, { "player_4.pushing.left.frames", "4" }, { "player_4.pushing.left.delay", "4" }, { "player_4.pushing.right", "RocksHeroes.pcx" }, { "player_4.pushing.right.xpos", "0" }, { "player_4.pushing.right.ypos", "11" }, { "player_4.pushing.right.frames", "4" }, { "player_4.pushing.right.delay", "4" }, { "player_4.snapping.down", "RocksHeroes.pcx" }, { "player_4.snapping.down.xpos", "0" }, { "player_4.snapping.down.ypos", "9" }, { "player_4.snapping.down.frames", "1" }, { "player_4.snapping.up", "RocksHeroes.pcx" }, { "player_4.snapping.up.xpos", "4" }, { "player_4.snapping.up.ypos", "9" }, { "player_4.snapping.up.frames", "1" }, { "player_4.snapping.left", "RocksHeroes.pcx" }, { "player_4.snapping.left.xpos", "0" }, { "player_4.snapping.left.ypos", "10" }, { "player_4.snapping.left.frames", "1" }, { "player_4.snapping.right", "RocksHeroes.pcx" }, { "player_4.snapping.right.xpos", "4" }, { "player_4.snapping.right.ypos", "10" }, { "player_4.snapping.right.frames", "1" }, { "[default].exploding", "RocksElements.pcx" }, { "[default].exploding.xpos", "0" }, { "[default].exploding.ypos", "4" }, { "[default].exploding.frames", "8" }, { "[default].exploding.delay", "2" }, { "[default].exploding.anim_mode", "linear" }, { "twinkle_blue", "RocksHeroes.pcx" }, { "twinkle_blue.xpos", "9" }, { "twinkle_blue.ypos", "11" }, { "twinkle_blue.frames", "3" }, { "twinkle_blue.delay", "2" }, { "twinkle_blue.anim_mode", "pingpong" }, { "twinkle_blue.global_sync", "false" }, { "twinkle_white", "RocksHeroes.pcx" }, { "twinkle_white.xpos", "13" }, { "twinkle_white.ypos", "11" }, { "twinkle_white.frames", "3" }, { "twinkle_white.delay", "2" }, { "twinkle_white.anim_mode", "pingpong" }, { "twinkle_white.global_sync", "false" }, { "steelwall_topleft", "RocksElements.pcx" }, { "steelwall_topleft.xpos", "4" }, { "steelwall_topleft.ypos", "0" }, { "steelwall_topleft.frames", "1" }, { "steelwall_topright", "RocksElements.pcx" }, { "steelwall_topright.xpos", "4" }, { "steelwall_topright.ypos", "0" }, { "steelwall_topright.frames", "1" }, { "steelwall_bottomleft", "RocksElements.pcx" }, { "steelwall_bottomleft.xpos", "4" }, { "steelwall_bottomleft.ypos", "0" }, { "steelwall_bottomleft.frames", "1" }, { "steelwall_bottomright", "RocksElements.pcx" }, { "steelwall_bottomright.xpos", "4" }, { "steelwall_bottomright.ypos", "0" }, { "steelwall_bottomright.frames", "1" }, { "steelwall_horizontal", "RocksElements.pcx" }, { "steelwall_horizontal.xpos", "4" }, { "steelwall_horizontal.ypos", "0" }, { "steelwall_horizontal.frames", "1" }, { "steelwall_vertical", "RocksElements.pcx" }, { "steelwall_vertical.xpos", "4" }, { "steelwall_vertical.ypos", "0" }, { "steelwall_vertical.frames", "1" }, { "steelwall_topleft.EDITOR", "RocksElements.pcx" }, { "steelwall_topleft.EDITOR.xpos", "0" }, { "steelwall_topleft.EDITOR.ypos", "13" }, { "steelwall_topright.EDITOR", "RocksElements.pcx" }, { "steelwall_topright.EDITOR.xpos", "1" }, { "steelwall_topright.EDITOR.ypos", "13" }, { "steelwall_bottomleft.EDITOR", "RocksElements.pcx" }, { "steelwall_bottomleft.EDITOR.xpos", "2" }, { "steelwall_bottomleft.EDITOR.ypos", "13" }, { "steelwall_bottomright.EDITOR", "RocksElements.pcx" }, { "steelwall_bottomright.EDITOR.xpos", "3" }, { "steelwall_bottomright.EDITOR.ypos", "13" }, { "steelwall_horizontal.EDITOR", "RocksElements.pcx" }, { "steelwall_horizontal.EDITOR.xpos", "4" }, { "steelwall_horizontal.EDITOR.ypos", "13" }, { "steelwall_vertical.EDITOR", "RocksElements.pcx" }, { "steelwall_vertical.EDITOR.xpos", "5" }, { "steelwall_vertical.EDITOR.ypos", "13" }, { "invisible_steelwall_topleft", "RocksSP.pcx" }, { "invisible_steelwall_topleft.xpos", "0" }, { "invisible_steelwall_topleft.ypos", "0" }, { "invisible_steelwall_topleft.frames", "1" }, { "invisible_steelwall_topright", "RocksSP.pcx" }, { "invisible_steelwall_topright.xpos", "0" }, { "invisible_steelwall_topright.ypos", "0" }, { "invisible_steelwall_topright.frames", "1" }, { "invisible_steelwall_bottomleft", "RocksSP.pcx" }, { "invisible_steelwall_bottomleft.xpos", "0" }, { "invisible_steelwall_bottomleft.ypos", "0" }, { "invisible_steelwall_bottomleft.frames", "1" }, { "invisible_steelwall_bottomright", "RocksSP.pcx" }, { "invisible_steelwall_bottomright.xpos", "0" }, { "invisible_steelwall_bottomright.ypos", "0" }, { "invisible_steelwall_bottomright.frames", "1" }, { "invisible_steelwall_horizontal", "RocksSP.pcx" }, { "invisible_steelwall_horizontal.xpos", "0" }, { "invisible_steelwall_horizontal.ypos", "0" }, { "invisible_steelwall_horizontal.frames", "1" }, { "invisible_steelwall_vertical", "RocksSP.pcx" }, { "invisible_steelwall_vertical.xpos", "0" }, { "invisible_steelwall_vertical.ypos", "0" }, { "invisible_steelwall_vertical.frames", "1" }, { "invisible_steelwall_topleft.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_topleft.EDITOR.xpos", "6" }, { "invisible_steelwall_topleft.EDITOR.ypos", "13" }, { "invisible_steelwall_topright.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_topright.EDITOR.xpos", "7" }, { "invisible_steelwall_topright.EDITOR.ypos", "13" }, { "invisible_steelwall_bottomleft.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_bottomleft.EDITOR.xpos","8" }, { "invisible_steelwall_bottomleft.EDITOR.ypos","13" }, { "invisible_steelwall_bottomright.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_bottomright.EDITOR.xpos","9" }, { "invisible_steelwall_bottomright.EDITOR.ypos","13" }, { "invisible_steelwall_horizontal.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_horizontal.EDITOR.xpos","10" }, { "invisible_steelwall_horizontal.EDITOR.ypos","13" }, { "invisible_steelwall_vertical.EDITOR", "RocksElements.pcx" }, { "invisible_steelwall_vertical.EDITOR.xpos", "11" }, { "invisible_steelwall_vertical.EDITOR.ypos", "13" }, { "arrow_left", "RocksDC.pcx" }, { "arrow_left.xpos", "8" }, { "arrow_left.ypos", "8" }, { "arrow_left.frames", "1" }, { "arrow_right", "RocksDC.pcx" }, { "arrow_right.xpos", "9" }, { "arrow_right.ypos", "8" }, { "arrow_right.frames", "1" }, { "arrow_up", "RocksDC.pcx" }, { "arrow_up.xpos", "10" }, { "arrow_up.ypos", "8" }, { "arrow_up.frames", "1" }, { "arrow_down", "RocksDC.pcx" }, { "arrow_down.xpos", "11" }, { "arrow_down.ypos", "8" }, { "arrow_down.frames", "1" }, { "unknown", "RocksFontEM.pcx" }, { "unknown.xpos", "15" }, { "unknown.ypos", "1" }, { "unknown.frames", "1" }, { "trigger_element", "RocksDC.pcx" }, { "trigger_element.xpos", "15" }, { "trigger_element.ypos", "14" }, { "trigger_element.frames", "1" }, { "trigger_player", "RocksDC.pcx" }, { "trigger_player.xpos", "15" }, { "trigger_player.ypos", "13" }, { "trigger_player.frames", "1" }, { "trigger_ce_value", "RocksDC.pcx" }, { "trigger_ce_value.xpos", "15" }, { "trigger_ce_value.ypos", "11" }, { "trigger_ce_value.frames", "1" }, { "trigger_ce_score", "RocksDC.pcx" }, { "trigger_ce_score.xpos", "15" }, { "trigger_ce_score.ypos", "12" }, { "trigger_ce_score.frames", "1" }, { "current_ce_value", "RocksDC.pcx" }, { "current_ce_value.xpos", "14" }, { "current_ce_value.ypos", "11" }, { "current_ce_value.frames", "1" }, { "current_ce_score", "RocksDC.pcx" }, { "current_ce_score.xpos", "14" }, { "current_ce_score.ypos", "12" }, { "current_ce_score.frames", "1" }, { "prev_ce_1", "RocksMore.pcx" }, { "prev_ce_1.xpos", "0" }, { "prev_ce_1.ypos", "7" }, { "prev_ce_1.frames", "1" }, { "prev_ce_2", "RocksMore.pcx" }, { "prev_ce_2.xpos", "1" }, { "prev_ce_2.ypos", "7" }, { "prev_ce_2.frames", "1" }, { "prev_ce_3", "RocksMore.pcx" }, { "prev_ce_3.xpos", "2" }, { "prev_ce_3.ypos", "7" }, { "prev_ce_3.frames", "1" }, { "prev_ce_4", "RocksMore.pcx" }, { "prev_ce_4.xpos", "3" }, { "prev_ce_4.ypos", "7" }, { "prev_ce_4.frames", "1" }, { "prev_ce_5", "RocksMore.pcx" }, { "prev_ce_5.xpos", "4" }, { "prev_ce_5.ypos", "7" }, { "prev_ce_5.frames", "1" }, { "prev_ce_6", "RocksMore.pcx" }, { "prev_ce_6.xpos", "5" }, { "prev_ce_6.ypos", "7" }, { "prev_ce_6.frames", "1" }, { "prev_ce_7", "RocksMore.pcx" }, { "prev_ce_7.xpos", "6" }, { "prev_ce_7.ypos", "7" }, { "prev_ce_7.frames", "1" }, { "prev_ce_8", "RocksMore.pcx" }, { "prev_ce_8.xpos", "7" }, { "prev_ce_8.ypos", "7" }, { "prev_ce_8.frames", "1" }, { "next_ce_1", "RocksMore.pcx" }, { "next_ce_1.xpos", "0" }, { "next_ce_1.ypos", "8" }, { "next_ce_1.frames", "1" }, { "next_ce_2", "RocksMore.pcx" }, { "next_ce_2.xpos", "1" }, { "next_ce_2.ypos", "8" }, { "next_ce_2.frames", "1" }, { "next_ce_3", "RocksMore.pcx" }, { "next_ce_3.xpos", "2" }, { "next_ce_3.ypos", "8" }, { "next_ce_3.frames", "1" }, { "next_ce_4", "RocksMore.pcx" }, { "next_ce_4.xpos", "3" }, { "next_ce_4.ypos", "8" }, { "next_ce_4.frames", "1" }, { "next_ce_5", "RocksMore.pcx" }, { "next_ce_5.xpos", "4" }, { "next_ce_5.ypos", "8" }, { "next_ce_5.frames", "1" }, { "next_ce_6", "RocksMore.pcx" }, { "next_ce_6.xpos", "5" }, { "next_ce_6.ypos", "8" }, { "next_ce_6.frames", "1" }, { "next_ce_7", "RocksMore.pcx" }, { "next_ce_7.xpos", "6" }, { "next_ce_7.ypos", "8" }, { "next_ce_7.frames", "1" }, { "next_ce_8", "RocksMore.pcx" }, { "next_ce_8.xpos", "7" }, { "next_ce_8.ypos", "8" }, { "next_ce_8.frames", "1" }, { "self", "RocksMore.pcx" }, { "self.xpos", "8" }, { "self.ypos", "7" }, { "self.frames", "1" }, { "any_element", "RocksMore.pcx" }, { "any_element.xpos", "9" }, { "any_element.ypos", "7" }, { "any_element.frames", "1" }, { "emc_key_5", "RocksEMC.pcx" }, { "emc_key_5.xpos", "0" }, { "emc_key_5.ypos", "5" }, { "emc_key_5.frames", "1" }, { "emc_key_6", "RocksEMC.pcx" }, { "emc_key_6.xpos", "1" }, { "emc_key_6.ypos", "5" }, { "emc_key_6.frames", "1" }, { "emc_key_7", "RocksEMC.pcx" }, { "emc_key_7.xpos", "2" }, { "emc_key_7.ypos", "5" }, { "emc_key_7.frames", "1" }, { "emc_key_8", "RocksEMC.pcx" }, { "emc_key_8.xpos", "3" }, { "emc_key_8.ypos", "5" }, { "emc_key_8.frames", "1" }, { "emc_gate_5", "RocksEMC.pcx" }, { "emc_gate_5.xpos", "0" }, { "emc_gate_5.ypos", "6" }, { "emc_gate_5.frames", "1" }, { "emc_gate_6", "RocksEMC.pcx" }, { "emc_gate_6.xpos", "1" }, { "emc_gate_6.ypos", "6" }, { "emc_gate_6.frames", "1" }, { "emc_gate_7", "RocksEMC.pcx" }, { "emc_gate_7.xpos", "2" }, { "emc_gate_7.ypos", "6" }, { "emc_gate_7.frames", "1" }, { "emc_gate_8", "RocksEMC.pcx" }, { "emc_gate_8.xpos", "3" }, { "emc_gate_8.ypos", "6" }, { "emc_gate_8.frames", "1" }, { "emc_gate_5_gray", "RocksEMC.pcx" }, { "emc_gate_5_gray.xpos", "4" }, { "emc_gate_5_gray.ypos", "7" }, { "emc_gate_5_gray.frames", "1" }, { "emc_gate_5_gray.EDITOR", "RocksEMC.pcx" }, { "emc_gate_5_gray.EDITOR.xpos", "0" }, { "emc_gate_5_gray.EDITOR.ypos", "7" }, { "emc_gate_5_gray.active", "RocksEMC.pcx" }, { "emc_gate_5_gray.active.xpos", "0" }, { "emc_gate_5_gray.active.ypos", "6" }, { "emc_gate_5_gray.active.frames", "1" }, { "emc_gate_6_gray", "RocksEMC.pcx" }, { "emc_gate_6_gray.xpos", "4" }, { "emc_gate_6_gray.ypos", "7" }, { "emc_gate_6_gray.frames", "1" }, { "emc_gate_6_gray.EDITOR", "RocksEMC.pcx" }, { "emc_gate_6_gray.EDITOR.xpos", "1" }, { "emc_gate_6_gray.EDITOR.ypos", "7" }, { "emc_gate_6_gray.active", "RocksEMC.pcx" }, { "emc_gate_6_gray.active.xpos", "1" }, { "emc_gate_6_gray.active.ypos", "6" }, { "emc_gate_6_gray.active.frames", "1" }, { "emc_gate_7_gray", "RocksEMC.pcx" }, { "emc_gate_7_gray.xpos", "4" }, { "emc_gate_7_gray.ypos", "7" }, { "emc_gate_7_gray.frames", "1" }, { "emc_gate_7_gray.EDITOR", "RocksEMC.pcx" }, { "emc_gate_7_gray.EDITOR.xpos", "2" }, { "emc_gate_7_gray.EDITOR.ypos", "7" }, { "emc_gate_7_gray.active", "RocksEMC.pcx" }, { "emc_gate_7_gray.active.xpos", "2" }, { "emc_gate_7_gray.active.ypos", "6" }, { "emc_gate_7_gray.active.frames", "1" }, { "emc_gate_8_gray", "RocksEMC.pcx" }, { "emc_gate_8_gray.xpos", "4" }, { "emc_gate_8_gray.ypos", "7" }, { "emc_gate_8_gray.frames", "1" }, { "emc_gate_8_gray.EDITOR", "RocksEMC.pcx" }, { "emc_gate_8_gray.EDITOR.xpos", "3" }, { "emc_gate_8_gray.EDITOR.ypos", "7" }, { "emc_gate_8_gray.active", "RocksEMC.pcx" }, { "emc_gate_8_gray.active.xpos", "3" }, { "emc_gate_8_gray.active.ypos", "6" }, { "emc_gate_8_gray.active.frames", "1" }, { "emc_android", "RocksEMC.pcx" }, { "emc_android.xpos", "0" }, { "emc_android.ypos", "8" }, { "emc_android.frames", "8" }, { "emc_android.delay", "2" }, { "emc_android.shrinking.upleft", "RocksEMC.pcx" }, { "emc_android.shrinking.upleft.xpos", "1" }, { "emc_android.shrinking.upleft.ypos", "11" }, { "emc_android.shrinking.upleft.frames", "8" }, { "emc_android.shrinking.upleft.anim_mode", "linear" }, { "emc_android.growing.downright", "RocksEMC.pcx" }, { "emc_android.growing.downright.xpos", "0" }, { "emc_android.growing.downright.ypos", "11" }, { "emc_android.growing.downright.frames", "8" }, { "emc_android.growing.downright.anim_mode", "linear,reverse" }, { "emc_android.shrinking.downleft", "RocksEMC.pcx" }, { "emc_android.shrinking.downleft.xpos", "1" }, { "emc_android.shrinking.downleft.ypos", "12" }, { "emc_android.shrinking.downleft.frames", "8" }, { "emc_android.shrinking.downleft.anim_mode", "linear" }, { "emc_android.growing.upright", "RocksEMC.pcx" }, { "emc_android.growing.upright.xpos", "0" }, { "emc_android.growing.upright.ypos", "12" }, { "emc_android.growing.upright.frames", "8" }, { "emc_android.growing.upright.anim_mode", "linear,reverse" }, { "emc_android.shrinking.upright", "RocksEMC.pcx" }, { "emc_android.shrinking.upright.xpos", "1" }, { "emc_android.shrinking.upright.ypos", "13" }, { "emc_android.shrinking.upright.frames", "8" }, { "emc_android.shrinking.upright.anim_mode", "linear" }, { "emc_android.growing.downleft", "RocksEMC.pcx" }, { "emc_android.growing.downleft.xpos", "0" }, { "emc_android.growing.downleft.ypos", "13" }, { "emc_android.growing.downleft.frames", "8" }, { "emc_android.growing.downleft.anim_mode", "linear,reverse" }, { "emc_android.shrinking.downright", "RocksEMC.pcx" }, { "emc_android.shrinking.downright.xpos", "1" }, { "emc_android.shrinking.downright.ypos", "14" }, { "emc_android.shrinking.downright.frames", "8" }, { "emc_android.shrinking.downright.anim_mode","linear" }, { "emc_android.growing.upleft", "RocksEMC.pcx" }, { "emc_android.growing.upleft.xpos", "0" }, { "emc_android.growing.upleft.ypos", "14" }, { "emc_android.growing.upleft.frames", "8" }, { "emc_android.growing.upleft.anim_mode", "linear,reverse" }, { "emc_grass", "RocksEMC.pcx" }, { "emc_grass.xpos", "0" }, { "emc_grass.ypos", "4" }, { "emc_grass.frames", "1" }, { "emc_grass.CRUMBLED", "RocksEMC.pcx" }, { "emc_grass.CRUMBLED.xpos", "1" }, { "emc_grass.CRUMBLED.ypos", "4" }, { "emc_grass.CRUMBLED.frames", "1" }, { "emc_grass.digging.left", "RocksEMC.pcx" }, { "emc_grass.digging.left.xpos", "6" }, { "emc_grass.digging.left.ypos", "0" }, { "emc_grass.digging.left.frames", "3" }, { "emc_grass.digging.left.delay", "2" }, { "emc_grass.digging.left.anim_mode", "linear" }, { "emc_grass.digging.right", "RocksEMC.pcx" }, { "emc_grass.digging.right.xpos", "9" }, { "emc_grass.digging.right.ypos", "0" }, { "emc_grass.digging.right.frames", "3" }, { "emc_grass.digging.right.delay", "2" }, { "emc_grass.digging.right.anim_mode", "linear" }, { "emc_grass.digging.up", "RocksEMC.pcx" }, { "emc_grass.digging.up.xpos", "0" }, { "emc_grass.digging.up.ypos", "0" }, { "emc_grass.digging.up.frames", "3" }, { "emc_grass.digging.up.delay", "2" }, { "emc_grass.digging.up.anim_mode", "linear" }, { "emc_grass.digging.down", "RocksEMC.pcx" }, { "emc_grass.digging.down.xpos", "3" }, { "emc_grass.digging.down.ypos", "0" }, { "emc_grass.digging.down.frames", "3" }, { "emc_grass.digging.down.delay", "2" }, { "emc_grass.digging.down.anim_mode", "linear" }, { "emc_grass.digging.left.CRUMBLED", "RocksEMC.pcx" }, { "emc_grass.digging.left.CRUMBLED.xpos", "6" }, { "emc_grass.digging.left.CRUMBLED.ypos", "1" }, { "emc_grass.digging.left.CRUMBLED.frames", "3" }, { "emc_grass.digging.left.CRUMBLED.delay", "2" }, { "emc_grass.digging.left.CRUMBLED.anim_mode","linear" }, { "emc_grass.digging.right.CRUMBLED", "RocksEMC.pcx" }, { "emc_grass.digging.right.CRUMBLED.xpos", "9" }, { "emc_grass.digging.right.CRUMBLED.ypos", "1" }, { "emc_grass.digging.right.CRUMBLED.frames", "3" }, { "emc_grass.digging.right.CRUMBLED.delay", "2" }, { "emc_grass.digging.right.CRUMBLED.anim_mode","linear" }, { "emc_grass.digging.up.CRUMBLED", "RocksEMC.pcx" }, { "emc_grass.digging.up.CRUMBLED.xpos", "0" }, { "emc_grass.digging.up.CRUMBLED.ypos", "1" }, { "emc_grass.digging.up.CRUMBLED.frames", "3" }, { "emc_grass.digging.up.CRUMBLED.delay", "2" }, { "emc_grass.digging.up.CRUMBLED.anim_mode", "linear" }, { "emc_grass.digging.down.CRUMBLED", "RocksEMC.pcx" }, { "emc_grass.digging.down.CRUMBLED.xpos", "3" }, { "emc_grass.digging.down.CRUMBLED.ypos", "1" }, { "emc_grass.digging.down.CRUMBLED.frames", "3" }, { "emc_grass.digging.down.CRUMBLED.delay", "2" }, { "emc_grass.digging.down.CRUMBLED.anim_mode","linear" }, { "emc_magic_ball", "RocksEMC.pcx" }, { "emc_magic_ball.xpos", "0" }, { "emc_magic_ball.ypos", "9" }, { "emc_magic_ball.frames", "1" }, { "emc_magic_ball.active", "RocksEMC.pcx" }, { "emc_magic_ball.active.xpos", "0" }, { "emc_magic_ball.active.ypos", "9" }, { "emc_magic_ball.active.frames", "16" }, { "emc_magic_ball.active.frames_per_line", "8" }, { "emc_magic_ball.dropping", "RocksElements.pcx" }, { "emc_magic_ball.dropping.xpos", "0" }, { "emc_magic_ball.dropping.ypos", "4" }, { "emc_magic_ball.dropping.frames", "8" }, { "emc_magic_ball.dropping.anim_mode", "linear" }, { "emc_magic_ball_switch", "RocksEMC.pcx" }, { "emc_magic_ball_switch.xpos", "8" }, { "emc_magic_ball_switch.ypos", "10" }, { "emc_magic_ball_switch.frames", "1" }, { "emc_magic_ball_switch.active", "RocksEMC.pcx" }, { "emc_magic_ball_switch.active.xpos", "8" }, { "emc_magic_ball_switch.active.ypos", "9" }, { "emc_magic_ball_switch.active.frames", "1" }, { "emc_spring_bumper", "RocksEMC.pcx" }, { "emc_spring_bumper.xpos", "8" }, { "emc_spring_bumper.ypos", "4" }, { "emc_spring_bumper.frames", "1" }, { "emc_spring_bumper.active", "RocksEMC.pcx" }, { "emc_spring_bumper.active.xpos", "8" }, { "emc_spring_bumper.active.ypos", "4" }, { "emc_spring_bumper.active.frames", "4" }, { "emc_spring_bumper.active.anim_mode", "pingpong2" }, { "emc_plant", "RocksEMC.pcx" }, { "emc_plant.xpos", "4" }, { "emc_plant.ypos", "4" }, { "emc_plant.frames", "1" }, { "emc_plant.CRUMBLED", "RocksEMC.pcx" }, { "emc_plant.CRUMBLED.xpos", "5" }, { "emc_plant.CRUMBLED.ypos", "4" }, { "emc_plant.CRUMBLED.frames", "1" }, { "emc_lenses", "RocksEMC.pcx" }, { "emc_lenses.xpos", "6" }, { "emc_lenses.ypos", "4" }, { "emc_lenses.frames", "1" }, { "emc_magnifier", "RocksEMC.pcx" }, { "emc_magnifier.xpos", "7" }, { "emc_magnifier.ypos", "4" }, { "emc_magnifier.frames", "1" }, { "emc_wall_9", "RocksEMC.pcx" }, { "emc_wall_9.xpos", "10" }, { "emc_wall_9.ypos", "5" }, { "emc_wall_9.frames", "1" }, { "emc_wall_10", "RocksEMC.pcx" }, { "emc_wall_10.xpos", "10" }, { "emc_wall_10.ypos", "6" }, { "emc_wall_10.frames", "1" }, { "emc_wall_11", "RocksEMC.pcx" }, { "emc_wall_11.xpos", "11" }, { "emc_wall_11.ypos", "5" }, { "emc_wall_11.frames", "1" }, { "emc_wall_12", "RocksEMC.pcx" }, { "emc_wall_12.xpos", "11" }, { "emc_wall_12.ypos", "6" }, { "emc_wall_12.frames", "1" }, { "emc_wall_13", "RocksEMC.pcx" }, { "emc_wall_13.xpos", "10" }, { "emc_wall_13.ypos", "7" }, { "emc_wall_13.frames", "1" }, { "emc_wall_14", "RocksEMC.pcx" }, { "emc_wall_14.xpos", "10" }, { "emc_wall_14.ypos", "8" }, { "emc_wall_14.frames", "1" }, { "emc_wall_15", "RocksEMC.pcx" }, { "emc_wall_15.xpos", "10" }, { "emc_wall_15.ypos", "9" }, { "emc_wall_15.frames", "1" }, { "emc_wall_16", "RocksEMC.pcx" }, { "emc_wall_16.xpos", "10" }, { "emc_wall_16.ypos", "10" }, { "emc_wall_16.frames", "1" }, { "emc_wall_slippery_1", "RocksEMC.pcx" }, { "emc_wall_slippery_1.xpos", "11" }, { "emc_wall_slippery_1.ypos", "7" }, { "emc_wall_slippery_1.frames", "1" }, { "emc_wall_slippery_2", "RocksEMC.pcx" }, { "emc_wall_slippery_2.xpos", "11" }, { "emc_wall_slippery_2.ypos", "8" }, { "emc_wall_slippery_2.frames", "1" }, { "emc_wall_slippery_3", "RocksEMC.pcx" }, { "emc_wall_slippery_3.xpos", "11" }, { "emc_wall_slippery_3.ypos", "9" }, { "emc_wall_slippery_3.frames", "1" }, { "emc_wall_slippery_4", "RocksEMC.pcx" }, { "emc_wall_slippery_4.xpos", "11" }, { "emc_wall_slippery_4.ypos", "10" }, { "emc_wall_slippery_4.frames", "1" }, { "emc_fake_grass", "RocksEMC.pcx" }, { "emc_fake_grass.xpos", "0" }, { "emc_fake_grass.ypos", "4" }, { "emc_fake_grass.frames", "1" }, { "emc_fake_grass.CRUMBLED", "RocksEMC.pcx" }, { "emc_fake_grass.CRUMBLED.xpos", "1" }, { "emc_fake_grass.CRUMBLED.ypos", "4" }, { "emc_fake_grass.CRUMBLED.frames", "1" }, { "emc_fake_grass.active", "RocksEMC.pcx" }, { "emc_fake_grass.active.xpos", "2" }, { "emc_fake_grass.active.ypos", "4" }, { "emc_fake_grass.active.frames", "1" }, { "emc_fake_grass.active.CRUMBLED", "RocksEMC.pcx" }, { "emc_fake_grass.active.CRUMBLED.xpos", "3" }, { "emc_fake_grass.active.CRUMBLED.ypos", "4" }, { "emc_fake_grass.active.CRUMBLED.frames", "1" }, { "emc_fake_grass.EDITOR", "RocksEMC.pcx" }, { "emc_fake_grass.EDITOR.xpos", "2" }, { "emc_fake_grass.EDITOR.ypos", "4" }, { "emc_fake_grass.EDITOR.frames", "1" }, { "emc_fake_acid", "RocksElements.pcx" }, { "emc_fake_acid.xpos", "12" }, { "emc_fake_acid.ypos", "7" }, { "emc_fake_acid.frames", "4" }, { "emc_fake_acid.delay", "10" }, { "emc_fake_acid.global_sync", "true" }, { "emc_dripper", "RocksSP.pcx" }, { "emc_dripper.xpos", "0" }, { "emc_dripper.ypos", "0" }, { "emc_dripper.frames", "1" }, { "emc_dripper.EDITOR", "RocksEMC.pcx" }, { "emc_dripper.EDITOR.xpos", "8" }, { "emc_dripper.EDITOR.ypos", "8" }, { "emc_dripper.active", "RocksEMC.pcx" }, { "emc_dripper.active.xpos", "8" }, { "emc_dripper.active.ypos", "8" }, { "emc_dripper.active.frames", "1" }, /* (these are only defined as elements to support ".PANEL" definitions) */ { "graphic_1", UNDEFINED_FILENAME }, { "graphic_2", UNDEFINED_FILENAME }, { "graphic_3", UNDEFINED_FILENAME }, { "graphic_4", UNDEFINED_FILENAME }, { "graphic_5", UNDEFINED_FILENAME }, { "graphic_6", UNDEFINED_FILENAME }, { "graphic_7", UNDEFINED_FILENAME }, { "graphic_8", UNDEFINED_FILENAME }, #include "conf_chr.c" /* include auto-generated data structure definitions */ #include "conf_cus.c" /* include auto-generated data structure definitions */ #include "conf_grp.c" /* include auto-generated data structure definitions */ /* images not associated to game elements (used for menu screens etc.) */ /* keyword to stop parser: "NO_MORE_ELEMENT_IMAGES" <-- do not change! */ #if 1 /* !!! TEMPORARILY STORED HERE -- PROBABLY TO BE CHANGED !!! */ /* (for testing, change filename back to "emc_objects dot pcx") */ { "emc_object", "RocksEMC.pcx" }, #if 0 { "emc_object.scale_up_factor", "2" }, #endif /* (for testing, change filename back to "emc_players dot pcx") */ { "emc_sprite", "RocksEMC.pcx" }, #if 0 { "emc_sprite.scale_up_factor", "2" }, #endif #endif { "sp_frame_horizontal", "RocksSP.pcx" }, { "sp_frame_horizontal.xpos", "7" }, { "sp_frame_horizontal.ypos", "14" }, { "sp_frame_vertical", "RocksSP.pcx" }, { "sp_frame_vertical.xpos", "6" }, { "sp_frame_vertical.ypos", "14" }, { "sp_frame_corner", "RocksSP.pcx" }, { "sp_frame_corner.xpos", "5" }, { "sp_frame_corner.ypos", "14" }, { "toon_1", "RocksToons.pcx" }, { "toon_1.x", "2" }, { "toon_1.y", "72" }, { "toon_1.width", "40" }, { "toon_1.height", "48" }, { "toon_1.frames", "8" }, { "toon_1.delay", "1" }, { "toon_1.step_offset", "4" }, { "toon_1.step_delay", "5" }, { "toon_1.direction", "right" }, { "toon_1.position", "bottom" }, { "toon_2", "RocksToons.pcx" }, { "toon_2.x", "2" }, { "toon_2.y", "186" }, { "toon_2.width", "40" }, { "toon_2.height", "48" }, { "toon_2.frames", "8" }, { "toon_2.delay", "1" }, { "toon_2.step_offset", "4" }, { "toon_2.step_delay", "5" }, { "toon_2.direction", "left" }, { "toon_2.position", "bottom" }, { "toon_3", "RocksToons.pcx" }, { "toon_3.x", "2" }, { "toon_3.y", "125" }, { "toon_3.width", "48" }, { "toon_3.height", "56" }, { "toon_3.frames", "8" }, { "toon_3.delay", "1" }, { "toon_3.step_offset", "4" }, { "toon_3.step_delay", "5" }, { "toon_3.direction", "right" }, { "toon_3.position", "bottom" }, { "toon_4", "RocksToons.pcx" }, { "toon_4.x", "327" }, { "toon_4.y", "10" }, { "toon_4.width", "80" }, { "toon_4.height", "110" }, { "toon_4.frames", "1" }, { "toon_4.delay", "1" }, { "toon_4.step_offset", "1" }, { "toon_4.step_delay", "1" }, { "toon_4.direction", "up" }, { "toon_4.position", "any" }, { "toon_5", "RocksToons.pcx" }, { "toon_5.x", "2" }, { "toon_5.y", "2" }, { "toon_5.width", "32" }, { "toon_5.height", "30" }, { "toon_5.frames", "8" }, { "toon_5.delay", "2" }, { "toon_5.anim_mode", "pingpong2" }, { "toon_5.step_offset", "2" }, { "toon_5.step_delay", "1" }, { "toon_5.direction", "right" }, { "toon_5.position", "upper" }, { "toon_6", "RocksToons.pcx" }, { "toon_6.x", "2" }, { "toon_6.y", "37" }, { "toon_6.width", "32" }, { "toon_6.height", "30" }, { "toon_6.frames", "8" }, { "toon_6.delay", "2" }, { "toon_6.anim_mode", "pingpong2" }, { "toon_6.step_offset", "2" }, { "toon_6.step_delay", "1" }, { "toon_6.direction", "left" }, { "toon_6.position", "upper" }, { "toon_7", "RocksMore.pcx" }, { "toon_7.xpos", "0" }, { "toon_7.ypos", "6" }, { "toon_7.frames", "16" }, { "toon_7.delay", "2" }, { "toon_7.direction", "down" }, { "toon_7.position", "any" }, { "toon_8", "RocksHeroes.pcx" }, { "toon_8.xpos", "4" }, { "toon_8.ypos", "1" }, { "toon_8.frames", "4" }, { "toon_8.delay", "4" }, { "toon_8.direction", "right" }, { "toon_8.position", "bottom" }, { "toon_9", "RocksHeroes.pcx" }, { "toon_9.xpos", "8" }, { "toon_9.ypos", "7" }, { "toon_9.frames", "4" }, { "toon_9.delay", "2" }, { "toon_9.direction", "left" }, { "toon_9.position", "bottom" }, { "toon_10", "RocksHeroes.pcx" }, { "toon_10.xpos", "12" }, { "toon_10.ypos", "7" }, { "toon_10.frames", "4" }, { "toon_10.delay", "2" }, { "toon_10.direction", "right" }, { "toon_10.position", "bottom" }, { "toon_11", "RocksHeroes.pcx" }, { "toon_11.xpos", "8" }, { "toon_11.ypos", "5" }, { "toon_11.frames", "4" }, { "toon_11.delay", "2" }, { "toon_11.direction", "left" }, { "toon_11.position", "bottom" }, { "toon_12", "RocksHeroes.pcx" }, { "toon_12.xpos", "12" }, { "toon_12.ypos", "5" }, { "toon_12.frames", "4" }, { "toon_12.delay", "2" }, { "toon_12.direction", "right" }, { "toon_12.position", "bottom" }, { "toon_13", "RocksHeroes.pcx" }, { "toon_13.xpos", "8" }, { "toon_13.ypos", "1" }, { "toon_13.frames", "4" }, { "toon_13.delay", "2" }, { "toon_13.direction", "left" }, { "toon_13.position", "bottom" }, { "toon_14", "RocksHeroes.pcx" }, { "toon_14.xpos", "12" }, { "toon_14.ypos", "1" }, { "toon_14.frames", "4" }, { "toon_14.delay", "2" }, { "toon_14.direction", "right" }, { "toon_14.position", "bottom" }, { "toon_15", "RocksHeroes.pcx" }, { "toon_15.xpos", "8" }, { "toon_15.ypos", "3" }, { "toon_15.frames", "4" }, { "toon_15.delay", "2" }, { "toon_15.direction", "left" }, { "toon_15.position", "bottom" }, { "toon_16", "RocksHeroes.pcx" }, { "toon_16.xpos", "12" }, { "toon_16.ypos", "3" }, { "toon_16.frames", "4" }, { "toon_16.delay", "2" }, { "toon_16.direction", "right" }, { "toon_16.position", "bottom" }, { "toon_17", "RocksHeroes.pcx" }, { "toon_17.xpos", "8" }, { "toon_17.ypos", "9" }, { "toon_17.frames", "8" }, { "toon_17.delay", "2" }, { "toon_17.direction", "left" }, { "toon_17.position", "any" }, { "toon_18", "RocksHeroes.pcx" }, { "toon_18.xpos", "8" }, { "toon_18.ypos", "9" }, { "toon_18.frames", "8" }, { "toon_18.delay", "2" }, { "toon_18.direction", "right" }, { "toon_18.position", "any" }, { "toon_19", "RocksElements.pcx" }, { "toon_19.xpos", "8" }, { "toon_19.ypos", "0" }, { "toon_19.frames", "2" }, { "toon_19.delay", "4" }, { "toon_19.direction", "down" }, { "toon_19.position", "any" }, { "toon_20", "RocksElements.pcx" }, { "toon_20.xpos", "10" }, { "toon_20.ypos", "0" }, { "toon_20.frames", "2" }, { "toon_20.delay", "4" }, { "toon_20.direction", "down" }, { "toon_20.position", "any" }, { "menu.calibrate_red", "RocksElements.pcx" }, { "menu.calibrate_red.xpos", "12" }, { "menu.calibrate_red.ypos", "8" }, { "menu.calibrate_red.frames", "1" }, { "menu.calibrate_blue", "RocksElements.pcx" }, { "menu.calibrate_blue.xpos", "13" }, { "menu.calibrate_blue.ypos", "8" }, { "menu.calibrate_blue.frames", "1" }, { "menu.calibrate_yellow", "RocksElements.pcx" }, { "menu.calibrate_yellow.xpos", "14" }, { "menu.calibrate_yellow.ypos", "8" }, { "menu.calibrate_yellow.frames", "1" }, { "menu.button", "RocksElements.pcx" }, { "menu.button.xpos", "13" }, { "menu.button.ypos", "8" }, { "menu.button.frames", "1" }, { "menu.button.active", "RocksElements.pcx" }, { "menu.button.active.xpos", "12" }, { "menu.button.active.ypos", "8" }, { "menu.button.active.frames", "1" }, { "menu.button_left", "RocksDC.pcx" }, { "menu.button_left.xpos", "8" }, { "menu.button_left.ypos", "8" }, { "menu.button_left.frames", "1" }, { "menu.button_left.active", "RocksDC.pcx" }, { "menu.button_left.active.xpos", "8" }, { "menu.button_left.active.ypos", "9" }, { "menu.button_left.active.frames", "1" }, { "menu.button_right", "RocksDC.pcx" }, { "menu.button_right.xpos", "9" }, { "menu.button_right.ypos", "8" }, { "menu.button_right.frames", "1" }, { "menu.button_right.active", "RocksDC.pcx" }, { "menu.button_right.active.xpos", "9" }, { "menu.button_right.active.ypos", "9" }, { "menu.button_right.active.frames", "1" }, { "menu.button_up", "RocksDC.pcx" }, { "menu.button_up.xpos", "10" }, { "menu.button_up.ypos", "8" }, { "menu.button_up.frames", "1" }, { "menu.button_up.active", "RocksDC.pcx" }, { "menu.button_up.active.xpos", "10" }, { "menu.button_up.active.ypos", "9" }, { "menu.button_up.active.frames", "1" }, { "menu.button_down", "RocksDC.pcx" }, { "menu.button_down.xpos", "11" }, { "menu.button_down.ypos", "8" }, { "menu.button_down.frames", "1" }, { "menu.button_down.active", "RocksDC.pcx" }, { "menu.button_down.active.xpos", "11" }, { "menu.button_down.active.ypos", "9" }, { "menu.button_down.active.frames", "1" }, { "menu.button_enter_menu", UNDEFINED_FILENAME }, { "menu.button_enter_menu.clone_from", "menu.button_right" }, { "menu.button_enter_menu.active", UNDEFINED_FILENAME }, { "menu.button_enter_menu.active.clone_from", "menu.button_right.active" }, { "menu.button_leave_menu", UNDEFINED_FILENAME }, { "menu.button_leave_menu.clone_from", "menu.button_left" }, { "menu.button_leave_menu.active", UNDEFINED_FILENAME }, { "menu.button_leave_menu.active.clone_from", "menu.button_left.active" }, { "menu.button_next_level", UNDEFINED_FILENAME }, { "menu.button_next_level.clone_from", "menu.button_right" }, { "menu.button_next_level.active", UNDEFINED_FILENAME }, { "menu.button_next_level.active.clone_from", "menu.button_right.active" }, { "menu.button_prev_level", UNDEFINED_FILENAME }, { "menu.button_prev_level.clone_from", "menu.button_left" }, { "menu.button_prev_level.active", UNDEFINED_FILENAME }, { "menu.button_prev_level.active.clone_from", "menu.button_left.active" }, { "menu.button_name", UNDEFINED_FILENAME }, { "menu.button_name.clone_from", "menu.button" }, { "menu.button_name.active", UNDEFINED_FILENAME }, { "menu.button_name.active.clone_from", "menu.button.active" }, { "menu.button_levels", UNDEFINED_FILENAME }, { "menu.button_levels.clone_from", "menu.button_right" }, { "menu.button_levels.active", UNDEFINED_FILENAME }, { "menu.button_levels.active.clone_from", "menu.button_right.active" }, { "menu.button_scores", UNDEFINED_FILENAME }, { "menu.button_scores.clone_from", "menu.button" }, { "menu.button_scores.active", UNDEFINED_FILENAME }, { "menu.button_scores.active.clone_from", "menu.button.active" }, { "menu.button_editor", UNDEFINED_FILENAME }, { "menu.button_editor.clone_from", "menu.button" }, { "menu.button_editor.active", UNDEFINED_FILENAME }, { "menu.button_editor.active.clone_from", "menu.button.active" }, { "menu.button_info", UNDEFINED_FILENAME }, { "menu.button_info.clone_from", "menu.button_right" }, { "menu.button_info.active", UNDEFINED_FILENAME }, { "menu.button_info.active.clone_from", "menu.button_right.active" }, { "menu.button_game", UNDEFINED_FILENAME }, { "menu.button_game.clone_from", "menu.button" }, { "menu.button_game.active", UNDEFINED_FILENAME }, { "menu.button_game.active.clone_from", "menu.button.active" }, { "menu.button_setup", UNDEFINED_FILENAME }, { "menu.button_setup.clone_from", "menu.button_right" }, { "menu.button_setup.active", UNDEFINED_FILENAME }, { "menu.button_setup.active.clone_from", "menu.button_right.active" }, { "menu.button_quit", UNDEFINED_FILENAME }, { "menu.button_quit.clone_from", "menu.button" }, { "menu.button_quit.active", UNDEFINED_FILENAME }, { "menu.button_quit.active.clone_from", "menu.button.active" }, { "menu.scrollbar", "RocksDC.pcx" }, { "menu.scrollbar.xpos", "8" }, { "menu.scrollbar.ypos", "10" }, { "menu.scrollbar.frames", "1" }, { "menu.scrollbar.active", "RocksDC.pcx" }, { "menu.scrollbar.active.xpos", "9" }, { "menu.scrollbar.active.ypos", "10" }, { "menu.scrollbar.active.frames", "1" }, { "font.initial_1", "RocksFontSmall.pcx" }, { "font.initial_1.x", "0" }, { "font.initial_1.y", "0" }, { "font.initial_1.width", "14" }, { "font.initial_1.height", "14" }, { "font.initial_2", "RocksFontSmall.pcx" }, { "font.initial_2.x", "0" }, { "font.initial_2.y", "70" }, { "font.initial_2.width", "14" }, { "font.initial_2.height", "14" }, { "font.initial_3", "RocksFontSmall.pcx" }, { "font.initial_3.x", "0" }, { "font.initial_3.y", "140" }, { "font.initial_3.width", "14" }, { "font.initial_3.height", "14" }, { "font.initial_4", "RocksFontSmall.pcx" }, { "font.initial_4.x", "0" }, { "font.initial_4.y", "210" }, { "font.initial_4.width", "14" }, { "font.initial_4.height", "14" }, { "font.title_1", "RocksFontBig.pcx" }, { "font.title_1.x", "0" }, { "font.title_1.y", "480" }, { "font.title_1.width", "32" }, { "font.title_1.height", "32" }, { "font.title_2", "RocksFontSmall.pcx" }, { "font.title_2.x", "0" }, { "font.title_2.y", "0" }, { "font.title_2.width", "14" }, { "font.title_2.height", "14" }, { "font.title_2.SETUP", UNDEFINED_FILENAME }, { "font.title_2.SETUP.clone_from", "font.text_4" }, { "font.menu_1", "RocksFontBig.pcx" }, { "font.menu_1.x", "0" }, { "font.menu_1.y", "320" }, { "font.menu_1.width", "32" }, { "font.menu_1.height", "32" }, { "font.menu_1.active", "RocksFontBig.pcx" }, { "font.menu_1.active.x", "0" }, { "font.menu_1.active.y", "480" }, { "font.menu_1.active.width", "32" }, { "font.menu_1.active.height", "32" }, { "font.menu_2", "RocksFontMedium.pcx" }, { "font.menu_2.x", "0" }, { "font.menu_2.y", "320" }, { "font.menu_2.width", "16" }, { "font.menu_2.height", "32" }, { "font.menu_2.active", "RocksFontMedium.pcx" }, { "font.menu_2.active.x", "0" }, { "font.menu_2.active.y", "480" }, { "font.menu_2.active.width", "16" }, { "font.menu_2.active.height", "32" }, { "font.text_1", "RocksFontSmall.pcx" }, { "font.text_1.x", "0" }, { "font.text_1.y", "140" }, { "font.text_1.width", "14" }, { "font.text_1.height", "14" }, { "font.text_1.MAIN", UNDEFINED_FILENAME }, { "font.text_1.MAIN.clone_from", "font.text_1.PREVIEW" }, { "font.text_1.LEVELS", "RocksFontMedium.pcx" }, { "font.text_1.LEVELS.x", "0" }, { "font.text_1.LEVELS.y", "0" }, { "font.text_1.LEVELS.width", "16" }, { "font.text_1.LEVELS.height", "32" }, { "font.text_1.SETUP", UNDEFINED_FILENAME }, { "font.text_1.SETUP.clone_from", "font.text_1.LEVELS" }, { "font.text_1.PREVIEW", "RocksFontEM.pcx" }, { "font.text_1.PREVIEW.x", "0" }, { "font.text_1.PREVIEW.y", "160" }, { "font.text_1.PREVIEW.width", "16" }, { "font.text_1.PREVIEW.height", "16" }, { "font.text_1.SCORES", "RocksFontMedium.pcx" }, { "font.text_1.SCORES.x", "0" }, { "font.text_1.SCORES.y", "480" }, { "font.text_1.SCORES.width", "16" }, { "font.text_1.SCORES.height", "32" }, { "font.text_1.active.SCORES", "RocksFontMedium.pcx" }, { "font.text_1.active.SCORES.x", "0" }, { "font.text_1.active.SCORES.y", "0" }, { "font.text_1.active.SCORES.width", "16" }, { "font.text_1.active.SCORES.height", "32" }, { "font.text_1.PANEL", UNDEFINED_FILENAME }, { "font.text_1.PANEL.clone_from", "font.level_number" }, { "font.text_1.DOOR", UNDEFINED_FILENAME }, { "font.text_1.DOOR.clone_from", "font.level_number" }, { "font.text_2", "RocksFontSmall.pcx" }, { "font.text_2.x", "0" }, { "font.text_2.y", "210" }, { "font.text_2.width", "14" }, { "font.text_2.height", "14" }, { "font.text_2.MAIN", UNDEFINED_FILENAME }, { "font.text_2.MAIN.clone_from", "font.text_2.PREVIEW" }, { "font.text_2.LEVELS", "RocksFontMedium.pcx" }, { "font.text_2.LEVELS.x", "0" }, { "font.text_2.LEVELS.y", "160" }, { "font.text_2.LEVELS.width", "16" }, { "font.text_2.LEVELS.height", "32" }, { "font.text_2.SETUP", UNDEFINED_FILENAME }, { "font.text_2.SETUP.clone_from", "font.text_2.LEVELS" }, { "font.text_2.PREVIEW", "RocksFontEM.pcx" }, { "font.text_2.PREVIEW.x", "0" }, { "font.text_2.PREVIEW.y", "160" }, { "font.text_2.PREVIEW.width", "16" }, { "font.text_2.PREVIEW.height", "16" }, { "font.text_2.SCORES", "RocksFontBig.pcx" }, { "font.text_2.SCORES.x", "0" }, { "font.text_2.SCORES.y", "320" }, { "font.text_2.SCORES.width", "32" }, { "font.text_2.SCORES.height", "32" }, { "font.text_2.active.SCORES", "RocksFontBig.pcx" }, { "font.text_2.active.SCORES.x", "0" }, { "font.text_2.active.SCORES.y", "0" }, { "font.text_2.active.SCORES.width", "32" }, { "font.text_2.active.SCORES.height", "32" }, { "font.text_3", "RocksFontSmall.pcx" }, { "font.text_3.x", "0" }, { "font.text_3.y", "0" }, { "font.text_3.width", "14" }, { "font.text_3.height", "14" }, { "font.text_3.LEVELS", "RocksFontMedium.pcx" }, { "font.text_3.LEVELS.x", "0" }, { "font.text_3.LEVELS.y", "320" }, { "font.text_3.LEVELS.width", "16" }, { "font.text_3.LEVELS.height", "32" }, { "font.text_3.SETUP", UNDEFINED_FILENAME }, { "font.text_3.SETUP.clone_from", "font.text_3.LEVELS" }, { "font.text_3.PREVIEW", "RocksFontEM.pcx" }, { "font.text_3.PREVIEW.x", "0" }, { "font.text_3.PREVIEW.y", "160" }, { "font.text_3.PREVIEW.width", "16" }, { "font.text_3.PREVIEW.height", "16" }, { "font.text_3.SCORES", "RocksFontMedium.pcx" }, { "font.text_3.SCORES.x", "0" }, { "font.text_3.SCORES.y", "480" }, { "font.text_3.SCORES.width", "16" }, { "font.text_3.SCORES.height", "32" }, { "font.text_3.active.SCORES", "RocksFontMedium.pcx" }, { "font.text_3.active.SCORES.x", "0" }, { "font.text_3.active.SCORES.y", "0" }, { "font.text_3.active.SCORES.width", "16" }, { "font.text_3.active.SCORES.height", "32" }, { "font.text_4", "RocksFontSmall.pcx" }, { "font.text_4.x", "0" }, { "font.text_4.y", "70" }, { "font.text_4.width", "14" }, { "font.text_4.height", "14" }, { "font.text_4.MAIN", UNDEFINED_FILENAME }, { "font.text_4.MAIN.clone_from", "font.text_3.PREVIEW" }, { "font.text_4.LEVELS", "RocksFontMedium.pcx" }, { "font.text_4.LEVELS.x", "0" }, { "font.text_4.LEVELS.y", "480" }, { "font.text_4.LEVELS.width", "16" }, { "font.text_4.LEVELS.height", "32" }, { "font.text_4.SETUP", UNDEFINED_FILENAME }, { "font.text_4.SETUP.clone_from", "font.text_4.LEVELS" }, { "font.text_4.SCORES", "RocksFontMedium.pcx" }, { "font.text_4.SCORES.x", "0" }, { "font.text_4.SCORES.y", "480" }, { "font.text_4.SCORES.width", "16" }, { "font.text_4.SCORES.height", "32" }, { "font.text_4.active.SCORES", "RocksFontMedium.pcx" }, { "font.text_4.active.SCORES.x", "0" }, { "font.text_4.active.SCORES.y", "0" }, { "font.text_4.active.SCORES.width", "16" }, { "font.text_4.active.SCORES.height", "32" }, { "font.envelope_1", "RocksFontEM.pcx" }, { "font.envelope_1.x", "0" }, { "font.envelope_1.y", "160" }, { "font.envelope_1.width", "16" }, { "font.envelope_1.height", "16" }, { "font.envelope_2", "RocksFontEM.pcx" }, { "font.envelope_2.x", "0" }, { "font.envelope_2.y", "160" }, { "font.envelope_2.width", "16" }, { "font.envelope_2.height", "16" }, { "font.envelope_3", "RocksFontEM.pcx" }, { "font.envelope_3.x", "0" }, { "font.envelope_3.y", "160" }, { "font.envelope_3.width", "16" }, { "font.envelope_3.height", "16" }, { "font.envelope_4", "RocksFontEM.pcx" }, { "font.envelope_4.x", "0" }, { "font.envelope_4.y", "160" }, { "font.envelope_4.width", "16" }, { "font.envelope_4.height", "16" }, { "font.input_1", "RocksFontSmall.pcx" }, { "font.input_1.x", "0" }, { "font.input_1.y", "210" }, { "font.input_1.width", "14" }, { "font.input_1.height", "14" }, { "font.input_1.MAIN", "RocksFontBig.pcx" }, { "font.input_1.MAIN.x", "0" }, { "font.input_1.MAIN.y", "0" }, { "font.input_1.MAIN.width", "32" }, { "font.input_1.MAIN.height", "32" }, { "font.input_1.active", "RocksFontSmall.pcx" }, { "font.input_1.active.x", "0" }, { "font.input_1.active.y", "210" }, { "font.input_1.active.width", "14" }, { "font.input_1.active.height", "14" }, { "font.input_1.active.MAIN", "RocksFontBig.pcx" }, { "font.input_1.active.MAIN.x", "0" }, { "font.input_1.active.MAIN.y", "480" }, { "font.input_1.active.MAIN.width", "32" }, { "font.input_1.active.MAIN.height", "32" }, { "font.input_1.active.SETUP", "RocksFontBig.pcx" }, { "font.input_1.active.SETUP.x", "0" }, { "font.input_1.active.SETUP.y", "0" }, { "font.input_1.active.SETUP.width", "32" }, { "font.input_1.active.SETUP.height", "32" }, { "font.input_2", "RocksFontSmall.pcx" }, { "font.input_2.x", "0" }, { "font.input_2.y", "210" }, { "font.input_2.width", "14" }, { "font.input_2.height", "14" }, { "font.input_2.active", "RocksFontSmall.pcx" }, { "font.input_2.active.x", "0" }, { "font.input_2.active.y", "210" }, { "font.input_2.active.width", "14" }, { "font.input_2.active.height", "14" }, { "font.option_off", "RocksFontBig.pcx" }, { "font.option_off.x", "0" }, { "font.option_off.y", "160" }, { "font.option_off.width", "32" }, { "font.option_off.height", "32" }, { "font.option_on", "RocksFontBig.pcx" }, { "font.option_on.x", "0" }, { "font.option_on.y", "480" }, { "font.option_on.width", "32" }, { "font.option_on.height", "32" }, { "font.value_1", "RocksFontBig.pcx" }, { "font.value_1.x", "0" }, { "font.value_1.y", "480" }, { "font.value_1.width", "32" }, { "font.value_1.height", "32" }, { "font.value_2", "RocksFontMedium.pcx" }, { "font.value_2.x", "0" }, { "font.value_2.y", "480" }, { "font.value_2.width", "16" }, { "font.value_2.height", "32" }, { "font.value_old", "RocksFontBig.pcx" }, { "font.value_old.x", "0" }, { "font.value_old.y", "160" }, { "font.value_old.width", "32" }, { "font.value_old.height", "32" }, { "font.level_number", "RocksFontSmall.pcx" }, { "font.level_number.x", "0" }, { "font.level_number.y", "350" }, { "font.level_number.width", "10" }, { "font.level_number.height", "14" }, { "font.level_number.active", UNDEFINED_FILENAME }, { "font.level_number.active.clone_from", "font.level_number" }, { "font.tape_recorder", "RocksFontSmall.pcx" }, { "font.tape_recorder.x", "0" }, { "font.tape_recorder.y", "280" }, { "font.tape_recorder.width", "11" }, { "font.tape_recorder.height", "14" }, { "font.game_info", "RocksFontEM.pcx" }, { "font.game_info.xpos", "0" }, { "font.game_info.ypos", "0" }, { "font.game_info.delay", "10" }, { "font.info.elements", UNDEFINED_FILENAME }, { "font.info.elements.clone_from", "font.level_number" }, { "font.info.levelset", UNDEFINED_FILENAME }, { "font.info.levelset.clone_from", "font.level_number" }, { "global.border", "RocksScreen.pcx" }, { "global.door", "RocksDoor.pcx" }, { "global.busy", "RocksBusy.pcx" }, { "global.busy.x", "0" }, { "global.busy.y", "0" }, { "global.busy.width", "32" }, { "global.busy.height", "32" }, { "global.busy.frames", "28" }, { "global.busy.frames_per_line", "7" }, { "global.busy.delay", "2" }, { "editor.element_border", "RocksElements.pcx" }, { "editor.element_border.x", "0" }, { "editor.element_border.y", "0" }, { "editor.element_border_input", "RocksDoor.pcx" }, { "editor.element_border_input.x", "740" }, { "editor.element_border_input.y", "48" }, { "editor.cascade_list", "RocksDoor.pcx" }, { "editor.cascade_list.x", "708" }, { "editor.cascade_list.y", "80" }, { "editor.cascade_list.frames", "1" }, { "editor.cascade_list.active", "RocksDoor.pcx" }, { "editor.cascade_list.active.x", "740" }, { "editor.cascade_list.active.y", "80" }, { "editor.cascade_list.active.frames", "1" }, { "background", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.SCORES", UNDEFINED_FILENAME }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", UNDEFINED_FILENAME }, { "background.INFO[ELEMENTS]", UNDEFINED_FILENAME }, { "background.INFO[MUSIC]", UNDEFINED_FILENAME }, { "background.INFO[CREDITS]", UNDEFINED_FILENAME }, { "background.INFO[PROGRAM]", UNDEFINED_FILENAME }, { "background.INFO[VERSION]", UNDEFINED_FILENAME }, { "background.INFO[LEVELSET]", UNDEFINED_FILENAME }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.PLAYING", UNDEFINED_FILENAME }, { "background.DOOR", UNDEFINED_FILENAME }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1", UNDEFINED_FILENAME }, { "background.titlemessage_initial_2", UNDEFINED_FILENAME }, { "background.titlemessage_initial_3", UNDEFINED_FILENAME }, { "background.titlemessage_initial_4", UNDEFINED_FILENAME }, { "background.titlemessage_initial_5", UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, { "background.envelope_1", "RocksScreen.pcx" }, { "background.envelope_1.x", "0" }, { "background.envelope_1.y", "0" }, { "background.envelope_1.width", "560" }, { "background.envelope_1.height", "560" }, { "background.envelope_1.anim_mode", "default" }, { "background.envelope_1.draw_masked", "false" }, { "background.envelope_2", "RocksScreen.pcx" }, { "background.envelope_2.x", "0" }, { "background.envelope_2.y", "0" }, { "background.envelope_2.width", "560" }, { "background.envelope_2.height", "560" }, { "background.envelope_2.anim_mode", "default" }, { "background.envelope_2.draw_masked", "false" }, { "background.envelope_3", "RocksScreen.pcx" }, { "background.envelope_3.x", "0" }, { "background.envelope_3.y", "0" }, { "background.envelope_3.width", "560" }, { "background.envelope_3.height", "560" }, { "background.envelope_3.anim_mode", "default" }, { "background.envelope_3.draw_masked", "false" }, { "background.envelope_4", "RocksScreen.pcx" }, { "background.envelope_4.x", "0" }, { "background.envelope_4.y", "0" }, { "background.envelope_4.width", "560" }, { "background.envelope_4.height", "560" }, { "background.envelope_4.anim_mode", "default" }, { "background.envelope_4.draw_masked", "false" }, { "titlescreen_initial_1", UNDEFINED_FILENAME }, { "titlescreen_initial_2", UNDEFINED_FILENAME }, { "titlescreen_initial_3", UNDEFINED_FILENAME }, { "titlescreen_initial_4", UNDEFINED_FILENAME }, { "titlescreen_initial_5", UNDEFINED_FILENAME }, { "titlescreen_1", UNDEFINED_FILENAME }, { "titlescreen_2", UNDEFINED_FILENAME }, { "titlescreen_3", UNDEFINED_FILENAME }, { "titlescreen_4", UNDEFINED_FILENAME }, { "titlescreen_5", UNDEFINED_FILENAME }, /* the following directives are not associated with an image, but probably make sense to be defined in "graphicsinfo.conf", too */ /* keyword to start parser: "CONFIG_VARS_START" <-- do not change! */ { "[title_initial].fade_mode", "fade" }, { "[title_initial].fade_delay", "500" }, { "[title_initial].post_delay", "250" }, { "[title_initial].auto_delay", "-1" }, { "[title].fade_mode", "fade" }, { "[title].fade_delay", "500" }, { "[title].post_delay", "250" }, { "[title].auto_delay", "-1" }, { "[titlemessage_initial].x", "336" }, { "[titlemessage_initial].y", "280" }, { "[titlemessage_initial].width", "640" }, { "[titlemessage_initial].height", "512" }, { "[titlemessage_initial].chars", "-1" }, { "[titlemessage_initial].lines", "-1" }, { "[titlemessage_initial].align", "center" }, { "[titlemessage_initial].valign", "middle" }, { "[titlemessage_initial].font", "font.text_1" }, { "[titlemessage_initial].autowrap", "false" }, { "[titlemessage_initial].centered", "false" }, { "[titlemessage_initial].parse_comments", "false" }, { "[titlemessage_initial].sort_priority", "0" }, { "[titlemessage_initial].fade_mode", ARG_DEFAULT }, { "[titlemessage_initial].fade_delay", ARG_DEFAULT }, { "[titlemessage_initial].post_delay", ARG_DEFAULT }, { "[titlemessage_initial].auto_delay", ARG_DEFAULT }, { "[titlemessage].x", "336" }, { "[titlemessage].y", "280" }, { "[titlemessage].width", "640" }, { "[titlemessage].height", "512" }, { "[titlemessage].chars", "-1" }, { "[titlemessage].lines", "-1" }, { "[titlemessage].align", "center" }, { "[titlemessage].valign", "middle" }, { "[titlemessage].font", "font.text_1" }, { "[titlemessage].autowrap", "false" }, { "[titlemessage].centered", "false" }, { "[titlemessage].parse_comments", "false" }, { "[titlemessage].sort_priority", "0" }, { "[titlemessage].fade_mode", ARG_DEFAULT }, { "[titlemessage].fade_delay", ARG_DEFAULT }, { "[titlemessage].post_delay", ARG_DEFAULT }, { "[titlemessage].auto_delay", ARG_DEFAULT }, { "titlemessage_initial_1.x", ARG_DEFAULT }, { "titlemessage_initial_1.y", ARG_DEFAULT }, { "titlemessage_initial_1.width", ARG_DEFAULT }, { "titlemessage_initial_1.height", ARG_DEFAULT }, { "titlemessage_initial_1.chars", ARG_DEFAULT }, { "titlemessage_initial_1.lines", ARG_DEFAULT }, { "titlemessage_initial_1.align", ARG_DEFAULT }, { "titlemessage_initial_1.valign", ARG_DEFAULT }, { "titlemessage_initial_1.font", ARG_DEFAULT }, { "titlemessage_initial_1.autowrap", ARG_DEFAULT }, { "titlemessage_initial_1.centered", ARG_DEFAULT }, { "titlemessage_initial_1.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_1.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_1.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_1.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_1.post_delay", ARG_DEFAULT }, { "titlemessage_initial_1.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_2.x", ARG_DEFAULT }, { "titlemessage_initial_2.y", ARG_DEFAULT }, { "titlemessage_initial_2.width", ARG_DEFAULT }, { "titlemessage_initial_2.height", ARG_DEFAULT }, { "titlemessage_initial_2.chars", ARG_DEFAULT }, { "titlemessage_initial_2.lines", ARG_DEFAULT }, { "titlemessage_initial_2.align", ARG_DEFAULT }, { "titlemessage_initial_2.valign", ARG_DEFAULT }, { "titlemessage_initial_2.font", ARG_DEFAULT }, { "titlemessage_initial_2.autowrap", ARG_DEFAULT }, { "titlemessage_initial_2.centered", ARG_DEFAULT }, { "titlemessage_initial_2.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_2.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_2.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_2.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_2.post_delay", ARG_DEFAULT }, { "titlemessage_initial_2.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_3.x", ARG_DEFAULT }, { "titlemessage_initial_3.y", ARG_DEFAULT }, { "titlemessage_initial_3.width", ARG_DEFAULT }, { "titlemessage_initial_3.height", ARG_DEFAULT }, { "titlemessage_initial_3.chars", ARG_DEFAULT }, { "titlemessage_initial_3.lines", ARG_DEFAULT }, { "titlemessage_initial_3.align", ARG_DEFAULT }, { "titlemessage_initial_3.valign", ARG_DEFAULT }, { "titlemessage_initial_3.font", ARG_DEFAULT }, { "titlemessage_initial_3.autowrap", ARG_DEFAULT }, { "titlemessage_initial_3.centered", ARG_DEFAULT }, { "titlemessage_initial_3.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_3.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_3.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_3.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_3.post_delay", ARG_DEFAULT }, { "titlemessage_initial_3.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_4.x", ARG_DEFAULT }, { "titlemessage_initial_4.y", ARG_DEFAULT }, { "titlemessage_initial_4.width", ARG_DEFAULT }, { "titlemessage_initial_4.height", ARG_DEFAULT }, { "titlemessage_initial_4.chars", ARG_DEFAULT }, { "titlemessage_initial_4.lines", ARG_DEFAULT }, { "titlemessage_initial_4.align", ARG_DEFAULT }, { "titlemessage_initial_4.valign", ARG_DEFAULT }, { "titlemessage_initial_4.font", ARG_DEFAULT }, { "titlemessage_initial_4.autowrap", ARG_DEFAULT }, { "titlemessage_initial_4.centered", ARG_DEFAULT }, { "titlemessage_initial_4.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_4.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_4.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_4.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_4.post_delay", ARG_DEFAULT }, { "titlemessage_initial_4.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_5.x", ARG_DEFAULT }, { "titlemessage_initial_5.y", ARG_DEFAULT }, { "titlemessage_initial_5.width", ARG_DEFAULT }, { "titlemessage_initial_5.height", ARG_DEFAULT }, { "titlemessage_initial_5.chars", ARG_DEFAULT }, { "titlemessage_initial_5.lines", ARG_DEFAULT }, { "titlemessage_initial_5.align", ARG_DEFAULT }, { "titlemessage_initial_5.valign", ARG_DEFAULT }, { "titlemessage_initial_5.font", ARG_DEFAULT }, { "titlemessage_initial_5.autowrap", ARG_DEFAULT }, { "titlemessage_initial_5.centered", ARG_DEFAULT }, { "titlemessage_initial_5.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_5.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_5.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_5.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_5.post_delay", ARG_DEFAULT }, { "titlemessage_initial_5.auto_delay", ARG_DEFAULT }, { "titlemessage_1.x", ARG_DEFAULT }, { "titlemessage_1.y", ARG_DEFAULT }, { "titlemessage_1.width", ARG_DEFAULT }, { "titlemessage_1.height", ARG_DEFAULT }, { "titlemessage_1.chars", ARG_DEFAULT }, { "titlemessage_1.lines", ARG_DEFAULT }, { "titlemessage_1.align", ARG_DEFAULT }, { "titlemessage_1.valign", ARG_DEFAULT }, { "titlemessage_1.font", ARG_DEFAULT }, { "titlemessage_1.autowrap", ARG_DEFAULT }, { "titlemessage_1.centered", ARG_DEFAULT }, { "titlemessage_1.parse_comments", ARG_DEFAULT }, { "titlemessage_1.sort_priority", ARG_DEFAULT }, { "titlemessage_1.fade_mode", ARG_DEFAULT }, { "titlemessage_1.fade_delay", ARG_DEFAULT }, { "titlemessage_1.post_delay", ARG_DEFAULT }, { "titlemessage_1.auto_delay", ARG_DEFAULT }, { "titlemessage_2.x", ARG_DEFAULT }, { "titlemessage_2.y", ARG_DEFAULT }, { "titlemessage_2.width", ARG_DEFAULT }, { "titlemessage_2.height", ARG_DEFAULT }, { "titlemessage_2.chars", ARG_DEFAULT }, { "titlemessage_2.lines", ARG_DEFAULT }, { "titlemessage_2.align", ARG_DEFAULT }, { "titlemessage_2.valign", ARG_DEFAULT }, { "titlemessage_2.font", ARG_DEFAULT }, { "titlemessage_2.autowrap", ARG_DEFAULT }, { "titlemessage_2.centered", ARG_DEFAULT }, { "titlemessage_2.parse_comments", ARG_DEFAULT }, { "titlemessage_2.sort_priority", ARG_DEFAULT }, { "titlemessage_2.fade_mode", ARG_DEFAULT }, { "titlemessage_2.fade_delay", ARG_DEFAULT }, { "titlemessage_2.post_delay", ARG_DEFAULT }, { "titlemessage_2.auto_delay", ARG_DEFAULT }, { "titlemessage_3.x", ARG_DEFAULT }, { "titlemessage_3.y", ARG_DEFAULT }, { "titlemessage_3.width", ARG_DEFAULT }, { "titlemessage_3.height", ARG_DEFAULT }, { "titlemessage_3.chars", ARG_DEFAULT }, { "titlemessage_3.lines", ARG_DEFAULT }, { "titlemessage_3.align", ARG_DEFAULT }, { "titlemessage_3.valign", ARG_DEFAULT }, { "titlemessage_3.font", ARG_DEFAULT }, { "titlemessage_3.autowrap", ARG_DEFAULT }, { "titlemessage_3.centered", ARG_DEFAULT }, { "titlemessage_3.parse_comments", ARG_DEFAULT }, { "titlemessage_3.sort_priority", ARG_DEFAULT }, { "titlemessage_3.fade_mode", ARG_DEFAULT }, { "titlemessage_3.fade_delay", ARG_DEFAULT }, { "titlemessage_3.post_delay", ARG_DEFAULT }, { "titlemessage_3.auto_delay", ARG_DEFAULT }, { "titlemessage_4.x", ARG_DEFAULT }, { "titlemessage_4.y", ARG_DEFAULT }, { "titlemessage_4.width", ARG_DEFAULT }, { "titlemessage_4.height", ARG_DEFAULT }, { "titlemessage_4.chars", ARG_DEFAULT }, { "titlemessage_4.lines", ARG_DEFAULT }, { "titlemessage_4.align", ARG_DEFAULT }, { "titlemessage_4.valign", ARG_DEFAULT }, { "titlemessage_4.font", ARG_DEFAULT }, { "titlemessage_4.autowrap", ARG_DEFAULT }, { "titlemessage_4.centered", ARG_DEFAULT }, { "titlemessage_4.parse_comments", ARG_DEFAULT }, { "titlemessage_4.sort_priority", ARG_DEFAULT }, { "titlemessage_4.fade_mode", ARG_DEFAULT }, { "titlemessage_4.fade_delay", ARG_DEFAULT }, { "titlemessage_4.post_delay", ARG_DEFAULT }, { "titlemessage_4.auto_delay", ARG_DEFAULT }, { "titlemessage_5.x", ARG_DEFAULT }, { "titlemessage_5.y", ARG_DEFAULT }, { "titlemessage_5.width", ARG_DEFAULT }, { "titlemessage_5.height", ARG_DEFAULT }, { "titlemessage_5.chars", ARG_DEFAULT }, { "titlemessage_5.lines", ARG_DEFAULT }, { "titlemessage_5.align", ARG_DEFAULT }, { "titlemessage_5.valign", ARG_DEFAULT }, { "titlemessage_5.font", ARG_DEFAULT }, { "titlemessage_5.autowrap", ARG_DEFAULT }, { "titlemessage_5.centered", ARG_DEFAULT }, { "titlemessage_5.parse_comments", ARG_DEFAULT }, { "titlemessage_5.sort_priority", ARG_DEFAULT }, { "titlemessage_5.fade_mode", ARG_DEFAULT }, { "titlemessage_5.fade_delay", ARG_DEFAULT }, { "titlemessage_5.post_delay", ARG_DEFAULT }, { "titlemessage_5.auto_delay", ARG_DEFAULT }, { "readme.x", "272" }, { "readme.y", "150" }, { "readme.width", "480" }, { "readme.height", "364" }, { "readme.chars", "-1" }, { "readme.lines", "-1" }, { "readme.align", "center" }, { "readme.valign", "top" }, { "readme.font", "font.info.levelset" }, { "readme.autowrap", "true" }, { "readme.centered", "false" }, { "readme.parse_comments", "true" }, { "readme.sort_priority", "0" }, { "global.num_toons", "20" }, { "border.draw_masked.TITLE", "false" }, { "border.draw_masked.MAIN", "false" }, { "border.draw_masked.LEVELS", "false" }, { "border.draw_masked.SCORES", "false" }, { "border.draw_masked.EDITOR", "false" }, { "border.draw_masked.INFO", "false" }, { "border.draw_masked.SETUP", "false" }, { "border.draw_masked.PLAYING", "false" }, { "border.draw_masked.DOOR", "false" }, { "border.draw_masked_when_fading", "true" }, { "init.busy.x", "336" }, { "init.busy.y", "280" }, { "init.busy.align", "center" }, { "init.busy.valign", "middle" }, { "menu.enter_menu.fade_mode", "none" }, { "menu.enter_menu.fade_delay", "250" }, { "menu.enter_menu.post_delay", "125" }, { "menu.leave_menu.fade_mode", "none" }, { "menu.leave_menu.fade_delay", "250" }, { "menu.leave_menu.post_delay", "125" }, { "menu.enter_screen.fade_mode", "fade" }, { "menu.enter_screen.fade_delay", "250" }, { "menu.enter_screen.post_delay", "125" }, { "menu.next_screen.fade_mode", "crossfade" }, { "menu.next_screen.fade_delay", "250" }, { "menu.next_screen.post_delay", "125" }, { "menu.leave_screen.fade_mode", "fade" }, { "menu.leave_screen.fade_delay", "250" }, { "menu.leave_screen.post_delay", "125" }, { "menu.enter_screen.SCORES.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.SCORES.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.SCORES.post_delay", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.post_delay", ARG_DEFAULT }, { "menu.enter_screen.INFO.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.INFO.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.INFO.post_delay", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.post_delay", ARG_DEFAULT }, { "menu.leave_screen.SCORES.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.SCORES.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.SCORES.post_delay", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.post_delay", ARG_DEFAULT }, { "menu.leave_screen.INFO.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.INFO.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.INFO.post_delay", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.post_delay", ARG_DEFAULT }, { "menu.draw_xoffset", "0" }, { "menu.draw_yoffset", "0" }, { "menu.draw_xoffset.MAIN", "0" }, { "menu.draw_yoffset.MAIN", "0" }, { "menu.draw_xoffset.LEVELS", "0" }, { "menu.draw_yoffset.LEVELS", "0" }, { "menu.draw_xoffset.SCORES", "0" }, { "menu.draw_yoffset.SCORES", "0" }, { "menu.draw_xoffset.EDITOR", "0" }, { "menu.draw_yoffset.EDITOR", "0" }, { "menu.draw_xoffset.INFO", "0" }, { "menu.draw_yoffset.INFO", "0" }, { "menu.draw_xoffset.INFO[ELEMENTS]", "0" }, { "menu.draw_yoffset.INFO[ELEMENTS]", "0" }, { "menu.draw_xoffset.INFO[MUSIC]", "0" }, { "menu.draw_yoffset.INFO[MUSIC]", "0" }, { "menu.draw_xoffset.INFO[CREDITS]", "0" }, { "menu.draw_yoffset.INFO[CREDITS]", "0" }, { "menu.draw_xoffset.INFO[PROGRAM]", "0" }, { "menu.draw_yoffset.INFO[PROGRAM]", "0" }, { "menu.draw_xoffset.INFO[VERSION]", "0" }, { "menu.draw_yoffset.INFO[VERSION]", "0" }, { "menu.draw_xoffset.INFO[LEVELSET]", "0" }, { "menu.draw_yoffset.INFO[LEVELSET]", "0" }, { "menu.draw_xoffset.SETUP", "0" }, { "menu.draw_yoffset.SETUP", "0" }, { "menu.draw_xoffset.SETUP[GAME]", "0" }, { "menu.draw_yoffset.SETUP[GAME]", "0" }, { "menu.draw_xoffset.SETUP[EDITOR]", "0" }, { "menu.draw_yoffset.SETUP[EDITOR]", "0" }, { "menu.draw_xoffset.SETUP[GRAPHICS]", "0" }, { "menu.draw_yoffset.SETUP[GRAPHICS]", "0" }, { "menu.draw_xoffset.SETUP[SOUND]", "0" }, { "menu.draw_yoffset.SETUP[SOUND]", "0" }, { "menu.draw_xoffset.SETUP[ARTWORK]", "0" }, { "menu.draw_yoffset.SETUP[ARTWORK]", "0" }, { "menu.draw_xoffset.SETUP[INPUT]", "0" }, { "menu.draw_yoffset.SETUP[INPUT]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_1]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_1]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_2]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_2]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_3]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_3]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_4]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_4]", "0" }, { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]", "0" }, { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]", "0" }, { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]", "0" }, { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]", "0" }, { "menu.scrollbar_xoffset", "0" }, { "menu.list_size", "-1" }, { "menu.list_size.LEVELS", "-1" }, { "menu.list_size.SCORES", "-1" }, { "menu.list_size.INFO", "-1" }, { "menu.list_size.SETUP", "-1" }, { "main.button.name.x", "0" }, { "main.button.name.y", "64" }, { "main.button.levels.x", "0" }, { "main.button.levels.y", "96" }, { "main.button.scores.x", "0" }, { "main.button.scores.y", "128" }, { "main.button.editor.x", "0" }, { "main.button.editor.y", "160" }, { "main.button.info.x", "0" }, { "main.button.info.y", "192" }, { "main.button.game.x", "0" }, { "main.button.game.y", "224" }, { "main.button.setup.x", "0" }, { "main.button.setup.y", "256" }, { "main.button.quit.x", "0" }, { "main.button.quit.y", "288" }, { "main.button.prev_level.x", "320" }, { "main.button.prev_level.y", "96" }, { "main.button.next_level.x", "448" }, { "main.button.next_level.y", "96" }, { "main.text.name.x", "-1" }, { "main.text.name.y", "-1" }, { "main.text.name.width", "-1" }, { "main.text.name.height", "-1" }, { "main.text.name.align", "left" }, { "main.text.name.valign", "top" }, { "main.text.name.font", "font.menu_1" }, { "main.text.levels.x", "-1" }, { "main.text.levels.y", "-1" }, { "main.text.levels.width", "-1" }, { "main.text.levels.height", "-1" }, { "main.text.levels.align", "left" }, { "main.text.levels.valign", "top" }, { "main.text.levels.font", "font.menu_1" }, { "main.text.scores.x", "-1" }, { "main.text.scores.y", "-1" }, { "main.text.scores.width", "-1" }, { "main.text.scores.height", "-1" }, { "main.text.scores.align", "left" }, { "main.text.scores.valign", "top" }, { "main.text.scores.font", "font.menu_1" }, { "main.text.editor.x", "-1" }, { "main.text.editor.y", "-1" }, { "main.text.editor.width", "-1" }, { "main.text.editor.height", "-1" }, { "main.text.editor.align", "left" }, { "main.text.editor.valign", "top" }, { "main.text.editor.font", "font.menu_1" }, { "main.text.info.x", "-1" }, { "main.text.info.y", "-1" }, { "main.text.info.width", "-1" }, { "main.text.info.height", "-1" }, { "main.text.info.align", "left" }, { "main.text.info.valign", "top" }, { "main.text.info.font", "font.menu_1" }, { "main.text.game.x", "-1" }, { "main.text.game.y", "-1" }, { "main.text.game.width", "-1" }, { "main.text.game.height", "-1" }, { "main.text.game.align", "left" }, { "main.text.game.valign", "top" }, { "main.text.game.font", "font.menu_1" }, { "main.text.setup.x", "-1" }, { "main.text.setup.y", "-1" }, { "main.text.setup.width", "-1" }, { "main.text.setup.height", "-1" }, { "main.text.setup.align", "left" }, { "main.text.setup.valign", "top" }, { "main.text.setup.font", "font.menu_1" }, { "main.text.quit.x", "-1" }, { "main.text.quit.y", "-1" }, { "main.text.quit.width", "-1" }, { "main.text.quit.height", "-1" }, { "main.text.quit.align", "left" }, { "main.text.quit.valign", "top" }, { "main.text.quit.font", "font.menu_1" }, { "main.text.first_level.x", "488" }, { "main.text.first_level.y", "98" }, { "main.text.first_level.align", "left" }, { "main.text.first_level.valign", "top" }, { "main.text.first_level.digits", "3" }, { "main.text.first_level.font", "font.text_3" }, { "main.text.last_level.x", "488" }, { "main.text.last_level.y", "112" }, { "main.text.last_level.align", "left" }, { "main.text.last_level.valign", "top" }, { "main.text.last_level.digits", "3" }, { "main.text.last_level.font", "font.text_3" }, { "main.text.level_number.x", "352" }, { "main.text.level_number.y", "96" }, { "main.text.level_number.align", "left" }, { "main.text.level_number.valign", "top" }, { "main.text.level_number.digits", "3" }, { "main.text.level_number.font", "font.value_1" }, { "main.text.level_info_1.x", "272" }, { "main.text.level_info_1.y", "352" }, { "main.text.level_info_1.align", "center" }, { "main.text.level_info_1.valign", "top" }, { "main.text.level_info_1.chars", "-1" }, { "main.text.level_info_1.font", "font.text_1" }, { "main.text.level_info_2.x", "272" }, { "main.text.level_info_2.y", "523" }, { "main.text.level_info_2.align", "center" }, { "main.text.level_info_2.valign", "top" }, { "main.text.level_info_2.chars", "-1" }, { "main.text.level_info_2.font", "font.text_2" }, { "main.text.level_info_2.font_header", "font.text_4" }, { "main.text.level_name.x", "-1" }, { "main.text.level_name.y", "-1" }, { "main.text.level_name.align", "left" }, { "main.text.level_name.valign", "top" }, { "main.text.level_name.chars", "-1" }, { "main.text.level_name.font", "font.text_2" }, { "main.text.level_author.x", "-1" }, { "main.text.level_author.y", "-1" }, { "main.text.level_author.align", "left" }, { "main.text.level_author.valign", "top" }, { "main.text.level_author.chars", "-1" }, { "main.text.level_author.font", "font.text_2" }, { "main.text.level_year.x", "-1" }, { "main.text.level_year.y", "-1" }, { "main.text.level_year.align", "left" }, { "main.text.level_year.valign", "top" }, { "main.text.level_year.digits", "-1" }, { "main.text.level_year.font", "font.text_2" }, { "main.text.level_imported_from.x", "-1" }, { "main.text.level_imported_from.y", "-1" }, { "main.text.level_imported_from.align", "left" }, { "main.text.level_imported_from.valign", "top" }, { "main.text.level_imported_from.chars", "-1" }, { "main.text.level_imported_from.font", "font.text_2" }, { "main.text.level_imported_by.x", "-1" }, { "main.text.level_imported_by.y", "-1" }, { "main.text.level_imported_by.align", "left" }, { "main.text.level_imported_by.valign", "top" }, { "main.text.level_imported_by.chars", "-1" }, { "main.text.level_imported_by.font", "font.text_2" }, { "main.text.level_tested_by.x", "-1" }, { "main.text.level_tested_by.y", "-1" }, { "main.text.level_tested_by.align", "left" }, { "main.text.level_tested_by.valign", "top" }, { "main.text.level_tested_by.chars", "-1" }, { "main.text.level_tested_by.font", "font.text_2" }, { "main.text.title_1.x", "272" }, { "main.text.title_1.y", "8" }, { "main.text.title_1.align", "center" }, { "main.text.title_1.valign", "top" }, { "main.text.title_1.font", "font.title_1" }, { "main.text.title_2.x", "272" }, { "main.text.title_2.y", "46" }, { "main.text.title_2.align", "center" }, { "main.text.title_2.valign", "top" }, { "main.text.title_2.font", "font.title_2" }, { "main.text.title_3.x", "272" }, { "main.text.title_3.y", "326" }, { "main.text.title_3.align", "center" }, { "main.text.title_3.valign", "top" }, { "main.text.title_3.font", "font.title_2" }, { "main.input.name.x", "-1" }, { "main.input.name.y", "-1" }, { "main.input.name.align", "left" }, { "main.input.name.valign", "top" }, { "main.input.name.font", "font.input_1" }, { "preview.x", "272" }, { "preview.y", "380" }, { "preview.align", "center" }, { "preview.valign", "top" }, { "preview.xsize", "66" }, { "preview.ysize", "34" }, { "preview.xoffset", "0" }, { "preview.yoffset", "0" }, { "preview.tile_size", "4" }, { "preview.step_offset", "1" }, { "preview.step_delay", "50" }, { "preview.anim_mode", "default" }, { "door_1.width", "-1" }, { "door_1.height", "-1" }, { "door_1.step_offset", "2" }, { "door_1.step_delay", "10" }, { "door_1.anim_mode", "default" }, { "door_2.width", "-1" }, { "door_2.height", "-1" }, { "door_2.step_offset", "2" }, { "door_2.step_delay", "10" }, { "door_2.anim_mode", "default" }, { "game.panel.level_number.x", "51" }, { "game.panel.level_number.y", "20" }, { "game.panel.level_number.align", "center" }, { "game.panel.level_number.valign", "top" }, { "game.panel.level_number.digits", "-1" }, { "game.panel.level_number.font", "font.text_2" }, { "game.panel.level_number.font_narrow", "font.text_1" }, { "game.panel.level_number.draw_masked", "true" }, { "game.panel.level_number.draw_order", "0" }, { "game.panel.gems.x", "50" }, { "game.panel.gems.y", "54" }, { "game.panel.gems.align", "center" }, { "game.panel.gems.valign", "top" }, { "game.panel.gems.digits", "3" }, { "game.panel.gems.font", "font.text_2" }, { "game.panel.gems.draw_masked", "true" }, { "game.panel.gems.draw_order", "0" }, { "game.panel.inventory_count.x", "50" }, { "game.panel.inventory_count.y", "89" }, { "game.panel.inventory_count.align", "center" }, { "game.panel.inventory_count.valign", "top" }, { "game.panel.inventory_count.digits", "3" }, { "game.panel.inventory_count.font", "font.text_2" }, { "game.panel.inventory_count.draw_masked", "true" }, { "game.panel.inventory_count.draw_order", "0" }, { "game.panel.inventory_first_1.x", "-1" }, { "game.panel.inventory_first_1.y", "-1" }, { "game.panel.inventory_first_1.tile_size", "16" }, { "game.panel.inventory_first_1.draw_masked", "false" }, { "game.panel.inventory_first_1.draw_order", "0" }, { "game.panel.inventory_first_2.x", "-1" }, { "game.panel.inventory_first_2.y", "-1" }, { "game.panel.inventory_first_2.tile_size", "16" }, { "game.panel.inventory_first_2.draw_masked", "false" }, { "game.panel.inventory_first_2.draw_order", "0" }, { "game.panel.inventory_first_3.x", "-1" }, { "game.panel.inventory_first_3.y", "-1" }, { "game.panel.inventory_first_3.tile_size", "16" }, { "game.panel.inventory_first_3.draw_masked", "false" }, { "game.panel.inventory_first_3.draw_order", "0" }, { "game.panel.inventory_first_4.x", "-1" }, { "game.panel.inventory_first_4.y", "-1" }, { "game.panel.inventory_first_4.tile_size", "16" }, { "game.panel.inventory_first_4.draw_masked", "false" }, { "game.panel.inventory_first_4.draw_order", "0" }, { "game.panel.inventory_first_5.x", "-1" }, { "game.panel.inventory_first_5.y", "-1" }, { "game.panel.inventory_first_5.tile_size", "16" }, { "game.panel.inventory_first_5.draw_masked", "false" }, { "game.panel.inventory_first_5.draw_order", "0" }, { "game.panel.inventory_first_6.x", "-1" }, { "game.panel.inventory_first_6.y", "-1" }, { "game.panel.inventory_first_6.tile_size", "16" }, { "game.panel.inventory_first_6.draw_masked", "false" }, { "game.panel.inventory_first_6.draw_order", "0" }, { "game.panel.inventory_first_7.x", "-1" }, { "game.panel.inventory_first_7.y", "-1" }, { "game.panel.inventory_first_7.tile_size", "16" }, { "game.panel.inventory_first_7.draw_masked", "false" }, { "game.panel.inventory_first_7.draw_order", "0" }, { "game.panel.inventory_first_8.x", "-1" }, { "game.panel.inventory_first_8.y", "-1" }, { "game.panel.inventory_first_8.tile_size", "16" }, { "game.panel.inventory_first_8.draw_masked", "false" }, { "game.panel.inventory_first_8.draw_order", "0" }, { "game.panel.inventory_last_1.x", "-1" }, { "game.panel.inventory_last_1.y", "-1" }, { "game.panel.inventory_last_1.tile_size", "16" }, { "game.panel.inventory_last_1.draw_masked", "false" }, { "game.panel.inventory_last_1.draw_order", "0" }, { "game.panel.inventory_last_2.x", "-1" }, { "game.panel.inventory_last_2.y", "-1" }, { "game.panel.inventory_last_2.tile_size", "16" }, { "game.panel.inventory_last_2.draw_masked", "false" }, { "game.panel.inventory_last_2.draw_order", "0" }, { "game.panel.inventory_last_3.x", "-1" }, { "game.panel.inventory_last_3.y", "-1" }, { "game.panel.inventory_last_3.tile_size", "16" }, { "game.panel.inventory_last_3.draw_masked", "false" }, { "game.panel.inventory_last_3.draw_order", "0" }, { "game.panel.inventory_last_4.x", "-1" }, { "game.panel.inventory_last_4.y", "-1" }, { "game.panel.inventory_last_4.tile_size", "16" }, { "game.panel.inventory_last_4.draw_masked", "false" }, { "game.panel.inventory_last_4.draw_order", "0" }, { "game.panel.inventory_last_5.x", "-1" }, { "game.panel.inventory_last_5.y", "-1" }, { "game.panel.inventory_last_5.tile_size", "16" }, { "game.panel.inventory_last_5.draw_masked", "false" }, { "game.panel.inventory_last_5.draw_order", "0" }, { "game.panel.inventory_last_6.x", "-1" }, { "game.panel.inventory_last_6.y", "-1" }, { "game.panel.inventory_last_6.tile_size", "16" }, { "game.panel.inventory_last_6.draw_masked", "false" }, { "game.panel.inventory_last_6.draw_order", "0" }, { "game.panel.inventory_last_7.x", "-1" }, { "game.panel.inventory_last_7.y", "-1" }, { "game.panel.inventory_last_7.tile_size", "16" }, { "game.panel.inventory_last_7.draw_masked", "false" }, { "game.panel.inventory_last_7.draw_order", "0" }, { "game.panel.inventory_last_8.x", "-1" }, { "game.panel.inventory_last_8.y", "-1" }, { "game.panel.inventory_last_8.tile_size", "16" }, { "game.panel.inventory_last_8.draw_masked", "false" }, { "game.panel.inventory_last_8.draw_order", "0" }, { "game.panel.key_1.x", "18" }, { "game.panel.key_1.y", "123" }, { "game.panel.key_1.tile_size", "16" }, { "game.panel.key_1.draw_masked", "false" }, { "game.panel.key_1.draw_order", "0" }, { "game.panel.key_2.x", "34" }, { "game.panel.key_2.y", "123" }, { "game.panel.key_2.tile_size", "16" }, { "game.panel.key_2.draw_masked", "false" }, { "game.panel.key_2.draw_order", "0" }, { "game.panel.key_3.x", "50" }, { "game.panel.key_3.y", "123" }, { "game.panel.key_3.tile_size", "16" }, { "game.panel.key_3.draw_masked", "false" }, { "game.panel.key_3.draw_order", "0" }, { "game.panel.key_4.x", "66" }, { "game.panel.key_4.y", "123" }, { "game.panel.key_4.tile_size", "16" }, { "game.panel.key_4.draw_masked", "false" }, { "game.panel.key_4.draw_order", "0" }, { "game.panel.key_5.x", "-1" }, { "game.panel.key_5.y", "-1" }, { "game.panel.key_5.tile_size", "16" }, { "game.panel.key_5.draw_masked", "false" }, { "game.panel.key_5.draw_order", "0" }, { "game.panel.key_6.x", "-1" }, { "game.panel.key_6.y", "-1" }, { "game.panel.key_6.tile_size", "16" }, { "game.panel.key_6.draw_masked", "false" }, { "game.panel.key_6.draw_order", "0" }, { "game.panel.key_7.x", "-1" }, { "game.panel.key_7.y", "-1" }, { "game.panel.key_7.tile_size", "16" }, { "game.panel.key_7.draw_masked", "false" }, { "game.panel.key_7.draw_order", "0" }, { "game.panel.key_8.x", "-1" }, { "game.panel.key_8.y", "-1" }, { "game.panel.key_8.tile_size", "16" }, { "game.panel.key_8.draw_masked", "false" }, { "game.panel.key_8.draw_order", "0" }, { "game.panel.key_white.x", "-1" }, { "game.panel.key_white.y", "-1" }, { "game.panel.key_white.tile_size", "16" }, { "game.panel.key_white.draw_masked", "false" }, { "game.panel.key_white.draw_order", "0" }, { "game.panel.key_white_count.x", "-1" }, { "game.panel.key_white_count.y", "-1" }, { "game.panel.key_white_count.align", "left" }, { "game.panel.key_white_count.valign", "top" }, { "game.panel.key_white_count.digits", "-1" }, { "game.panel.key_white_count.font", "font.text_2" }, { "game.panel.key_white_count.draw_masked", "true" }, { "game.panel.key_white_count.draw_order", "0" }, { "game.panel.score.x", "50" }, { "game.panel.score.y", "159" }, { "game.panel.score.align", "center" }, { "game.panel.score.valign", "top" }, { "game.panel.score.digits", "5" }, { "game.panel.score.font", "font.text_2" }, { "game.panel.score.draw_masked", "true" }, { "game.panel.score.draw_order", "0" }, { "game.panel.highscore.x", "-1" }, { "game.panel.highscore.y", "-1" }, { "game.panel.highscore.align", "left" }, { "game.panel.highscore.valign", "top" }, { "game.panel.highscore.digits", "5" }, { "game.panel.highscore.font", "font.text_2" }, { "game.panel.highscore.draw_masked", "true" }, { "game.panel.highscore.draw_order", "0" }, { "game.panel.time.x", "50" }, { "game.panel.time.y", "194" }, { "game.panel.time.align", "center" }, { "game.panel.time.valign", "top" }, { "game.panel.time.digits", "-1" }, { "game.panel.time.font", "font.text_2" }, { "game.panel.time.font_narrow", "font.text_1" }, { "game.panel.time.draw_masked", "true" }, { "game.panel.time.draw_order", "0" }, { "game.panel.time_hh.x", "-1" }, { "game.panel.time_hh.y", "-1" }, { "game.panel.time_hh.align", "left" }, { "game.panel.time_hh.valign", "top" }, { "game.panel.time_hh.digits", "2" }, { "game.panel.time_hh.font", "font.text_2" }, { "game.panel.time_hh.draw_masked", "true" }, { "game.panel.time_hh.draw_order", "0" }, { "game.panel.time_mm.x", "-1" }, { "game.panel.time_mm.y", "-1" }, { "game.panel.time_mm.align", "left" }, { "game.panel.time_mm.valign", "top" }, { "game.panel.time_mm.digits", "2" }, { "game.panel.time_mm.font", "font.text_2" }, { "game.panel.time_mm.draw_masked", "true" }, { "game.panel.time_mm.draw_order", "0" }, { "game.panel.time_ss.x", "-1" }, { "game.panel.time_ss.y", "-1" }, { "game.panel.time_ss.align", "left" }, { "game.panel.time_ss.valign", "top" }, { "game.panel.time_ss.digits", "2" }, { "game.panel.time_ss.font", "font.text_2" }, { "game.panel.time_ss.draw_masked", "true" }, { "game.panel.time_ss.draw_order", "0" }, { "game.panel.frame.x", "-1" }, { "game.panel.frame.y", "-1" }, { "game.panel.frame.align", "left" }, { "game.panel.frame.valign", "top" }, { "game.panel.frame.digits", "-1" }, { "game.panel.frame.font", "font.text_2" }, { "game.panel.frame.draw_masked", "true" }, { "game.panel.frame.draw_order", "0" }, { "game.panel.shield_normal.x", "-1" }, { "game.panel.shield_normal.y", "-1" }, { "game.panel.shield_normal.tile_size", "16" }, { "game.panel.shield_normal.draw_masked", "false" }, { "game.panel.shield_normal.draw_order", "0" }, { "game.panel.shield_normal_time.x", "-1" }, { "game.panel.shield_normal_time.y", "-1" }, { "game.panel.shield_normal_time.align", "left" }, { "game.panel.shield_normal_time.valign", "top" }, { "game.panel.shield_normal_time.digits", "-1" }, { "game.panel.shield_normal_time.font", "font.text_2" }, { "game.panel.shield_normal_time.draw_masked", "true" }, { "game.panel.shield_normal_time.draw_order", "0" }, { "game.panel.shield_deadly.x", "-1" }, { "game.panel.shield_deadly.y", "-1" }, { "game.panel.shield_deadly.tile_size", "16" }, { "game.panel.shield_deadly.draw_masked", "false" }, { "game.panel.shield_deadly.draw_order", "0" }, { "game.panel.shield_deadly_time.x", "-1" }, { "game.panel.shield_deadly_time.y", "-1" }, { "game.panel.shield_deadly_time.align", "left" }, { "game.panel.shield_deadly_time.valign", "top" }, { "game.panel.shield_deadly_time.digits", "-1" }, { "game.panel.shield_deadly_time.font", "font.text_2" }, { "game.panel.shield_deadly_time.draw_masked","true" }, { "game.panel.shield_deadly_time.draw_order", "0" }, { "game.panel.exit.x", "-1" }, { "game.panel.exit.y", "-1" }, { "game.panel.exit.tile_size", "16" }, { "game.panel.exit.draw_masked", "false" }, { "game.panel.exit.draw_order", "0" }, { "game.panel.emc_magic_ball.x", "-1" }, { "game.panel.emc_magic_ball.y", "-1" }, { "game.panel.emc_magic_ball.tile_size", "16" }, { "game.panel.emc_magic_ball.draw_masked", "false" }, { "game.panel.emc_magic_ball.draw_order", "0" }, { "game.panel.emc_magic_ball_switch.x", "-1" }, { "game.panel.emc_magic_ball_switch.y", "-1" }, { "game.panel.emc_magic_ball_switch.tile_size", "16" }, { "game.panel.emc_magic_ball_switch.draw_masked", "true" }, { "game.panel.emc_magic_ball_switch.draw_order", "0" }, { "game.panel.light_switch.x", "-1" }, { "game.panel.light_switch.y", "-1" }, { "game.panel.light_switch.tile_size", "16" }, { "game.panel.light_switch.draw_masked", "false" }, { "game.panel.light_switch.draw_order", "0" }, { "game.panel.light_switch_time.x", "-1" }, { "game.panel.light_switch_time.y", "-1" }, { "game.panel.light_switch_time.align", "left" }, { "game.panel.light_switch_time.valign", "top" }, { "game.panel.light_switch_time.digits", "-1" }, { "game.panel.light_switch_time.font", "font.text_2" }, { "game.panel.light_switch_time.draw_masked", "true" }, { "game.panel.light_switch_time.draw_order", "0" }, { "game.panel.timegate_switch.x", "-1" }, { "game.panel.timegate_switch.y", "-1" }, { "game.panel.timegate_switch.tile_size", "16" }, { "game.panel.timegate_switch.draw_masked", "false" }, { "game.panel.timegate_switch.draw_order", "0" }, { "game.panel.timegate_switch_time.x", "-1" }, { "game.panel.timegate_switch_time.y", "-1" }, { "game.panel.timegate_switch_time.align", "left" }, { "game.panel.timegate_switch_time.valign", "top" }, { "game.panel.timegate_switch_time.digits", "-1" }, { "game.panel.timegate_switch_time.font", "font.text_2" }, { "game.panel.timegate_switch_time.draw_masked", "true" }, { "game.panel.timegate_switch_time.draw_order", "0" }, { "game.panel.switchgate_switch.x", "-1" }, { "game.panel.switchgate_switch.y", "-1" }, { "game.panel.switchgate_switch.tile_size", "16" }, { "game.panel.switchgate_switch.draw_masked", "false" }, { "game.panel.switchgate_switch.draw_order", "0" }, { "game.panel.emc_lenses.x", "-1" }, { "game.panel.emc_lenses.y", "-1" }, { "game.panel.emc_lenses.tile_size", "16" }, { "game.panel.emc_lenses.draw_masked", "false" }, { "game.panel.emc_lenses.draw_order", "0" }, { "game.panel.emc_lenses_time.x", "-1" }, { "game.panel.emc_lenses_time.y", "-1" }, { "game.panel.emc_lenses_time.align", "left" }, { "game.panel.emc_lenses_time.valign", "top" }, { "game.panel.emc_lenses_time.digits", "-1" }, { "game.panel.emc_lenses_time.font", "font.text_2" }, { "game.panel.emc_lenses_time.draw_masked", "true" }, { "game.panel.emc_lenses_time.draw_order", "0" }, { "game.panel.emc_magnifier.x", "-1" }, { "game.panel.emc_magnifier.y", "-1" }, { "game.panel.emc_magnifier.tile_size", "16" }, { "game.panel.emc_magnifier.draw_masked", "false" }, { "game.panel.emc_magnifier.draw_order", "0" }, { "game.panel.emc_magnifier_time.x", "-1" }, { "game.panel.emc_magnifier_time.y", "-1" }, { "game.panel.emc_magnifier_time.align", "left" }, { "game.panel.emc_magnifier_time.valign", "top" }, { "game.panel.emc_magnifier_time.digits", "-1" }, { "game.panel.emc_magnifier_time.font", "font.text_2" }, { "game.panel.emc_magnifier_time.draw_masked","true" }, { "game.panel.emc_magnifier_time.draw_order", "0" }, { "game.panel.balloon_switch.x", "-1" }, { "game.panel.balloon_switch.y", "-1" }, { "game.panel.balloon_switch.tile_size", "16" }, { "game.panel.balloon_switch.draw_masked", "false" }, { "game.panel.balloon_switch.draw_order", "0" }, { "game.panel.dynabomb_number.x", "-1" }, { "game.panel.dynabomb_number.y", "-1" }, { "game.panel.dynabomb_number.align", "left" }, { "game.panel.dynabomb_number.valign", "top" }, { "game.panel.dynabomb_number.digits", "-1" }, { "game.panel.dynabomb_number.font", "font.text_2" }, { "game.panel.dynabomb_number.draw_masked", "true" }, { "game.panel.dynabomb_number.draw_order", "0" }, { "game.panel.dynabomb_size.x", "-1" }, { "game.panel.dynabomb_size.y", "-1" }, { "game.panel.dynabomb_size.align", "left" }, { "game.panel.dynabomb_size.valign", "top" }, { "game.panel.dynabomb_size.digits", "-1" }, { "game.panel.dynabomb_size.font", "font.text_2" }, { "game.panel.dynabomb_size.draw_masked", "true" }, { "game.panel.dynabomb_size.draw_order", "0" }, { "game.panel.dynabomb_power.x", "-1" }, { "game.panel.dynabomb_power.y", "-1" }, { "game.panel.dynabomb_power.tile_size", "16" }, { "game.panel.dynabomb_power.draw_masked", "false" }, { "game.panel.dynabomb_power.draw_order", "0" }, { "game.panel.penguins.x", "-1" }, { "game.panel.penguins.y", "-1" }, { "game.panel.penguins.align", "left" }, { "game.panel.penguins.valign", "top" }, { "game.panel.penguins.digits", "-1" }, { "game.panel.penguins.font", "font.text_2" }, { "game.panel.penguins.draw_masked", "true" }, { "game.panel.penguins.draw_order", "0" }, { "game.panel.sokoban_objects.x", "-1" }, { "game.panel.sokoban_objects.y", "-1" }, { "game.panel.sokoban_objects.align", "left" }, { "game.panel.sokoban_objects.valign", "top" }, { "game.panel.sokoban_objects.digits", "-1" }, { "game.panel.sokoban_objects.font", "font.text_2" }, { "game.panel.sokoban_objects.draw_masked", "true" }, { "game.panel.sokoban_objects.draw_order", "0" }, { "game.panel.sokoban_fields.x", "-1" }, { "game.panel.sokoban_fields.y", "-1" }, { "game.panel.sokoban_fields.align", "left" }, { "game.panel.sokoban_fields.valign", "top" }, { "game.panel.sokoban_fields.digits", "-1" }, { "game.panel.sokoban_fields.font", "font.text_2" }, { "game.panel.sokoban_fields.draw_masked", "true" }, { "game.panel.sokoban_fields.draw_order", "0" }, { "game.panel.robot_wheel.x", "-1" }, { "game.panel.robot_wheel.y", "-1" }, { "game.panel.robot_wheel.tile_size", "16" }, { "game.panel.robot_wheel.draw_masked", "false" }, { "game.panel.robot_wheel.draw_order", "0" }, { "game.panel.conveyor_belt_1.x", "-1" }, { "game.panel.conveyor_belt_1.y", "-1" }, { "game.panel.conveyor_belt_1.tile_size", "16" }, { "game.panel.conveyor_belt_1.draw_masked", "false" }, { "game.panel.conveyor_belt_1.draw_order", "0" }, { "game.panel.conveyor_belt_1_switch.x", "-1" }, { "game.panel.conveyor_belt_1_switch.y", "-1" }, { "game.panel.conveyor_belt_1_switch.tile_size", "16" }, { "game.panel.conveyor_belt_1_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_1_switch.draw_order", "0" }, { "game.panel.conveyor_belt_2.x", "-1" }, { "game.panel.conveyor_belt_2.y", "-1" }, { "game.panel.conveyor_belt_2.tile_size", "16" }, { "game.panel.conveyor_belt_2.draw_masked", "false" }, { "game.panel.conveyor_belt_2.draw_order", "0" }, { "game.panel.conveyor_belt_2_switch.x", "-1" }, { "game.panel.conveyor_belt_2_switch.y", "-1" }, { "game.panel.conveyor_belt_2_switch.tile_size", "16" }, { "game.panel.conveyor_belt_2_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_2_switch.draw_order", "0" }, { "game.panel.conveyor_belt_3.x", "-1" }, { "game.panel.conveyor_belt_3.y", "-1" }, { "game.panel.conveyor_belt_3.tile_size", "16" }, { "game.panel.conveyor_belt_3.draw_masked", "false" }, { "game.panel.conveyor_belt_3.draw_order", "0" }, { "game.panel.conveyor_belt_3_switch.x", "-1" }, { "game.panel.conveyor_belt_3_switch.y", "-1" }, { "game.panel.conveyor_belt_3_switch.tile_size", "16" }, { "game.panel.conveyor_belt_3_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_3_switch.draw_order", "0" }, { "game.panel.conveyor_belt_4.x", "-1" }, { "game.panel.conveyor_belt_4.y", "-1" }, { "game.panel.conveyor_belt_4.tile_size", "16" }, { "game.panel.conveyor_belt_4.draw_masked", "false" }, { "game.panel.conveyor_belt_4.draw_order", "0" }, { "game.panel.conveyor_belt_4_switch.x", "-1" }, { "game.panel.conveyor_belt_4_switch.y", "-1" }, { "game.panel.conveyor_belt_4_switch.tile_size", "16" }, { "game.panel.conveyor_belt_4_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_4_switch.draw_order", "0" }, { "game.panel.magic_wall.x", "-1" }, { "game.panel.magic_wall.y", "-1" }, { "game.panel.magic_wall.tile_size", "16" }, { "game.panel.magic_wall.draw_masked", "false" }, { "game.panel.magic_wall.draw_order", "0" }, { "game.panel.magic_wall_time.x", "-1" }, { "game.panel.magic_wall_time.y", "-1" }, { "game.panel.magic_wall_time.align", "left" }, { "game.panel.magic_wall_time.valign", "top" }, { "game.panel.magic_wall_time.digits", "-1" }, { "game.panel.magic_wall_time.font", "font.text_2" }, { "game.panel.magic_wall_time.draw_masked", "true" }, { "game.panel.magic_wall_time.draw_order", "0" }, { "game.panel.gravity_state.x", "-1" }, { "game.panel.gravity_state.y", "-1" }, { "game.panel.gravity_state.align", "left" }, { "game.panel.gravity_state.valign", "top" }, { "game.panel.gravity_state.chars", "-1" }, { "game.panel.gravity_state.font", "font.text_1" }, { "game.panel.gravity_state.font_active", "font.text_2" }, { "game.panel.gravity_state.draw_masked", "true" }, { "game.panel.gravity_state.draw_order", "0" }, { "game.panel.graphic_1.x", "-1" }, { "game.panel.graphic_1.y", "-1" }, { "game.panel.graphic_1.draw_masked", "true" }, { "game.panel.graphic_1.draw_order", "0" }, { "game.panel.graphic_2.x", "-1" }, { "game.panel.graphic_2.y", "-1" }, { "game.panel.graphic_2.draw_masked", "true" }, { "game.panel.graphic_2.draw_order", "0" }, { "game.panel.graphic_3.x", "-1" }, { "game.panel.graphic_3.y", "-1" }, { "game.panel.graphic_3.draw_masked", "true" }, { "game.panel.graphic_3.draw_order", "0" }, { "game.panel.graphic_4.x", "-1" }, { "game.panel.graphic_4.y", "-1" }, { "game.panel.graphic_4.draw_masked", "true" }, { "game.panel.graphic_4.draw_order", "0" }, { "game.panel.graphic_5.x", "-1" }, { "game.panel.graphic_5.y", "-1" }, { "game.panel.graphic_5.draw_masked", "true" }, { "game.panel.graphic_5.draw_order", "0" }, { "game.panel.graphic_6.x", "-1" }, { "game.panel.graphic_6.y", "-1" }, { "game.panel.graphic_6.draw_masked", "true" }, { "game.panel.graphic_6.draw_order", "0" }, { "game.panel.graphic_7.x", "-1" }, { "game.panel.graphic_7.y", "-1" }, { "game.panel.graphic_7.draw_masked", "true" }, { "game.panel.graphic_7.draw_order", "0" }, { "game.panel.graphic_8.x", "-1" }, { "game.panel.graphic_8.y", "-1" }, { "game.panel.graphic_8.draw_masked", "true" }, { "game.panel.graphic_8.draw_order", "0" }, { "game.panel.element_1.x", "-1" }, { "game.panel.element_1.y", "-1" }, { "game.panel.element_1.tile_size", "16" }, { "game.panel.element_1.element", "empty_space" }, { "game.panel.element_1.draw_masked", "false" }, { "game.panel.element_1.draw_order", "0" }, { "game.panel.element_1_count.x", "-1" }, { "game.panel.element_1_count.y", "-1" }, { "game.panel.element_1_count.align", "left" }, { "game.panel.element_1_count.valign", "top" }, { "game.panel.element_1_count.digits", "-1" }, { "game.panel.element_1_count.font", "font.text_2" }, { "game.panel.element_1_count.element", "empty_space" }, { "game.panel.element_1_count.draw_masked", "true" }, { "game.panel.element_1_count.draw_order", "0" }, { "game.panel.element_2.x", "-1" }, { "game.panel.element_2.y", "-1" }, { "game.panel.element_2.tile_size", "16" }, { "game.panel.element_2.element", "empty_space" }, { "game.panel.element_2.draw_masked", "false" }, { "game.panel.element_2.draw_order", "0" }, { "game.panel.element_2_count.x", "-1" }, { "game.panel.element_2_count.y", "-1" }, { "game.panel.element_2_count.align", "left" }, { "game.panel.element_2_count.valign", "top" }, { "game.panel.element_2_count.digits", "-1" }, { "game.panel.element_2_count.font", "font.text_2" }, { "game.panel.element_2_count.element", "empty_space" }, { "game.panel.element_2_count.draw_masked", "true" }, { "game.panel.element_2_count.draw_order", "0" }, { "game.panel.element_3.x", "-1" }, { "game.panel.element_3.y", "-1" }, { "game.panel.element_3.tile_size", "16" }, { "game.panel.element_3.element", "empty_space" }, { "game.panel.element_3.draw_masked", "false" }, { "game.panel.element_3.draw_order", "0" }, { "game.panel.element_3_count.x", "-1" }, { "game.panel.element_3_count.y", "-1" }, { "game.panel.element_3_count.align", "left" }, { "game.panel.element_3_count.valign", "top" }, { "game.panel.element_3_count.digits", "-1" }, { "game.panel.element_3_count.font", "font.text_2" }, { "game.panel.element_3_count.element", "empty_space" }, { "game.panel.element_3_count.draw_masked", "true" }, { "game.panel.element_3_count.draw_order", "0" }, { "game.panel.element_4.x", "-1" }, { "game.panel.element_4.y", "-1" }, { "game.panel.element_4.tile_size", "16" }, { "game.panel.element_4.element", "empty_space" }, { "game.panel.element_4.draw_masked", "false" }, { "game.panel.element_4.draw_order", "0" }, { "game.panel.element_4_count.x", "-1" }, { "game.panel.element_4_count.y", "-1" }, { "game.panel.element_4_count.align", "left" }, { "game.panel.element_4_count.valign", "top" }, { "game.panel.element_4_count.digits", "-1" }, { "game.panel.element_4_count.font", "font.text_2" }, { "game.panel.element_4_count.element", "empty_space" }, { "game.panel.element_4_count.draw_masked", "true" }, { "game.panel.element_4_count.draw_order", "0" }, { "game.panel.element_5.x", "-1" }, { "game.panel.element_5.y", "-1" }, { "game.panel.element_5.tile_size", "16" }, { "game.panel.element_5.element", "empty_space" }, { "game.panel.element_5.draw_masked", "false" }, { "game.panel.element_5.draw_order", "0" }, { "game.panel.element_5_count.x", "-1" }, { "game.panel.element_5_count.y", "-1" }, { "game.panel.element_5_count.align", "left" }, { "game.panel.element_5_count.valign", "top" }, { "game.panel.element_5_count.digits", "-1" }, { "game.panel.element_5_count.font", "font.text_2" }, { "game.panel.element_5_count.element", "empty_space" }, { "game.panel.element_5_count.draw_masked", "true" }, { "game.panel.element_5_count.draw_order", "0" }, { "game.panel.element_6.x", "-1" }, { "game.panel.element_6.y", "-1" }, { "game.panel.element_6.tile_size", "16" }, { "game.panel.element_6.element", "empty_space" }, { "game.panel.element_6.draw_masked", "false" }, { "game.panel.element_6.draw_order", "0" }, { "game.panel.element_6_count.x", "-1" }, { "game.panel.element_6_count.y", "-1" }, { "game.panel.element_6_count.align", "left" }, { "game.panel.element_6_count.valign", "top" }, { "game.panel.element_6_count.digits", "-1" }, { "game.panel.element_6_count.font", "font.text_2" }, { "game.panel.element_6_count.element", "empty_space" }, { "game.panel.element_6_count.draw_masked", "true" }, { "game.panel.element_6_count.draw_order", "0" }, { "game.panel.element_7.x", "-1" }, { "game.panel.element_7.y", "-1" }, { "game.panel.element_7.tile_size", "16" }, { "game.panel.element_7.element", "empty_space" }, { "game.panel.element_7.draw_masked", "false" }, { "game.panel.element_7.draw_order", "0" }, { "game.panel.element_7_count.x", "-1" }, { "game.panel.element_7_count.y", "-1" }, { "game.panel.element_7_count.align", "left" }, { "game.panel.element_7_count.valign", "top" }, { "game.panel.element_7_count.digits", "-1" }, { "game.panel.element_7_count.font", "font.text_2" }, { "game.panel.element_7_count.element", "empty_space" }, { "game.panel.element_7_count.draw_masked", "true" }, { "game.panel.element_7_count.draw_order", "0" }, { "game.panel.element_8.x", "-1" }, { "game.panel.element_8.y", "-1" }, { "game.panel.element_8.tile_size", "16" }, { "game.panel.element_8.element", "empty_space" }, { "game.panel.element_8.draw_masked", "false" }, { "game.panel.element_8.draw_order", "0" }, { "game.panel.element_8_count.x", "-1" }, { "game.panel.element_8_count.y", "-1" }, { "game.panel.element_8_count.align", "left" }, { "game.panel.element_8_count.valign", "top" }, { "game.panel.element_8_count.digits", "-1" }, { "game.panel.element_8_count.font", "font.text_2" }, { "game.panel.element_8_count.element", "empty_space" }, { "game.panel.element_8_count.draw_masked", "true" }, { "game.panel.element_8_count.draw_order", "0" }, { "game.panel.ce_score_1.x", "-1" }, { "game.panel.ce_score_1.y", "-1" }, { "game.panel.ce_score_1.align", "left" }, { "game.panel.ce_score_1.valign", "top" }, { "game.panel.ce_score_1.digits", "-1" }, { "game.panel.ce_score_1.font", "font.text_2" }, { "game.panel.ce_score_1.element", "empty_space" }, { "game.panel.ce_score_1.draw_masked", "true" }, { "game.panel.ce_score_1.draw_order", "0" }, { "game.panel.ce_score_1_element.x", "-1" }, { "game.panel.ce_score_1_element.y", "-1" }, { "game.panel.ce_score_1_element.tile_size", "16" }, { "game.panel.ce_score_1_element.element", "empty_space" }, { "game.panel.ce_score_1_element.draw_masked","false" }, { "game.panel.ce_score_1_element.draw_order", "0" }, { "game.panel.ce_score_2.x", "-1" }, { "game.panel.ce_score_2.y", "-1" }, { "game.panel.ce_score_2.align", "left" }, { "game.panel.ce_score_2.valign", "top" }, { "game.panel.ce_score_2.digits", "-1" }, { "game.panel.ce_score_2.font", "font.text_2" }, { "game.panel.ce_score_2.element", "empty_space" }, { "game.panel.ce_score_2.draw_masked", "true" }, { "game.panel.ce_score_2.draw_order", "0" }, { "game.panel.ce_score_2_element.x", "-1" }, { "game.panel.ce_score_2_element.y", "-1" }, { "game.panel.ce_score_2_element.tile_size", "16" }, { "game.panel.ce_score_2_element.element", "empty_space" }, { "game.panel.ce_score_2_element.draw_masked","false" }, { "game.panel.ce_score_2_element.draw_order", "0" }, { "game.panel.ce_score_3.x", "-1" }, { "game.panel.ce_score_3.y", "-1" }, { "game.panel.ce_score_3.align", "left" }, { "game.panel.ce_score_3.valign", "top" }, { "game.panel.ce_score_3.digits", "-1" }, { "game.panel.ce_score_3.font", "font.text_2" }, { "game.panel.ce_score_3.element", "empty_space" }, { "game.panel.ce_score_3.draw_masked", "true" }, { "game.panel.ce_score_3.draw_order", "0" }, { "game.panel.ce_score_3_element.x", "-1" }, { "game.panel.ce_score_3_element.y", "-1" }, { "game.panel.ce_score_3_element.tile_size", "16" }, { "game.panel.ce_score_3_element.element", "empty_space" }, { "game.panel.ce_score_3_element.draw_masked","false" }, { "game.panel.ce_score_3_element.draw_order", "0" }, { "game.panel.ce_score_4.x", "-1" }, { "game.panel.ce_score_4.y", "-1" }, { "game.panel.ce_score_4.align", "left" }, { "game.panel.ce_score_4.valign", "top" }, { "game.panel.ce_score_4.digits", "-1" }, { "game.panel.ce_score_4.font", "font.text_2" }, { "game.panel.ce_score_4.element", "empty_space" }, { "game.panel.ce_score_4.draw_masked", "true" }, { "game.panel.ce_score_4.draw_order", "0" }, { "game.panel.ce_score_4_element.x", "-1" }, { "game.panel.ce_score_4_element.y", "-1" }, { "game.panel.ce_score_4_element.tile_size", "16" }, { "game.panel.ce_score_4_element.element", "empty_space" }, { "game.panel.ce_score_4_element.draw_masked","false" }, { "game.panel.ce_score_4_element.draw_order", "0" }, { "game.panel.ce_score_5.x", "-1" }, { "game.panel.ce_score_5.y", "-1" }, { "game.panel.ce_score_5.align", "left" }, { "game.panel.ce_score_5.valign", "top" }, { "game.panel.ce_score_5.digits", "-1" }, { "game.panel.ce_score_5.font", "font.text_2" }, { "game.panel.ce_score_5.element", "empty_space" }, { "game.panel.ce_score_5.draw_masked", "true" }, { "game.panel.ce_score_5.draw_order", "0" }, { "game.panel.ce_score_5_element.x", "-1" }, { "game.panel.ce_score_5_element.y", "-1" }, { "game.panel.ce_score_5_element.tile_size", "16" }, { "game.panel.ce_score_5_element.element", "empty_space" }, { "game.panel.ce_score_5_element.draw_masked","false" }, { "game.panel.ce_score_5_element.draw_order", "0" }, { "game.panel.ce_score_6.x", "-1" }, { "game.panel.ce_score_6.y", "-1" }, { "game.panel.ce_score_6.align", "left" }, { "game.panel.ce_score_6.valign", "top" }, { "game.panel.ce_score_6.digits", "-1" }, { "game.panel.ce_score_6.font", "font.text_2" }, { "game.panel.ce_score_6.element", "empty_space" }, { "game.panel.ce_score_6.draw_masked", "true" }, { "game.panel.ce_score_6.draw_order", "0" }, { "game.panel.ce_score_6_element.x", "-1" }, { "game.panel.ce_score_6_element.y", "-1" }, { "game.panel.ce_score_6_element.tile_size", "16" }, { "game.panel.ce_score_6_element.element", "empty_space" }, { "game.panel.ce_score_6_element.draw_masked","false" }, { "game.panel.ce_score_6_element.draw_order", "0" }, { "game.panel.ce_score_7.x", "-1" }, { "game.panel.ce_score_7.y", "-1" }, { "game.panel.ce_score_7.align", "left" }, { "game.panel.ce_score_7.valign", "top" }, { "game.panel.ce_score_7.digits", "-1" }, { "game.panel.ce_score_7.font", "font.text_2" }, { "game.panel.ce_score_7.element", "empty_space" }, { "game.panel.ce_score_7.draw_masked", "true" }, { "game.panel.ce_score_7.draw_order", "0" }, { "game.panel.ce_score_7_element.x", "-1" }, { "game.panel.ce_score_7_element.y", "-1" }, { "game.panel.ce_score_7_element.tile_size", "16" }, { "game.panel.ce_score_7_element.element", "empty_space" }, { "game.panel.ce_score_7_element.draw_masked","false" }, { "game.panel.ce_score_7_element.draw_order", "0" }, { "game.panel.ce_score_8.x", "-1" }, { "game.panel.ce_score_8.y", "-1" }, { "game.panel.ce_score_8.align", "left" }, { "game.panel.ce_score_8.valign", "top" }, { "game.panel.ce_score_8.digits", "-1" }, { "game.panel.ce_score_8.font", "font.text_2" }, { "game.panel.ce_score_8.element", "empty_space" }, { "game.panel.ce_score_8.draw_masked", "true" }, { "game.panel.ce_score_8.draw_order", "0" }, { "game.panel.ce_score_8_element.x", "-1" }, { "game.panel.ce_score_8_element.y", "-1" }, { "game.panel.ce_score_8_element.tile_size", "16" }, { "game.panel.ce_score_8_element.element", "empty_space" }, { "game.panel.ce_score_8_element.draw_masked","false" }, { "game.panel.ce_score_8_element.draw_order", "0" }, { "game.panel.player_name.x", "-1" }, { "game.panel.player_name.y", "-1" }, { "game.panel.player_name.align", "left" }, { "game.panel.player_name.valign", "top" }, { "game.panel.player_name.chars", "-1" }, { "game.panel.player_name.font", "font.text_2" }, { "game.panel.player_name.draw_masked", "true" }, { "game.panel.player_name.draw_order", "0" }, { "game.panel.level_name.x", "-1" }, { "game.panel.level_name.y", "-1" }, { "game.panel.level_name.align", "left" }, { "game.panel.level_name.valign", "top" }, { "game.panel.level_name.chars", "-1" }, { "game.panel.level_name.font", "font.text_2" }, { "game.panel.level_name.draw_masked", "true" }, { "game.panel.level_name.draw_order", "0" }, { "game.panel.level_author.x", "-1" }, { "game.panel.level_author.y", "-1" }, { "game.panel.level_author.align", "left" }, { "game.panel.level_author.valign", "top" }, { "game.panel.level_author.chars", "-1" }, { "game.panel.level_author.font", "font.text_2" }, { "game.panel.level_author.draw_masked", "true" }, { "game.panel.level_author.draw_order", "0" }, { "game.button.stop.x", "5" }, { "game.button.stop.y", "215" }, { "game.button.pause.x", "35" }, { "game.button.pause.y", "215" }, { "game.button.play.x", "65" }, { "game.button.play.y", "215" }, { "game.button.sound_music.x", "5" }, { "game.button.sound_music.y", "245" }, { "game.button.sound_loops.x", "35" }, { "game.button.sound_loops.y", "245" }, { "game.button.sound_simple.x", "65" }, { "game.button.sound_simple.y", "245" }, { "game.forced_scroll_delay_value", "-1" }, { "game.use_native_emc_graphics_engine", "false" }, { "game.use_native_sp_graphics_engine", "true" }, { "game.use_masked_pushing", "false" }, { "[player].boring_delay_fixed", "1000" }, { "[player].boring_delay_random", "1000" }, { "[player].sleeping_delay_fixed", "2000" }, { "[player].sleeping_delay_random", "2000" }, { "viewport.window.width", "672" }, { "viewport.window.height", "560" }, { "viewport.playfield.x", "6" }, { "viewport.playfield.y", "6" }, { "viewport.playfield.width", "548" }, { "viewport.playfield.height", "548" }, { "viewport.playfield.border_size", "2" }, { "viewport.playfield.MAIN.x", ARG_DEFAULT }, { "viewport.playfield.MAIN.y", ARG_DEFAULT }, { "viewport.playfield.MAIN.width", ARG_DEFAULT }, { "viewport.playfield.MAIN.height", ARG_DEFAULT }, { "viewport.playfield.MAIN.border_size", ARG_DEFAULT }, { "viewport.playfield.PLAYING.x", ARG_DEFAULT }, { "viewport.playfield.PLAYING.y", ARG_DEFAULT }, { "viewport.playfield.PLAYING.width", ARG_DEFAULT }, { "viewport.playfield.PLAYING.height", ARG_DEFAULT }, { "viewport.playfield.PLAYING.border_size", ARG_DEFAULT }, { "viewport.playfield.EDITOR.x", ARG_DEFAULT }, { "viewport.playfield.EDITOR.y", ARG_DEFAULT }, { "viewport.playfield.EDITOR.width", ARG_DEFAULT }, { "viewport.playfield.EDITOR.height", ARG_DEFAULT }, { "viewport.playfield.EDITOR.border_size", ARG_DEFAULT }, { "viewport.door_1.x", "566" }, { "viewport.door_1.y", "60" }, { "viewport.door_1.MAIN.x", ARG_DEFAULT }, { "viewport.door_1.MAIN.y", ARG_DEFAULT }, { "viewport.door_1.PLAYING.x", ARG_DEFAULT }, { "viewport.door_1.PLAYING.y", ARG_DEFAULT }, { "viewport.door_1.EDITOR.x", ARG_DEFAULT }, { "viewport.door_1.EDITOR.y", ARG_DEFAULT }, { "viewport.door_2.x", "566" }, { "viewport.door_2.y", "400" }, { "viewport.door_2.MAIN.x", ARG_DEFAULT }, { "viewport.door_2.MAIN.y", ARG_DEFAULT }, { "viewport.door_2.PLAYING.x", ARG_DEFAULT }, { "viewport.door_2.PLAYING.y", ARG_DEFAULT }, { "viewport.door_2.EDITOR.x", "566" }, { "viewport.door_2.EDITOR.y", "356" }, { NULL, NULL } }; rocksndiamonds-3.3.0.1+dfsg1/src/events.c0000644000175000017500000006541611403521210017066 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * events.c * ***********************************************************/ #include "libgame/libgame.h" #include "events.h" #include "init.h" #include "screens.h" #include "tools.h" #include "game.h" #include "editor.h" #include "files.h" #include "tape.h" #include "network.h" #define DEBUG_EVENTS 0 static boolean cursor_inside_playfield = FALSE; static boolean playfield_cursor_set = FALSE; static unsigned long playfield_cursor_delay = 0; /* event filter especially needed for SDL event filtering due to delay problems with lots of mouse motion events when mouse button not pressed (X11 can handle this with 'PointerMotionHintMask') */ int FilterMouseMotionEvents(const Event *event) { MotionEvent *motion; /* non-motion events are directly passed to event handler functions */ if (event->type != EVENT_MOTIONNOTIFY) return 1; motion = (MotionEvent *)event; cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE && motion->y >= SY && motion->y < SY + SYSIZE); if (game_status == GAME_MODE_PLAYING && playfield_cursor_set) { SetMouseCursor(CURSOR_DEFAULT); playfield_cursor_set = FALSE; DelayReached(&playfield_cursor_delay, 0); } /* skip mouse motion events without pressed button outside level editor */ if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING) return 0; else return 1; } /* to prevent delay problems, skip mouse motion events if the very next event is also a mouse motion event (and therefore effectively only handling the last of a row of mouse motion events in the event queue) */ boolean SkipPressedMouseMotionEvent(const Event *event) { /* nothing to do if the current event is not a mouse motion event */ if (event->type != EVENT_MOTIONNOTIFY) return FALSE; /* only skip motion events with pressed button outside level editor */ if (button_status == MB_RELEASED || game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING) return FALSE; if (PendingEvent()) { Event next_event; PeekEvent(&next_event); /* if next event is also a mouse motion event, skip the current one */ if (next_event.type == EVENT_MOTIONNOTIFY) return TRUE; } return FALSE; } /* this is only really needed for non-SDL targets to filter unwanted events; when using SDL with properly installed event filter, this function can be replaced with a simple "NextEvent()" call, but it doesn't hurt either */ static boolean NextValidEvent(Event *event) { while (PendingEvent()) { boolean handle_this_event = FALSE; NextEvent(event); if (FilterMouseMotionEvents(event)) handle_this_event = TRUE; if (SkipPressedMouseMotionEvent(event)) handle_this_event = FALSE; if (handle_this_event) return TRUE; } return FALSE; } void EventLoop(void) { while (1) { if (PendingEvent()) /* got event */ { Event event; while (NextValidEvent(&event)) { switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_BUTTONRELEASE: HandleButtonEvent((ButtonEvent *) &event); break; case EVENT_MOTIONNOTIFY: HandleMotionEvent((MotionEvent *) &event); break; case EVENT_KEYPRESS: case EVENT_KEYRELEASE: HandleKeyEvent((KeyEvent *) &event); break; default: HandleOtherEvents(&event); break; } } } else { /* when playing, display a special mouse pointer inside the playfield */ if (game_status == GAME_MODE_PLAYING && !tape.pausing) { if (!playfield_cursor_set && cursor_inside_playfield && DelayReached(&playfield_cursor_delay, 1000)) { SetMouseCursor(CURSOR_PLAYFIELD); playfield_cursor_set = TRUE; } } else if (playfield_cursor_set) { SetMouseCursor(CURSOR_DEFAULT); playfield_cursor_set = FALSE; } HandleNoEvent(); } /* don't use all CPU time when idle; the main loop while playing has its own synchronization and is CPU friendly, too */ if (game_status == GAME_MODE_PLAYING) { HandleGameActions(); } else { SyncDisplay(); if (!PendingEvent()) /* delay only if no pending events */ Delay(10); } /* refresh window contents from drawing buffer, if needed */ BackToFront(); if (game_status == GAME_MODE_QUIT) return; } } void HandleOtherEvents(Event *event) { switch (event->type) { case EVENT_EXPOSE: HandleExposeEvent((ExposeEvent *) event); break; case EVENT_UNMAPNOTIFY: #if 0 /* This causes the game to stop not only when iconified, but also when on another virtual desktop, which might be not desired. */ SleepWhileUnmapped(); #endif break; case EVENT_FOCUSIN: case EVENT_FOCUSOUT: HandleFocusEvent((FocusChangeEvent *) event); break; case EVENT_CLIENTMESSAGE: HandleClientMessageEvent((ClientMessageEvent *) event); break; #if defined(TARGET_SDL) case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: HandleJoystickEvent(event); break; case SDL_SYSWMEVENT: HandleWindowManagerEvent(event); break; #endif default: break; } } void ClearEventQueue() { while (PendingEvent()) { Event event; NextEvent(&event); switch (event.type) { case EVENT_BUTTONRELEASE: button_status = MB_RELEASED; break; case EVENT_KEYRELEASE: #if 1 ClearPlayerAction(); #else key_joystick_mapping = 0; #endif break; default: HandleOtherEvents(&event); break; } } } void ClearPlayerAction() { int i; /* simulate key release events for still pressed keys */ key_joystick_mapping = 0; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].action = 0; } void SleepWhileUnmapped() { boolean window_unmapped = TRUE; KeyboardAutoRepeatOn(); while (window_unmapped) { Event event; NextEvent(&event); switch (event.type) { case EVENT_BUTTONRELEASE: button_status = MB_RELEASED; break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; case EVENT_MAPNOTIFY: window_unmapped = FALSE; break; case EVENT_UNMAPNOTIFY: /* this is only to surely prevent the 'should not happen' case * of recursively looping between 'SleepWhileUnmapped()' and * 'HandleOtherEvents()' which usually calls this funtion. */ break; default: HandleOtherEvents(&event); break; } } if (game_status == GAME_MODE_PLAYING) KeyboardAutoRepeatOffUnlessAutoplay(); } void HandleExposeEvent(ExposeEvent *event) { #ifndef TARGET_SDL RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height); FlushDisplay(); #endif } void HandleButtonEvent(ButtonEvent *event) { #if DEBUG_EVENTS printf("::: BUTTON EVENT: button %d %s\n", event->button, event->type == EVENT_BUTTONPRESS ? "pressed" : "released"); #endif motion_status = FALSE; if (event->type == EVENT_BUTTONPRESS) button_status = event->button; else button_status = MB_RELEASED; HandleButton(event->x, event->y, button_status, event->button); } void HandleMotionEvent(MotionEvent *event) { if (!PointerInWindow(window)) return; /* window and pointer are on different screens */ if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR) return; motion_status = TRUE; HandleButton(event->x, event->y, button_status, button_status); } void HandleKeyEvent(KeyEvent *event) { int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED); boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE); Key key = GetEventKey(event, with_modifiers); Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key); #if DEBUG_EVENTS printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE), event->type == EVENT_KEYPRESS ? "pressed" : "released"); #endif HandleKeyModState(keymod, key_status); HandleKey(key, key_status); } void HandleFocusEvent(FocusChangeEvent *event) { static int old_joystick_status = -1; if (event->type == EVENT_FOCUSOUT) { KeyboardAutoRepeatOn(); old_joystick_status = joystick.status; joystick.status = JOYSTICK_NOT_AVAILABLE; ClearPlayerAction(); } else if (event->type == EVENT_FOCUSIN) { /* When there are two Rocks'n'Diamonds windows which overlap and the player moves the pointer from one game window to the other, a 'FocusOut' event is generated for the window the pointer is leaving and a 'FocusIn' event is generated for the window the pointer is entering. In some cases, it can happen that the 'FocusIn' event is handled by the one game process before the 'FocusOut' event by the other game process. In this case the X11 environment would end up with activated keyboard auto repeat, because unfortunately this is a global setting and not (which would be far better) set for each X11 window individually. The effect would be keyboard auto repeat while playing the game (game_status == GAME_MODE_PLAYING), which is not desired. To avoid this special case, we just wait 1/10 second before processing the 'FocusIn' event. */ if (game_status == GAME_MODE_PLAYING) { Delay(100); KeyboardAutoRepeatOffUnlessAutoplay(); } if (old_joystick_status != -1) joystick.status = old_joystick_status; } } void HandleClientMessageEvent(ClientMessageEvent *event) { if (CheckCloseWindowEvent(event)) CloseAllAndExit(0); } void HandleWindowManagerEvent(Event *event) { #if defined(TARGET_SDL) SDLHandleWindowManagerEvent(event); #endif } void HandleButton(int mx, int my, int button, int button_nr) { static int old_mx = 0, old_my = 0; if (button < 0) { mx = old_mx; my = old_my; button = -button; } else { old_mx = mx; old_my = my; } if (HandleGadgets(mx, my, button)) { /* do not handle this button event anymore */ mx = my = -32; /* force mouse event to be outside screen tiles */ } /* do not use scroll wheel button events for anything other than gadgets */ if (IS_WHEEL_BUTTON(button_nr)) return; switch (game_status) { case GAME_MODE_TITLE: HandleTitleScreen(mx, my, 0, 0, button); break; case GAME_MODE_MAIN: HandleMainMenu(mx, my, 0, 0, button); break; case GAME_MODE_PSEUDO_TYPENAME: HandleTypeName(0, KSYM_Return); break; case GAME_MODE_LEVELS: HandleChooseLevel(mx, my, 0, 0, button); break; case GAME_MODE_SCORES: HandleHallOfFame(0, 0, 0, 0, button); break; case GAME_MODE_EDITOR: HandleLevelEditorIdle(); break; case GAME_MODE_INFO: HandleInfoScreen(mx, my, 0, 0, button); break; case GAME_MODE_SETUP: HandleSetupScreen(mx, my, 0, 0, button); break; case GAME_MODE_PLAYING: #ifdef DEBUG if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my)) DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY)); #endif break; default: break; } } static boolean is_string_suffix(char *string, char *suffix) { int string_len = strlen(string); int suffix_len = strlen(suffix); if (suffix_len > string_len) return FALSE; return (strEqual(&string[string_len - suffix_len], suffix)); } #define MAX_CHEAT_INPUT_LEN 32 static void HandleKeysSpecial(Key key) { static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = ""; char letter = getCharFromKey(key); int cheat_input_len = strlen(cheat_input); int i; if (letter == 0) return; if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN) { for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++) cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i]; cheat_input_len = MAX_CHEAT_INPUT_LEN; } cheat_input[cheat_input_len++] = letter; cheat_input[cheat_input_len] = '\0'; #if DEBUG_EVENTS printf("::: '%s' [%d]\n", cheat_input, cheat_input_len); #endif if (game_status == GAME_MODE_MAIN) { if (is_string_suffix(cheat_input, ":insert-solution-tape") || is_string_suffix(cheat_input, ":ist")) { InsertSolutionTape(); } else if (is_string_suffix(cheat_input, ":reload-graphics") || is_string_suffix(cheat_input, ":rg")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-sounds") || is_string_suffix(cheat_input, ":rs")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-music") || is_string_suffix(cheat_input, ":rm")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-artwork") || is_string_suffix(cheat_input, ":ra")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS | 1 << ARTWORK_TYPE_SOUNDS | 1 << ARTWORK_TYPE_MUSIC); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":dump-level") || is_string_suffix(cheat_input, ":dl")) { DumpLevel(&level); } else if (is_string_suffix(cheat_input, ":dump-tape") || is_string_suffix(cheat_input, ":dt")) { DumpTape(&tape); } else if (is_string_suffix(cheat_input, ":save-native-level") || is_string_suffix(cheat_input, ":snl")) { SaveNativeLevel(&level); } } else if (game_status == GAME_MODE_PLAYING) { #ifdef DEBUG if (is_string_suffix(cheat_input, ".q")) DEBUG_SetMaximumDynamite(); #endif } else if (game_status == GAME_MODE_EDITOR) { if (is_string_suffix(cheat_input, ":dump-brush") || is_string_suffix(cheat_input, ":DB")) { DumpBrush(); } else if (is_string_suffix(cheat_input, ":DDB")) { DumpBrush_Small(); } } } void HandleKey(Key key, int key_status) { boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive(); static struct SetupKeyboardInfo ski; static struct SetupShortcutInfo ssi; static struct { Key *key_custom; Key *key_snap; Key key_default; byte action; } key_info[] = { { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT }, { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT }, { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP }, { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN }, { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP }, { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP } }; int joy = 0; int i; if (game_status == GAME_MODE_PLAYING) { /* only needed for single-step tape recording mode */ static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE }; static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE }; int pnr; ssi = setup.shortcut; for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { byte key_action = 0; if (setup.input[pnr].use_joystick) continue; ski = setup.input[pnr].key; for (i = 0; i < NUM_PLAYER_ACTIONS; i++) if (key == *key_info[i].key_custom) key_action |= key_info[i].action; for (i = 0; i < NUM_DIRECTIONS; i++) if (key == *key_info[i].key_snap) key_action |= key_info[i].action | JOY_BUTTON_SNAP; if (tape.single_step && clear_button_2[pnr]) { stored_player[pnr].action &= ~KEY_BUTTON_2; clear_button_2[pnr] = FALSE; } if (key_status == KEY_PRESSED) stored_player[pnr].action |= key_action; else stored_player[pnr].action &= ~key_action; if (tape.single_step && tape.recording && tape.pausing) { if (key_status == KEY_PRESSED && (key_action & (KEY_MOTION | KEY_BUTTON_1))) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); if (key_action & KEY_MOTION) { if (stored_player[pnr].action & KEY_BUTTON_2) element_dropped[pnr] = TRUE; } } else if (key_status == KEY_RELEASED && (key_action & KEY_BUTTON_2)) { if (!element_dropped[pnr]) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); stored_player[pnr].action |= KEY_BUTTON_2; clear_button_2[pnr] = TRUE; } element_dropped[pnr] = FALSE; } } #if 1 else if (tape.recording && tape.pausing) { /* prevent key release events from un-pausing a paused game */ if (key_status == KEY_PRESSED && (key_action & KEY_ACTION)) TapeTogglePause(TAPE_TOGGLE_MANUAL); } #else else if (tape.recording && tape.pausing && (key_action & KEY_ACTION)) TapeTogglePause(TAPE_TOGGLE_MANUAL); #endif } } else { for (i = 0; i < NUM_PLAYER_ACTIONS; i++) if (key == key_info[i].key_default) joy |= key_info[i].action; } if (joy) { if (key_status == KEY_PRESSED) key_joystick_mapping |= joy; else key_joystick_mapping &= ~joy; HandleJoystick(); } if (game_status != GAME_MODE_PLAYING) key_joystick_mapping = 0; if (key_status == KEY_RELEASED) return; if ((key == KSYM_Return || key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt) && video.fullscreen_available) { setup.fullscreen = !setup.fullscreen; ToggleFullscreenIfNeeded(); if (game_status == GAME_MODE_SETUP) RedrawSetupScreenAfterFullscreenToggle(); return; } #if 0 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd && (key == KSYM_Return || key == setup.shortcut.toggle_pause)) #else if (game_status == GAME_MODE_PLAYING && AllPlayersGone && (key == KSYM_Return || key == setup.shortcut.toggle_pause)) #endif { GameEnd(); return; } if (game_status == GAME_MODE_MAIN && (key == setup.shortcut.toggle_pause || key == KSYM_space)) { StartGameActions(options.network, setup.autorecord, level.random_seed); return; } if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING) { if (key == setup.shortcut.save_game) TapeQuickSave(); else if (key == setup.shortcut.load_game) TapeQuickLoad(); else if (key == setup.shortcut.toggle_pause) TapeTogglePause(TAPE_TOGGLE_MANUAL); HandleTapeButtonKeys(key); HandleSoundButtonKeys(key); } if (game_status == GAME_MODE_PLAYING && !network_playing) { int centered_player_nr_next = -999; if (key == setup.shortcut.focus_player_all) centered_player_nr_next = -1; else for (i = 0; i < MAX_PLAYERS; i++) if (key == setup.shortcut.focus_player[i]) centered_player_nr_next = i; if (centered_player_nr_next != -999) { game.centered_player_nr_next = centered_player_nr_next; game.set_centered_player = TRUE; if (tape.recording) { tape.centered_player_nr_next = game.centered_player_nr_next; tape.set_centered_player = TRUE; } } } HandleKeysSpecial(key); if (HandleGadgetsKeyInput(key)) { if (key != KSYM_Escape) /* always allow ESC key to be handled */ key = KSYM_UNDEFINED; } switch (game_status) { case GAME_MODE_PSEUDO_TYPENAME: HandleTypeName(0, key); break; case GAME_MODE_TITLE: case GAME_MODE_MAIN: case GAME_MODE_LEVELS: case GAME_MODE_SETUP: case GAME_MODE_INFO: case GAME_MODE_SCORES: switch (key) { case KSYM_space: case KSYM_Return: if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_MAIN) HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE); break; case KSYM_Escape: if (game_status != GAME_MODE_MAIN) FadeSkipNextFadeIn(); if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE); break; case KSYM_Page_Up: if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); break; case KSYM_Page_Down: if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); break; #ifdef DEBUG case KSYM_0: GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500); break; case KSYM_b: setup.sp_show_border_elements = !setup.sp_show_border_elements; printf("Supaplex border elements %s\n", setup.sp_show_border_elements ? "enabled" : "disabled"); break; #endif default: break; } break; case GAME_MODE_EDITOR: if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape) HandleLevelEditorKeyInput(key); break; case GAME_MODE_PLAYING: { switch (key) { case KSYM_Escape: RequestQuitGame(setup.ask_on_escape); break; #ifdef DEBUG case KSYM_0: #if 0 case KSYM_1: case KSYM_2: case KSYM_3: case KSYM_4: case KSYM_5: case KSYM_6: case KSYM_7: case KSYM_8: case KSYM_9: #endif if (key == KSYM_0) { if (GameFrameDelay == 500) GameFrameDelay = GAME_FRAME_DELAY; else GameFrameDelay = 500; } else GameFrameDelay = (key - KSYM_0) * 10; printf("Game speed == %d%% (%d ms delay between two frames)\n", GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay); break; case KSYM_d: if (options.debug) { options.debug = FALSE; printf("debug mode disabled\n"); } else { options.debug = TRUE; printf("debug mode enabled\n"); } break; case KSYM_S: if (!global.fps_slowdown) { global.fps_slowdown = TRUE; global.fps_slowdown_factor = 2; printf("fps slowdown enabled -- display only every 2nd frame\n"); } else if (global.fps_slowdown_factor == 2) { global.fps_slowdown_factor = 4; printf("fps slowdown enabled -- display only every 4th frame\n"); } else { global.fps_slowdown = FALSE; global.fps_slowdown_factor = 1; printf("fps slowdown disabled\n"); } break; case KSYM_f: ScrollStepSize = TILEX/8; printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize); break; case KSYM_g: ScrollStepSize = TILEX/4; printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize); break; case KSYM_h: ScrollStepSize = TILEX/2; printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize); break; case KSYM_l: ScrollStepSize = TILEX; printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize); break; case KSYM_v: printf("::: currently using game engine version %d\n", game.engine_version); break; #endif default: break; } break; } default: if (key == KSYM_Escape) { game_status = GAME_MODE_MAIN; DrawMainMenu(); return; } } } void HandleNoEvent() { if (button_status && game_status != GAME_MODE_PLAYING) { HandleButton(0, 0, -button_status, button_status); return; } #if defined(NETWORK_AVALIABLE) if (options.network) HandleNetworking(); #endif HandleJoystick(); } static int HandleJoystickForAllPlayers() { int i; int result = 0; for (i = 0; i < MAX_PLAYERS; i++) { byte joy_action = 0; /* if (!setup.input[i].use_joystick) continue; */ joy_action = Joystick(i); result |= joy_action; if (!setup.input[i].use_joystick) continue; stored_player[i].action = joy_action; } return result; } void HandleJoystick() { int joystick = HandleJoystickForAllPlayers(); int keyboard = key_joystick_mapping; int joy = (joystick | keyboard); int left = joy & JOY_LEFT; int right = joy & JOY_RIGHT; int up = joy & JOY_UP; int down = joy & JOY_DOWN; int button = joy & JOY_BUTTON; int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED); int dx = (left ? -1 : right ? 1 : 0); int dy = (up ? -1 : down ? 1 : 0); switch (game_status) { case GAME_MODE_TITLE: case GAME_MODE_MAIN: case GAME_MODE_LEVELS: case GAME_MODE_SETUP: case GAME_MODE_INFO: { static unsigned long joystickmove_delay = 0; if (joystick && !button && !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY)) newbutton = dx = dy = 0; if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_MAIN) HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); break; } case GAME_MODE_SCORES: HandleHallOfFame(0, 0, dx, dy, !newbutton); break; case GAME_MODE_EDITOR: HandleLevelEditorIdle(); break; case GAME_MODE_PLAYING: if (tape.playing || keyboard) newbutton = ((joy & JOY_BUTTON) != 0); #if 0 if (local_player->LevelSolved_GameEnd && newbutton) #else if (AllPlayersGone && newbutton) #endif { GameEnd(); return; } break; default: break; } } rocksndiamonds-3.3.0.1+dfsg1/src/conf_e2s.c0000644000175000017500000004137211375255512017274 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_e2s.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_E2S_C #define CONF_E2S_C /* values for element/sounds mapping configuration */ static struct { int element; boolean is_class; int action; int sound; } element_to_sound[] = { { EL_DEFAULT, TRUE, ACTION_DIGGING, SND_CLASS_DEFAULT_DIGGING }, { EL_DEFAULT, TRUE, ACTION_COLLECTING, SND_CLASS_DEFAULT_COLLECTING }, { EL_DEFAULT, TRUE, ACTION_SNAPPING, SND_CLASS_DEFAULT_SNAPPING }, { EL_DEFAULT, TRUE, ACTION_PUSHING, SND_CLASS_DEFAULT_PUSHING }, { EL_DEFAULT, TRUE, ACTION_IMPACT, SND_CLASS_DEFAULT_IMPACT }, { EL_DEFAULT, TRUE, ACTION_WALKING, SND_CLASS_DEFAULT_WALKING }, { EL_DEFAULT, TRUE, ACTION_PASSING, SND_CLASS_DEFAULT_PASSING }, { EL_DEFAULT, TRUE, ACTION_DYING, SND_CLASS_DEFAULT_DYING }, { EL_DEFAULT, TRUE, ACTION_EXPLODING, SND_CLASS_DEFAULT_EXPLODING }, { EL_SP_DEFAULT, TRUE, ACTION_EXPLODING, SND_CLASS_SP_DEFAULT_EXPLODING }, { EL_BD_DIAMOND, FALSE, ACTION_COLLECTING, SND_BD_DIAMOND_COLLECTING }, { EL_BD_DIAMOND, FALSE, ACTION_IMPACT, SND_BD_DIAMOND_IMPACT }, { EL_BD_ROCK, FALSE, ACTION_PUSHING, SND_BD_ROCK_PUSHING }, { EL_BD_ROCK, FALSE, ACTION_IMPACT, SND_BD_ROCK_IMPACT }, { EL_BD_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_BD_MAGIC_WALL_ACTIVATING }, { EL_BD_MAGIC_WALL_ACTIVE, FALSE, -1, SND_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL_FILLING, FALSE, -1, SND_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL, FALSE, ACTION_FILLING, SND_BD_MAGIC_WALL_FILLING }, { EL_BD_AMOEBA, FALSE, ACTION_WAITING, SND_BD_AMOEBA_WAITING }, { EL_BD_AMOEBA, FALSE, ACTION_GROWING, SND_BD_AMOEBA_GROWING }, { EL_BD_BUTTERFLY, FALSE, ACTION_MOVING, SND_BD_BUTTERFLY_MOVING }, { EL_BD_BUTTERFLY, FALSE, ACTION_WAITING, SND_BD_BUTTERFLY_WAITING }, { EL_BD_FIREFLY, FALSE, ACTION_MOVING, SND_BD_FIREFLY_MOVING }, { EL_BD_FIREFLY, FALSE, ACTION_WAITING, SND_BD_FIREFLY_WAITING }, { EL_SP_BASE, FALSE, ACTION_DIGGING, SND_SP_BASE_DIGGING }, { EL_SP_BUGGY_BASE, FALSE, ACTION_DIGGING, SND_SP_BUGGY_BASE_DIGGING }, { EL_SP_BUGGY_BASE_ACTIVE, FALSE, -1, SND_SP_BUGGY_BASE_ACTIVE }, { EL_SP_BUGGY_BASE, FALSE, ACTION_ACTIVE, SND_SP_BUGGY_BASE_ACTIVE }, { EL_SP_INFOTRON, FALSE, ACTION_COLLECTING, SND_SP_INFOTRON_COLLECTING }, { EL_SP_INFOTRON, FALSE, ACTION_IMPACT, SND_SP_INFOTRON_IMPACT }, { EL_SP_ZONK, FALSE, ACTION_PUSHING, SND_SP_ZONK_PUSHING }, { EL_SP_ZONK, FALSE, ACTION_IMPACT, SND_SP_ZONK_IMPACT }, { EL_SP_DISK_RED, FALSE, ACTION_COLLECTING, SND_SP_DISK_RED_COLLECTING }, { EL_SP_DISK_ORANGE, FALSE, ACTION_PUSHING, SND_SP_DISK_ORANGE_PUSHING }, { EL_SP_DISK_YELLOW, FALSE, ACTION_PUSHING, SND_SP_DISK_YELLOW_PUSHING }, { EL_SP_PORT_RIGHT, TRUE, ACTION_PASSING, SND_CLASS_SP_PORT_PASSING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_SP_EXIT_PASSING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_SP_EXIT_OPENING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_SP_EXIT_CLOSING }, { EL_SP_SNIKSNAK, FALSE, ACTION_MOVING, SND_SP_SNIKSNAK_MOVING }, { EL_SP_SNIKSNAK, FALSE, ACTION_WAITING, SND_SP_SNIKSNAK_WAITING }, { EL_SP_ELECTRON, FALSE, ACTION_MOVING, SND_SP_ELECTRON_MOVING }, { EL_SP_ELECTRON, FALSE, ACTION_WAITING, SND_SP_ELECTRON_WAITING }, { EL_SP_TERMINAL, FALSE, ACTION_ACTIVATING, SND_SP_TERMINAL_ACTIVATING }, { EL_SP_TERMINAL_ACTIVE, FALSE, -1, SND_SP_TERMINAL_ACTIVE }, { EL_SP_TERMINAL, FALSE, ACTION_ACTIVE, SND_SP_TERMINAL_ACTIVE }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_PUSHING, SND_CLASS_SOKOBAN_PUSHING }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_FILLING, SND_CLASS_SOKOBAN_FILLING }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_EMPTYING, SND_CLASS_SOKOBAN_EMPTYING }, { EL_PLAYER_1, TRUE, ACTION_MOVING, SND_CLASS_PLAYER_MOVING }, { EL_SAND, FALSE, ACTION_DIGGING, SND_SAND_DIGGING }, { EL_EMERALD, TRUE, ACTION_COLLECTING, SND_CLASS_EMERALD_COLLECTING }, { EL_EMERALD, TRUE, ACTION_IMPACT, SND_CLASS_EMERALD_IMPACT }, { EL_DIAMOND, FALSE, ACTION_COLLECTING, SND_DIAMOND_COLLECTING }, { EL_DIAMOND, FALSE, ACTION_IMPACT, SND_DIAMOND_IMPACT }, { EL_DIAMOND_BREAKING, FALSE, -1, SND_DIAMOND_BREAKING }, { EL_DIAMOND, FALSE, ACTION_BREAKING, SND_DIAMOND_BREAKING }, { EL_ROCK, FALSE, ACTION_PUSHING, SND_ROCK_PUSHING }, { EL_ROCK, FALSE, ACTION_IMPACT, SND_ROCK_IMPACT }, { EL_BOMB, FALSE, ACTION_PUSHING, SND_BOMB_PUSHING }, { EL_NUT, FALSE, ACTION_PUSHING, SND_NUT_PUSHING }, { EL_NUT_BREAKING, FALSE, -1, SND_NUT_BREAKING }, { EL_NUT, FALSE, ACTION_BREAKING, SND_NUT_BREAKING }, { EL_NUT, FALSE, ACTION_IMPACT, SND_NUT_IMPACT }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_COLLECTING, SND_CLASS_DYNAMITE_COLLECTING }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_DROPPING, SND_CLASS_DYNAMITE_DROPPING }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_ACTIVE, SND_CLASS_DYNAMITE_ACTIVE }, { EL_KEY_1, TRUE, ACTION_COLLECTING, SND_CLASS_KEY_COLLECTING }, { EL_GATE_1, TRUE, ACTION_PASSING, SND_CLASS_GATE_PASSING }, { EL_BUG, FALSE, ACTION_MOVING, SND_BUG_MOVING }, { EL_BUG, FALSE, ACTION_WAITING, SND_BUG_WAITING }, { EL_SPACESHIP, FALSE, ACTION_MOVING, SND_SPACESHIP_MOVING }, { EL_SPACESHIP, FALSE, ACTION_WAITING, SND_SPACESHIP_WAITING }, { EL_YAMYAM, FALSE, ACTION_MOVING, SND_YAMYAM_MOVING }, { EL_YAMYAM, FALSE, ACTION_WAITING, SND_YAMYAM_WAITING }, { EL_YAMYAM, FALSE, ACTION_DIGGING, SND_YAMYAM_DIGGING }, { EL_ROBOT, FALSE, ACTION_MOVING, SND_ROBOT_MOVING }, { EL_ROBOT, FALSE, ACTION_WAITING, SND_ROBOT_WAITING }, { EL_ROBOT_WHEEL, FALSE, ACTION_ACTIVATING, SND_ROBOT_WHEEL_ACTIVATING }, { EL_ROBOT_WHEEL_ACTIVE, FALSE, -1, SND_ROBOT_WHEEL_ACTIVE }, { EL_ROBOT_WHEEL, FALSE, ACTION_ACTIVE, SND_ROBOT_WHEEL_ACTIVE }, { EL_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_MAGIC_WALL_ACTIVATING }, { EL_MAGIC_WALL_ACTIVE, FALSE, -1, SND_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL_FILLING, FALSE, -1, SND_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL, FALSE, ACTION_FILLING, SND_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_DC_MAGIC_WALL_ACTIVATING }, { EL_DC_MAGIC_WALL_ACTIVE, FALSE, -1, SND_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL_FILLING, FALSE, -1, SND_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, FALSE, ACTION_FILLING, SND_DC_MAGIC_WALL_FILLING }, { EL_AMOEBA_DEAD, TRUE, ACTION_WAITING, SND_CLASS_AMOEBA_WAITING }, { EL_AMOEBA_DEAD, TRUE, ACTION_GROWING, SND_CLASS_AMOEBA_GROWING }, { EL_AMOEBA_DEAD, TRUE, ACTION_DROPPING, SND_CLASS_AMOEBA_DROPPING }, { EL_ACID, FALSE, ACTION_SPLASHING, SND_ACID_SPLASHING }, { EL_QUICKSAND_EMPTY, TRUE, ACTION_FILLING, SND_CLASS_QUICKSAND_FILLING }, { EL_QUICKSAND_EMPTY, TRUE, ACTION_EMPTYING, SND_CLASS_QUICKSAND_EMPTYING }, { EL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EXIT_OPENING }, { EL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EXIT_CLOSING }, { EL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EXIT_PASSING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_STEEL_EXIT_OPENING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_STEEL_EXIT_CLOSING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_STEEL_EXIT_PASSING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EM_EXIT_OPENING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EM_EXIT_CLOSING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EM_EXIT_PASSING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EM_STEEL_EXIT_OPENING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EM_STEEL_EXIT_CLOSING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EM_STEEL_EXIT_PASSING }, { EL_PENGUIN, FALSE, ACTION_PASSING, SND_PENGUIN_PASSING }, { EL_BALLOON, FALSE, ACTION_MOVING, SND_BALLOON_MOVING }, { EL_BALLOON, FALSE, ACTION_WAITING, SND_BALLOON_WAITING }, { EL_BALLOON, FALSE, ACTION_PUSHING, SND_BALLOON_PUSHING }, { EL_BALLOON_SWITCH_LEFT, TRUE, ACTION_ACTIVATING, SND_CLASS_BALLOON_SWITCH_ACTIVATING }, { EL_SPRING, FALSE, ACTION_MOVING, SND_SPRING_MOVING }, { EL_SPRING, FALSE, ACTION_PUSHING, SND_SPRING_PUSHING }, { EL_SPRING, FALSE, ACTION_IMPACT, SND_SPRING_IMPACT }, { EL_WALL, TRUE, ACTION_GROWING, SND_CLASS_WALL_GROWING }, { EL_EMC_ANDROID, FALSE, ACTION_PUSHING, SND_EMC_ANDROID_PUSHING }, { EL_EMC_ANDROID, FALSE, ACTION_MOVING, SND_EMC_ANDROID_MOVING }, { EL_EMC_ANDROID, FALSE, ACTION_DROPPING, SND_EMC_ANDROID_DROPPING }, { EL_EMC_MAGIC_BALL, FALSE, ACTION_DROPPING, SND_EMC_MAGIC_BALL_DROPPING }, { EL_PEARL, FALSE, ACTION_COLLECTING, SND_PEARL_COLLECTING }, { EL_PEARL_BREAKING, FALSE, -1, SND_PEARL_BREAKING }, { EL_PEARL, FALSE, ACTION_BREAKING, SND_PEARL_BREAKING }, { EL_PEARL, FALSE, ACTION_IMPACT, SND_PEARL_IMPACT }, { EL_CRYSTAL, FALSE, ACTION_COLLECTING, SND_CRYSTAL_COLLECTING }, { EL_CRYSTAL, FALSE, ACTION_IMPACT, SND_CRYSTAL_IMPACT }, { EL_ENVELOPE_1, TRUE, ACTION_COLLECTING, SND_CLASS_ENVELOPE_COLLECTING }, { EL_ENVELOPE_1, TRUE, ACTION_OPENING, SND_CLASS_ENVELOPE_OPENING }, { EL_ENVELOPE_1, TRUE, ACTION_CLOSING, SND_CLASS_ENVELOPE_CLOSING }, { EL_INVISIBLE_SAND, FALSE, ACTION_DIGGING, SND_INVISIBLE_SAND_DIGGING }, { EL_INVISIBLE_SAND_ACTIVE, FALSE, ACTION_DIGGING, SND_INVISIBLE_SAND_ACTIVE_DIGGING }, { EL_SHIELD_NORMAL, FALSE, ACTION_COLLECTING, SND_SHIELD_NORMAL_COLLECTING }, { EL_SHIELD_NORMAL_ACTIVE, FALSE, -1, SND_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_NORMAL, FALSE, ACTION_ACTIVE, SND_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_DEADLY, FALSE, ACTION_COLLECTING, SND_SHIELD_DEADLY_COLLECTING }, { EL_SHIELD_DEADLY_ACTIVE, FALSE, -1, SND_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_DEADLY, FALSE, ACTION_ACTIVE, SND_SHIELD_DEADLY_ACTIVE }, { EL_EXTRA_TIME, FALSE, ACTION_COLLECTING, SND_EXTRA_TIME_COLLECTING }, { EL_MOLE, FALSE, ACTION_MOVING, SND_MOLE_MOVING }, { EL_MOLE, FALSE, ACTION_WAITING, SND_MOLE_WAITING }, { EL_MOLE, FALSE, ACTION_DIGGING, SND_MOLE_DIGGING }, { EL_SWITCHGATE_SWITCH_UP, TRUE, ACTION_ACTIVATING, SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_OPENING, SND_CLASS_SWITCHGATE_OPENING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_CLOSING, SND_CLASS_SWITCHGATE_CLOSING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_PASSING, SND_CLASS_SWITCHGATE_PASSING }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_ACTIVATING, SND_CLASS_TIMEGATE_SWITCH_ACTIVATING }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_ACTIVE, SND_CLASS_TIMEGATE_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_DEACTIVATING, SND_CLASS_TIMEGATE_SWITCH_DEACTIVATING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_OPENING, SND_CLASS_TIMEGATE_OPENING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_CLOSING, SND_CLASS_TIMEGATE_CLOSING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_PASSING, SND_CLASS_TIMEGATE_PASSING }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE, ACTION_ACTIVATING, SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING }, { EL_CONVEYOR_BELT_1_LEFT, TRUE, ACTION_ACTIVE, SND_CLASS_CONVEYOR_BELT_ACTIVE }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE, ACTION_DEACTIVATING, SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING }, { EL_LIGHT_SWITCH, FALSE, ACTION_ACTIVATING, SND_LIGHT_SWITCH_ACTIVATING }, { EL_LIGHT_SWITCH, FALSE, ACTION_DEACTIVATING, SND_LIGHT_SWITCH_DEACTIVATING }, { EL_DX_SUPABOMB, FALSE, ACTION_PUSHING, SND_DX_SUPABOMB_PUSHING }, { EL_TRAP, FALSE, ACTION_DIGGING, SND_TRAP_DIGGING }, { EL_TRAP, FALSE, ACTION_ACTIVATING, SND_TRAP_ACTIVATING }, { EL_TUBE_ANY, TRUE, ACTION_WALKING, SND_CLASS_TUBE_WALKING }, { EL_SPEED_PILL, FALSE, ACTION_COLLECTING, SND_SPEED_PILL_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_NUMBER_COLLECTING }, { EL_DYNABOMB_INCREASE_SIZE, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_SIZE_COLLECTING }, { EL_DYNABOMB_INCREASE_POWER, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_POWER_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER, TRUE, ACTION_DROPPING, SND_CLASS_DYNABOMB_DROPPING }, { EL_DYNABOMB_INCREASE_NUMBER, TRUE, ACTION_ACTIVE, SND_CLASS_DYNABOMB_ACTIVE }, { EL_SATELLITE, FALSE, ACTION_MOVING, SND_SATELLITE_MOVING }, { EL_SATELLITE, FALSE, ACTION_WAITING, SND_SATELLITE_WAITING }, { EL_SATELLITE, FALSE, ACTION_PUSHING, SND_SATELLITE_PUSHING }, { EL_LAMP, FALSE, ACTION_ACTIVATING, SND_LAMP_ACTIVATING }, { EL_LAMP, FALSE, ACTION_DEACTIVATING, SND_LAMP_DEACTIVATING }, { EL_TIME_ORB_FULL, FALSE, ACTION_COLLECTING, SND_TIME_ORB_FULL_COLLECTING }, { EL_TIME_ORB_FULL, FALSE, ACTION_IMPACT, SND_TIME_ORB_FULL_IMPACT }, { EL_TIME_ORB_EMPTY, FALSE, ACTION_PUSHING, SND_TIME_ORB_EMPTY_PUSHING }, { EL_TIME_ORB_EMPTY, FALSE, ACTION_IMPACT, SND_TIME_ORB_EMPTY_IMPACT }, { EL_GAME_OF_LIFE, FALSE, ACTION_WAITING, SND_GAME_OF_LIFE_WAITING }, { EL_GAME_OF_LIFE, FALSE, ACTION_GROWING, SND_GAME_OF_LIFE_GROWING }, { EL_BIOMAZE, FALSE, ACTION_WAITING, SND_BIOMAZE_WAITING }, { EL_BIOMAZE, FALSE, ACTION_GROWING, SND_BIOMAZE_GROWING }, { EL_PACMAN, FALSE, ACTION_MOVING, SND_PACMAN_MOVING }, { EL_PACMAN, FALSE, ACTION_WAITING, SND_PACMAN_WAITING }, { EL_PACMAN, FALSE, ACTION_DIGGING, SND_PACMAN_DIGGING }, { EL_DARK_YAMYAM, FALSE, ACTION_MOVING, SND_DARK_YAMYAM_MOVING }, { EL_DARK_YAMYAM, FALSE, ACTION_WAITING, SND_DARK_YAMYAM_WAITING }, { EL_DARK_YAMYAM, FALSE, ACTION_DIGGING, SND_DARK_YAMYAM_DIGGING }, { EL_PENGUIN, FALSE, ACTION_MOVING, SND_PENGUIN_MOVING }, { EL_PENGUIN, FALSE, ACTION_WAITING, SND_PENGUIN_WAITING }, { EL_PIG, FALSE, ACTION_MOVING, SND_PIG_MOVING }, { EL_PIG, FALSE, ACTION_WAITING, SND_PIG_WAITING }, { EL_PIG, FALSE, ACTION_DIGGING, SND_PIG_DIGGING }, { EL_DRAGON, FALSE, ACTION_MOVING, SND_DRAGON_MOVING }, { EL_DRAGON, FALSE, ACTION_WAITING, SND_DRAGON_WAITING }, { EL_DRAGON, FALSE, ACTION_ATTACKING, SND_DRAGON_ATTACKING }, { -1, -1, -1, -1 }, }; #endif /* CONF_E2S_C */ rocksndiamonds-3.3.0.1+dfsg1/src/network.c0000644000175000017500000004417411036743211017262 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * network.c * ***********************************************************/ #include "libgame/platform.h" #if defined(NETWORK_AVALIABLE) #include #include #if defined(TARGET_SDL) #include "main.h" #else #include #include #include #include #include #include #endif #include "libgame/libgame.h" #include "network.h" #include "netserv.h" #include "game.h" #include "tape.h" #include "files.h" #include "tools.h" #include "screens.h" struct NetworkClientPlayerInfo { byte nr; char name[MAX_PLAYER_NAME_LEN + 1]; struct NetworkClientPlayerInfo *next; }; static struct NetworkClientPlayerInfo first_player = { 0, EMPTY_PLAYER_NAME, NULL }; /* server stuff */ #if defined(TARGET_SDL) static TCPsocket sfd; /* server socket */ static SDLNet_SocketSet rfds; /* socket set */ #else static int sfd; /* server socket */ #endif static byte realbuffer[512]; static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE]; static byte *buffer = realbuffer + 4; static int nread = 0, nwrite = 0; static boolean stop_network_game = FALSE; static void SendBufferToServer(int size) { if (!options.network) return; realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; realbuffer[3] = (byte)size; buffer[0] = 0; if (nwrite + 4 + size >= MAX_BUFFER_SIZE) Error(ERR_EXIT, "internal error: network send buffer overflow"); memcpy(writbuffer + nwrite, realbuffer, 4 + size); nwrite += 4 + size; /* directly send the buffer to the network server */ #if defined(TARGET_SDL) SDLNet_TCP_Send(sfd, writbuffer, nwrite); #else write(sfd, writbuffer, nwrite); #endif nwrite = 0; } struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr) { struct NetworkClientPlayerInfo *player = NULL; for (player = &first_player; player; player = player->next) if (player->nr == player_nr) break; if (player == NULL) /* should not happen */ Error(ERR_EXIT, "protocol error: reference to non-existing player %d", player_nr); return player; } char *getNetworkPlayerName(int player_nr) { struct NetworkClientPlayerInfo *player; if (player_nr == 0) return("the network game server"); else if (player_nr == first_player.nr) return("you"); else for (player = &first_player; player; player = player->next) if (player->nr == player_nr && player->name && strlen(player->name)) return(player->name); return(EMPTY_PLAYER_NAME); } static void StartNetworkServer(int port) { #if defined(TARGET_SDL) static int p; p = port; server_thread = SDL_CreateThread(NetworkServerThread, &p); network_server = TRUE; #else switch (fork()) { case 0: NetworkServer(port, options.serveronly); /* never reached */ exit(0); case -1: Error(ERR_WARN, "cannot create network server process - no network playing"); options.network = FALSE; return; default: /* we are parent process -- resume normal operation */ return; } #endif } #if defined(TARGET_SDL) boolean ConnectToServer(char *hostname, int port) { IPaddress ip; int i; if (port == 0) port = DEFAULT_SERVER_PORT; rfds = SDLNet_AllocSocketSet(1); if (hostname) { SDLNet_ResolveHost(&ip, hostname, port); if (ip.host == INADDR_NONE) Error(ERR_EXIT, "cannot locate host '%s'", hostname); } else { SDLNet_Write32(0x7f000001, &ip.host); /* 127.0.0.1 */ SDLNet_Write16(port, &ip.port); } sfd = SDLNet_TCP_Open(&ip); if (sfd) { SDLNet_TCP_AddSocket(rfds, sfd); return TRUE; } else { printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError()); } if (hostname) /* connect to specified server failed */ return FALSE; printf("No rocksndiamonds server on localhost -- starting up one ...\n"); StartNetworkServer(port); /* wait for server to start up and try connecting several times */ for (i = 0; i < 6; i++) { Delay(500); /* wait 500 ms == 0.5 seconds */ if ((sfd = SDLNet_TCP_Open(&ip))) /* connected */ { SDLNet_TCP_AddSocket(rfds, sfd); return TRUE; } } /* when reaching this point, connect to newly started server has failed */ return FALSE; } #else boolean ConnectToServer(char *hostname, int port) { struct sockaddr_in s; struct protoent *tcpproto; int on = 1, i; if (hostname) { if ((s.sin_addr.s_addr = inet_addr(hostname)) == -1) { struct hostent *host; if ((host = gethostbyname(hostname)) == NULL) Error(ERR_EXIT, "cannot locate host '%s'", hostname); s.sin_addr = *(struct in_addr *)(host->h_addr_list[0]); } } else s.sin_addr.s_addr = inet_addr("127.0.0.1"); /* localhost */ if (port == 0) port = DEFAULT_SERVER_PORT; s.sin_port = htons(port); s.sin_family = AF_INET; sfd = socket(PF_INET, SOCK_STREAM, 0); if (sfd < 0) Error(ERR_EXIT, "out of file descriptors"); if ((tcpproto = getprotobyname("tcp")) != NULL) setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int)); if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) == 0) /* connected */ return TRUE; if (hostname) /* connect to specified server failed */ return FALSE; printf("No rocksndiamonds server on localhost -- starting up one ...\n"); StartNetworkServer(port); /* wait for server to start up and try connecting several times */ for (i = 0; i < 6; i++) { Delay(500); /* wait 500 ms == 0.5 seconds */ close(sfd); sfd = socket(PF_INET, SOCK_STREAM, 0); if (sfd < 0) Error(ERR_EXIT, "out of file descriptors"); setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int)); if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0) /* connected */ return TRUE; } /* when reaching this point, connect to newly started server has failed */ return FALSE; } #endif /* defined(TARGET_SDL) */ void SendToServer_PlayerName(char *player_name) { int len_player_name = strlen(player_name); buffer[1] = OP_PLAYER_NAME; memcpy(&buffer[2], player_name, len_player_name); SendBufferToServer(2 + len_player_name); Error(ERR_NETWORK_CLIENT, "you set your player name to \"%s\"", player_name); } void SendToServer_ProtocolVersion() { buffer[1] = OP_PROTOCOL_VERSION; buffer[2] = PROTOCOL_VERSION_1; buffer[3] = PROTOCOL_VERSION_2; buffer[4] = PROTOCOL_VERSION_3; SendBufferToServer(5); } void SendToServer_NrWanted(int nr_wanted) { buffer[1] = OP_NUMBER_WANTED; buffer[2] = nr_wanted; SendBufferToServer(3); } void SendToServer_StartPlaying() { unsigned long new_random_seed = InitRND(level.random_seed); int dummy = 0; /* !!! HAS NO MEANING ANYMORE !!! */ /* the name of the level must be enough */ buffer[1] = OP_START_PLAYING; buffer[2] = (byte)(level_nr >> 8); buffer[3] = (byte)(level_nr & 0xff); buffer[4] = (byte)(dummy >> 8); buffer[5] = (byte)(dummy & 0xff); buffer[6] = (unsigned char)((new_random_seed >> 24) & 0xff); buffer[7] = (unsigned char)((new_random_seed >> 16) & 0xff); buffer[8] = (unsigned char)((new_random_seed >> 8) & 0xff); buffer[9] = (unsigned char)((new_random_seed >> 0) & 0xff); strcpy((char *)&buffer[10], leveldir_current->identifier); SendBufferToServer(10 + strlen(leveldir_current->identifier) + 1); } void SendToServer_PausePlaying() { buffer[1] = OP_PAUSE_PLAYING; SendBufferToServer(2); } void SendToServer_ContinuePlaying() { buffer[1] = OP_CONTINUE_PLAYING; SendBufferToServer(2); } void SendToServer_StopPlaying(int cause_for_stopping) { buffer[1] = OP_STOP_PLAYING; buffer[2] = cause_for_stopping; SendBufferToServer(3); } void SendToServer_MovePlayer(byte player_action) { buffer[1] = OP_MOVE_PLAYER; buffer[2] = player_action; SendBufferToServer(3); } static void Handle_OP_BAD_PROTOCOL_VERSION() { Error(ERR_WARN, "protocol version mismatch"); Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d", buffer[2], buffer[3], PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3); } static void Handle_OP_YOUR_NUMBER() { int new_client_nr = buffer[2]; int new_index_nr = new_client_nr - 1; struct PlayerInfo *old_local_player = local_player; struct PlayerInfo *new_local_player = &stored_player[new_index_nr]; printf("OP_YOUR_NUMBER: %d\n", buffer[0]); first_player.nr = new_client_nr; if (old_local_player != new_local_player) { /* copy existing player settings and change to new player */ *new_local_player = *old_local_player; old_local_player->connected = FALSE; local_player = new_local_player; } if (first_player.nr > MAX_PLAYERS) Error(ERR_EXIT, "sorry, more than %d players not allowed", MAX_PLAYERS); Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr); } static void Handle_OP_NUMBER_WANTED() { int client_nr_wanted = buffer[2]; int old_client_nr = buffer[0]; int new_client_nr = buffer[3]; int old_index_nr = old_client_nr - 1; int new_index_nr = new_client_nr - 1; int index_nr_wanted = client_nr_wanted - 1; struct PlayerInfo *old_player = &stored_player[old_index_nr]; struct PlayerInfo *new_player = &stored_player[new_index_nr]; printf("OP_NUMBER_WANTED: %d\n", buffer[0]); if (new_client_nr == client_nr_wanted) /* switching succeeded */ { struct NetworkClientPlayerInfo *player; if (old_client_nr != client_nr_wanted) /* client's nr has changed */ Error(ERR_NETWORK_CLIENT, "client %d switches to # %d", old_client_nr, new_client_nr); else if (old_client_nr == first_player.nr) /* local player keeps his nr */ Error(ERR_NETWORK_CLIENT, "keeping client # %d", new_client_nr); if (old_client_nr != new_client_nr) { /* copy existing player settings and change to new player */ *new_player = *old_player; old_player->connected = FALSE; } player = getNetworkPlayer(old_client_nr); player->nr = new_client_nr; if (old_player == local_player) /* local player switched */ local_player = new_player; } else if (old_client_nr == first_player.nr) /* failed -- local player? */ { char request[100]; sprintf(request, "Sorry ! Player %d already exists ! You are player %d !", index_nr_wanted + 1, new_index_nr + 1); Request(request, REQ_CONFIRM); Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d", new_client_nr); } } static void Handle_OP_PLAYER_NAME(unsigned int len) { struct NetworkClientPlayerInfo *player; int player_nr = (int)buffer[0]; printf("OP_PLAYER_NAME: %d\n", player_nr); player = getNetworkPlayer(player_nr); buffer[len] = 0; Error(ERR_NETWORK_CLIENT, "client %d calls itself \"%s\"", buffer[0], &buffer[2]); strncpy(player->name, (char *)&buffer[2], MAX_PLAYER_NAME_LEN); } static void Handle_OP_PLAYER_CONNECTED() { struct NetworkClientPlayerInfo *player, *last_player = NULL; int new_client_nr = (int)buffer[0]; int new_index_nr = new_client_nr - 1; printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr); Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr); for (player = &first_player; player; player = player->next) { if (player->nr == new_client_nr) Error(ERR_EXIT, "multiplayer server sent duplicate player id"); last_player = player; } last_player->next = player = checked_malloc(sizeof(struct NetworkClientPlayerInfo)); player->nr = new_client_nr; player->name[0] = '\0'; player->next = NULL; stored_player[new_index_nr].connected = TRUE; } static void Handle_OP_PLAYER_DISCONNECTED() { struct NetworkClientPlayerInfo *player, *player_disconnected; int player_nr = (int)buffer[0]; printf("OP_PLAYER_DISCONNECTED: %d\n", player_nr); player_disconnected = getNetworkPlayer(player_nr); Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected", player_nr, getNetworkPlayerName(buffer[0])); for (player = &first_player; player; player = player->next) if (player->next == player_disconnected) player->next = player_disconnected->next; free(player_disconnected); } static void Handle_OP_START_PLAYING() { LevelDirTree *new_leveldir; int new_level_nr; int dummy; unsigned long new_random_seed; char *new_leveldir_identifier; new_level_nr = (buffer[2] << 8) + buffer[3]; dummy = (buffer[4] << 8) + buffer[5]; /* (obsolete) */ new_random_seed = (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]); new_leveldir_identifier = (char *)&buffer[10]; new_leveldir = getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier); if (new_leveldir == NULL) { Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier); new_leveldir = leveldir_first; Error(ERR_WARN, "using default level set: '%s'", new_leveldir->identifier); } printf("OP_START_PLAYING: %d\n", buffer[0]); Error(ERR_NETWORK_CLIENT, "client %d starts game [level %d from level identifier '%s']\n", buffer[0], new_level_nr, new_leveldir->identifier); leveldir_current = new_leveldir; level_nr = new_level_nr; TapeErase(); LoadTape(level_nr); LoadLevel(level_nr); StartGameActions(FALSE, setup.autorecord, new_random_seed); } static void Handle_OP_PAUSE_PLAYING() { printf("OP_PAUSE_PLAYING: %d\n", buffer[0]); Error(ERR_NETWORK_CLIENT, "client %d pauses game", buffer[0]); tape.pausing = TRUE; DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0); } static void Handle_OP_CONTINUE_PLAYING() { printf("OP_CONTINUE_PLAYING: %d\n", buffer[0]); Error(ERR_NETWORK_CLIENT, "client %d continues game", buffer[0]); tape.pausing = FALSE; DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); } static void Handle_OP_STOP_PLAYING() { printf("OP_STOP_PLAYING: %d [%d]\n", buffer[0], buffer[2]); Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]", buffer[0], buffer[2]); if (game_status == GAME_MODE_PLAYING) { if (buffer[2] == NETWORK_STOP_BY_PLAYER) Request("Network game stopped by player!", REQ_CONFIRM); else if (buffer[2] == NETWORK_STOP_BY_ERROR) Request("Network game stopped due to internal error!", REQ_CONFIRM); else Request("Network game stopped !", REQ_CONFIRM); } game_status = GAME_MODE_MAIN; DrawMainMenu(); } static void Handle_OP_MOVE_PLAYER(unsigned int len) { int server_frame_counter; int i; if (!network_playing) return; server_frame_counter = (buffer[2] << 24) | (buffer[3] << 16) | (buffer[4] << 8) | (buffer[5]); #if 0 Error(ERR_NETWORK_CLIENT, "receiving server frame counter value %d [%d]", server_frame_counter, FrameCounter); #endif if (server_frame_counter != FrameCounter) { Error(ERR_INFO, "client and servers frame counters out of sync"); Error(ERR_INFO, "frame counter of client is %d", FrameCounter); Error(ERR_INFO, "frame counter of server is %d", server_frame_counter); Error(ERR_INFO, "this should not happen -- please debug"); stop_network_game = TRUE; return; } /* copy valid player actions */ for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = (i < len - 6 && stored_player[i].active ? buffer[6 + i] : 0); network_player_action_received = TRUE; } static void HandleNetworkingMessages() { unsigned int message_length; stop_network_game = FALSE; while (nread >= 4 && nread >= 4 + readbuffer[3]) { message_length = readbuffer[3]; if (readbuffer[0] || readbuffer[1] || readbuffer[2]) Error(ERR_EXIT, "wrong network server line length"); memcpy(buffer, &readbuffer[4], message_length); nread -= 4 + message_length; memmove(readbuffer, readbuffer + 4 + message_length, nread); switch (buffer[1]) { case OP_BAD_PROTOCOL_VERSION: Handle_OP_BAD_PROTOCOL_VERSION(); break; case OP_YOUR_NUMBER: Handle_OP_YOUR_NUMBER(); break; case OP_NUMBER_WANTED: Handle_OP_NUMBER_WANTED(); break; case OP_PLAYER_NAME: Handle_OP_PLAYER_NAME(message_length); break; case OP_PLAYER_CONNECTED: Handle_OP_PLAYER_CONNECTED(); break; case OP_PLAYER_DISCONNECTED: Handle_OP_PLAYER_DISCONNECTED(); break; case OP_START_PLAYING: Handle_OP_START_PLAYING(); break; case OP_PAUSE_PLAYING: Handle_OP_PAUSE_PLAYING(); break; case OP_CONTINUE_PLAYING: Handle_OP_CONTINUE_PLAYING(); break; case OP_STOP_PLAYING: Handle_OP_STOP_PLAYING(); break; case OP_MOVE_PLAYER: Handle_OP_MOVE_PLAYER(message_length); break; case OP_BROADCAST_MESSAGE: printf("OP_BROADCAST_MESSAGE: %d\n", buffer[0]); Error(ERR_NETWORK_CLIENT, "client %d sends message", buffer[0]); break; } } fflush(stdout); /* in case of internal error, stop network game */ if (stop_network_game) SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR); } /* TODO */ void HandleNetworking() { #if !defined(TARGET_SDL) static struct timeval tv = { 0, 0 }; fd_set rfds; #endif int r = 0; do { #if defined(TARGET_SDL) if ((r = SDLNet_CheckSockets(rfds, 1)) < 0) Error(ERR_EXIT, "HandleNetworking(): SDLNet_CheckSockets() failed"); #else FD_ZERO(&rfds); FD_SET(sfd, &rfds); r = select(sfd + 1, &rfds, NULL, NULL, &tv); if (r < 0 && errno != EINTR) Error(ERR_EXIT, "HandleNetworking(): select() failed"); if (r < 0) FD_ZERO(&rfds); #endif #if defined(TARGET_SDL) if (r > 0) #else if (FD_ISSET(sfd, &rfds)) #endif { #if defined(TARGET_SDL) r = SDLNet_TCP_Recv(sfd, readbuffer + nread, 1); #else r = read(sfd, readbuffer + nread, MAX_BUFFER_SIZE - nread); #endif if (r < 0) Error(ERR_EXIT, "error reading from network server"); if (r == 0) Error(ERR_EXIT, "connection to network server lost"); nread += r; HandleNetworkingMessages(); } } while (r > 0); } #endif /* PLATFORM_UNIX */ rocksndiamonds-3.3.0.1+dfsg1/src/tape.c0000644000175000017500000010775211362674004016531 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tape.c * ***********************************************************/ #include "libgame/libgame.h" #include "tape.h" #include "init.h" #include "game.h" #include "tools.h" #include "files.h" #include "network.h" #include "cartoons.h" /* tape button identifiers */ #define TAPE_CTRL_ID_EJECT 0 #define TAPE_CTRL_ID_EXTRA 1 #define TAPE_CTRL_ID_STOP 2 #define TAPE_CTRL_ID_PAUSE 3 #define TAPE_CTRL_ID_RECORD 4 #define TAPE_CTRL_ID_PLAY 5 #define NUM_TAPE_BUTTONS 6 /* values for tape handling */ #define TAPE_PAUSE_SECONDS_BEFORE_DEATH 5 /* forward declaration for internal use */ static void HandleTapeButtons(struct GadgetInfo *); static void TapeStopWarpForward(); static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS]; /* ========================================================================= */ /* video tape definitions */ /* ========================================================================= */ /* some positions in the video tape control window */ #define VIDEO_DATE_LABEL_XPOS (VIDEO_DISPLAY1_XPOS) #define VIDEO_DATE_LABEL_YPOS (VIDEO_DISPLAY1_YPOS) #define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE) #define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE) #define VIDEO_DATE_XPOS (VIDEO_DISPLAY1_XPOS + 2) #define VIDEO_DATE_YPOS (VIDEO_DISPLAY1_YPOS + 14) #define VIDEO_DATE_XSIZE (VIDEO_DISPLAY_XSIZE) #define VIDEO_DATE_YSIZE 16 #define VIDEO_REC_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) #define VIDEO_REC_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) #define VIDEO_REC_LABEL_XSIZE 20 #define VIDEO_REC_LABEL_YSIZE 12 #define VIDEO_REC_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 20) #define VIDEO_REC_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) #define VIDEO_REC_SYMBOL_XSIZE 16 #define VIDEO_REC_SYMBOL_YSIZE 16 #define VIDEO_PLAY_LABEL_XPOS (VIDEO_DISPLAY2_XPOS + 65) #define VIDEO_PLAY_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) #define VIDEO_PLAY_LABEL_XSIZE 22 #define VIDEO_PLAY_LABEL_YSIZE 12 #define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 52) #define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) #define VIDEO_PLAY_SYMBOL_XSIZE 11 #define VIDEO_PLAY_SYMBOL_YSIZE 13 #define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) #define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS + 20) #define VIDEO_PAUSE_LABEL_XSIZE 35 #define VIDEO_PAUSE_LABEL_YSIZE 8 #define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 35) #define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) #define VIDEO_PAUSE_SYMBOL_XSIZE 17 #define VIDEO_PAUSE_SYMBOL_YSIZE 13 #define VIDEO_TIME_XPOS (VIDEO_DISPLAY2_XPOS + 39) #define VIDEO_TIME_YPOS (VIDEO_DISPLAY2_YPOS + 14) #define VIDEO_TIME_XSIZE 50 #define VIDEO_TIME_YSIZE 16 /* some default values for tape labels and symbols */ #define VIDEO_LABEL_XPOS 5 #define VIDEO_LABEL_YPOS 42 #define VIDEO_LABEL_XSIZE 40 #define VIDEO_LABEL_YSIZE 28 #define VIDEO_SYMBOL_XPOS 39 #define VIDEO_SYMBOL_YPOS 42 #define VIDEO_SYMBOL_XSIZE 56 #define VIDEO_SYMBOL_YSIZE 13 /* values for certain tape labels and symbols */ #define VIDEO_FFWD_LABEL_XPOS VIDEO_LABEL_XPOS #define VIDEO_FFWD_LABEL_YPOS 193 #define VIDEO_FFWD_LABEL_XSIZE VIDEO_LABEL_XSIZE #define VIDEO_FFWD_LABEL_YSIZE VIDEO_LABEL_YSIZE #define VIDEO_FFWD_SYMBOL_XPOS VIDEO_SYMBOL_XPOS #define VIDEO_FFWD_SYMBOL_YPOS 193 #define VIDEO_FFWD_SYMBOL_XSIZE 27 #define VIDEO_FFWD_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE #define VIDEO_PBEND_LABEL_XPOS VIDEO_LABEL_XPOS #define VIDEO_PBEND_LABEL_YPOS 221 #define VIDEO_PBEND_LABEL_XSIZE VIDEO_LABEL_XSIZE #define VIDEO_PBEND_LABEL_YSIZE VIDEO_LABEL_YSIZE #define VIDEO_PBEND_SYMBOL_XPOS VIDEO_SYMBOL_XPOS #define VIDEO_PBEND_SYMBOL_YPOS 221 #define VIDEO_PBEND_SYMBOL_XSIZE 27 #define VIDEO_PBEND_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE #define VIDEO_WARP_LABEL_XPOS VIDEO_LABEL_XPOS #define VIDEO_WARP_LABEL_YPOS 165 #define VIDEO_WARP_LABEL_XSIZE VIDEO_LABEL_XSIZE #define VIDEO_WARP_LABEL_YSIZE VIDEO_LABEL_YSIZE #define VIDEO_WARP_SYMBOL_XPOS VIDEO_SYMBOL_XPOS #define VIDEO_WARP_SYMBOL_YPOS 165 #define VIDEO_WARP_SYMBOL_XSIZE 27 #define VIDEO_WARP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE #define VIDEO_WARP2_SYMBOL_XPOS VIDEO_SYMBOL_XPOS #define VIDEO_WARP2_SYMBOL_YPOS 152 #define VIDEO_WARP2_SYMBOL_XSIZE 27 #define VIDEO_WARP2_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE #define VIDEO_1STEP_SYMBOL_XPOS (VIDEO_SYMBOL_XPOS + 18) #define VIDEO_1STEP_SYMBOL_YPOS 139 #define VIDEO_1STEP_SYMBOL_XSIZE (VIDEO_SYMBOL_XSIZE - 18) #define VIDEO_1STEP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE #define PG_X3(x) (DOOR_GFX_PAGEX3 + (x)) #define PG_X4(x) (DOOR_GFX_PAGEX4 + (x)) #define PG_X5(x) (DOOR_GFX_PAGEX5 + (x)) #define PG_X6(x) (DOOR_GFX_PAGEX6 + (x)) #define PG_Y1(y) (DOOR_GFX_PAGEY1 + (y)) #define PG_Y2(y) (DOOR_GFX_PAGEY2 + (y)) #define VIDEO_INFO_OFF (VIDEO_STATE_DATE_OFF | \ VIDEO_STATE_TIME_OFF) #define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \ VIDEO_STATE_REC_OFF | \ VIDEO_STATE_PAUSE_OFF | \ VIDEO_STATE_FFWD_OFF | \ VIDEO_STATE_PBEND_OFF | \ VIDEO_STATE_1STEP_OFF) #define VIDEO_PRESS_OFF (VIDEO_PRESS_PLAY_OFF | \ VIDEO_PRESS_REC_OFF | \ VIDEO_PRESS_PAUSE_OFF | \ VIDEO_PRESS_STOP_OFF | \ VIDEO_PRESS_EJECT_OFF) #define VIDEO_ALL_OFF (VIDEO_INFO_OFF | \ VIDEO_STATE_OFF | \ VIDEO_PRESS_OFF) #define VIDEO_INFO_ON (VIDEO_STATE_DATE_ON | \ VIDEO_STATE_TIME_ON) #define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \ VIDEO_STATE_REC_ON | \ VIDEO_STATE_PAUSE_ON | \ VIDEO_STATE_FFWD_ON | \ VIDEO_STATE_PBEND_ON | \ VIDEO_STATE_1STEP_ON) #define VIDEO_PRESS_ON (VIDEO_PRESS_PLAY_ON | \ VIDEO_PRESS_REC_ON | \ VIDEO_PRESS_PAUSE_ON | \ VIDEO_PRESS_STOP_ON | \ VIDEO_PRESS_EJECT_ON) #define VIDEO_ALL_ON (VIDEO_INFO_ON | \ VIDEO_STATE_ON | \ VIDEO_PRESS_ON) #define VIDEO_INFO (VIDEO_INFO_ON | VIDEO_INFO_OFF) #define VIDEO_STATE (VIDEO_STATE_ON | VIDEO_STATE_OFF) #define VIDEO_PRESS (VIDEO_PRESS_ON | VIDEO_PRESS_OFF) #define VIDEO_ALL (VIDEO_ALL_ON | VIDEO_ALL_OFF) #define NUM_TAPE_FUNCTIONS 10 #define NUM_TAPE_FUNCTION_PARTS 2 #define NUM_TAPE_FUNCTION_STATES 2 /* ========================================================================= */ /* video display functions */ /* ========================================================================= */ void DrawVideoDisplay(unsigned long state, unsigned long value) { int i, j, k; static char *monatsname[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; static struct { int gd_x1, gd_y1; int gd_x2, gd_y2; int x, y; int width, height; } video_pos[NUM_TAPE_FUNCTIONS][NUM_TAPE_FUNCTION_PARTS] = { { { PG_X4(VIDEO_PLAY_LABEL_XPOS), PG_Y2(VIDEO_PLAY_LABEL_YPOS), PG_X3(VIDEO_PLAY_LABEL_XPOS), PG_Y2(VIDEO_PLAY_LABEL_YPOS), VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS, VIDEO_PLAY_LABEL_XSIZE, VIDEO_PLAY_LABEL_YSIZE }, { PG_X4(VIDEO_PLAY_SYMBOL_XPOS), PG_Y2(VIDEO_PLAY_SYMBOL_YPOS), PG_X3(VIDEO_PLAY_SYMBOL_XPOS), PG_Y2(VIDEO_PLAY_SYMBOL_YPOS), VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS, VIDEO_PLAY_SYMBOL_XSIZE, VIDEO_PLAY_SYMBOL_YSIZE } }, { { PG_X4(VIDEO_REC_LABEL_XPOS), PG_Y2(VIDEO_REC_LABEL_YPOS), PG_X3(VIDEO_REC_LABEL_XPOS), PG_Y2(VIDEO_REC_LABEL_YPOS), VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS, VIDEO_REC_LABEL_XSIZE, VIDEO_REC_LABEL_YSIZE }, { PG_X4(VIDEO_REC_SYMBOL_XPOS), PG_Y2(VIDEO_REC_SYMBOL_YPOS), PG_X3(VIDEO_REC_SYMBOL_XPOS), PG_Y2(VIDEO_REC_SYMBOL_YPOS), VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS, VIDEO_REC_SYMBOL_XSIZE, VIDEO_REC_SYMBOL_YSIZE } }, { { PG_X4(VIDEO_PAUSE_LABEL_XPOS), PG_Y2(VIDEO_PAUSE_LABEL_YPOS), PG_X3(VIDEO_PAUSE_LABEL_XPOS), PG_Y2(VIDEO_PAUSE_LABEL_YPOS), VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS, VIDEO_PAUSE_LABEL_XSIZE, VIDEO_PAUSE_LABEL_YSIZE }, { PG_X4(VIDEO_PAUSE_SYMBOL_XPOS), PG_Y2(VIDEO_PAUSE_SYMBOL_YPOS), PG_X3(VIDEO_PAUSE_SYMBOL_XPOS), PG_Y2(VIDEO_PAUSE_SYMBOL_YPOS), VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS, VIDEO_PAUSE_SYMBOL_XSIZE, VIDEO_PAUSE_SYMBOL_YSIZE } }, { { PG_X4(VIDEO_DATE_LABEL_XPOS), PG_Y2(VIDEO_DATE_LABEL_YPOS), PG_X3(VIDEO_DATE_LABEL_XPOS), PG_Y2(VIDEO_DATE_LABEL_YPOS), VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS, VIDEO_DATE_LABEL_XSIZE, VIDEO_DATE_LABEL_YSIZE }, { PG_X4(VIDEO_DATE_XPOS), PG_Y2(VIDEO_DATE_YPOS), PG_X3(VIDEO_DATE_XPOS), PG_Y2(VIDEO_DATE_YPOS), VIDEO_DATE_XPOS, VIDEO_DATE_YPOS, VIDEO_DATE_XSIZE, VIDEO_DATE_YSIZE } }, { { -1, -1, -1, -1, -1, -1, -1, -1 }, { PG_X4(VIDEO_TIME_XPOS), PG_Y2(VIDEO_TIME_YPOS), PG_X3(VIDEO_TIME_XPOS), PG_Y2(VIDEO_TIME_YPOS), VIDEO_TIME_XPOS, VIDEO_TIME_YPOS, VIDEO_TIME_XSIZE, VIDEO_TIME_YSIZE } }, { { PG_X6(VIDEO_FFWD_LABEL_XPOS), PG_Y1(VIDEO_FFWD_LABEL_YPOS), PG_X3(VIDEO_LABEL_XPOS), PG_Y2(VIDEO_LABEL_YPOS), VIDEO_LABEL_XPOS, VIDEO_LABEL_YPOS, VIDEO_LABEL_XSIZE, VIDEO_LABEL_YSIZE }, { PG_X6(VIDEO_FFWD_SYMBOL_XPOS), PG_Y1(VIDEO_FFWD_SYMBOL_YPOS), PG_X3(VIDEO_FFWD_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS), VIDEO_SYMBOL_XPOS, VIDEO_SYMBOL_YPOS, VIDEO_FFWD_SYMBOL_XSIZE, VIDEO_FFWD_SYMBOL_YSIZE } }, { { PG_X6(VIDEO_PBEND_LABEL_XPOS), PG_Y1(VIDEO_PBEND_LABEL_YPOS), PG_X3(VIDEO_LABEL_XPOS), PG_Y2(VIDEO_LABEL_YPOS), VIDEO_LABEL_XPOS, VIDEO_LABEL_YPOS, VIDEO_LABEL_XSIZE, VIDEO_LABEL_YSIZE }, { PG_X6(VIDEO_PBEND_SYMBOL_XPOS), PG_Y1(VIDEO_PBEND_SYMBOL_YPOS), PG_X3(VIDEO_PBEND_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS), VIDEO_SYMBOL_XPOS, VIDEO_SYMBOL_YPOS, VIDEO_PBEND_SYMBOL_XSIZE, VIDEO_PBEND_SYMBOL_YSIZE } }, { { PG_X6(VIDEO_WARP_LABEL_XPOS), PG_Y1(VIDEO_WARP_LABEL_YPOS), PG_X3(VIDEO_LABEL_XPOS), PG_Y2(VIDEO_LABEL_YPOS), VIDEO_LABEL_XPOS, VIDEO_LABEL_YPOS, VIDEO_LABEL_XSIZE, VIDEO_LABEL_YSIZE }, { PG_X6(VIDEO_WARP_SYMBOL_XPOS), PG_Y1(VIDEO_WARP_SYMBOL_YPOS), PG_X3(VIDEO_WARP_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS), VIDEO_SYMBOL_XPOS, VIDEO_SYMBOL_YPOS, VIDEO_WARP_SYMBOL_XSIZE, VIDEO_WARP_SYMBOL_YSIZE } }, { { -1, -1, -1, -1, -1, -1, -1, -1 }, { PG_X6(VIDEO_WARP2_SYMBOL_XPOS), PG_Y1(VIDEO_WARP2_SYMBOL_YPOS), PG_X3(VIDEO_WARP2_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS), VIDEO_SYMBOL_XPOS, VIDEO_SYMBOL_YPOS, VIDEO_WARP2_SYMBOL_XSIZE, VIDEO_WARP2_SYMBOL_YSIZE } }, { { -1, -1, -1, -1, -1, -1, -1, -1 }, { PG_X6(VIDEO_1STEP_SYMBOL_XPOS), PG_Y1(VIDEO_1STEP_SYMBOL_YPOS), PG_X3(VIDEO_1STEP_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS), VIDEO_1STEP_SYMBOL_XPOS, VIDEO_SYMBOL_YPOS, VIDEO_1STEP_SYMBOL_XSIZE, VIDEO_1STEP_SYMBOL_YSIZE } }, }; for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++) /* on or off states */ { for (i = 0; i < NUM_TAPE_FUNCTIONS; i++) /* record, play, ... */ { for (j = 0; j < NUM_TAPE_FUNCTION_PARTS; j++) /* label or symbol */ { if (state & (1 << (i * 2 + k))) { int gd_x, gd_y; int skip_value = (j == 0 ? VIDEO_DISPLAY_SYMBOL_ONLY : VIDEO_DISPLAY_LABEL_ONLY); if (k == 1) /* on */ { gd_x = video_pos[i][j].gd_x1; gd_y = video_pos[i][j].gd_y1; } else /* off */ { gd_x = video_pos[i][j].gd_x2; gd_y = video_pos[i][j].gd_y2; } if (video_pos[i][j].x != -1 && value != skip_value) BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, gd_x, gd_y, video_pos[i][j].width, video_pos[i][j].height, VX + video_pos[i][j].x, VY + video_pos[i][j].y); } } } } if (state & VIDEO_STATE_DATE_ON) { int tag = value % 100; int monat = (value/100) % 100; int jahr = (value/10000); DrawText(VX + VIDEO_DATE_XPOS, VY + VIDEO_DATE_YPOS, int2str(tag, 2), FONT_TAPE_RECORDER); DrawText(VX + VIDEO_DATE_XPOS + 27, VY + VIDEO_DATE_YPOS, monatsname[monat], FONT_TAPE_RECORDER); DrawText(VX + VIDEO_DATE_XPOS + 64, VY + VIDEO_DATE_YPOS, int2str(jahr, 2), FONT_TAPE_RECORDER); } if (state & VIDEO_STATE_TIME_ON) { int min = value / 60; int sec = value % 60; DrawText(VX + VIDEO_TIME_XPOS, VY + VIDEO_TIME_YPOS, int2str(min, 2), FONT_TAPE_RECORDER); DrawText(VX + VIDEO_TIME_XPOS + 27, VY + VIDEO_TIME_YPOS, int2str(sec, 2), FONT_TAPE_RECORDER); } redraw_mask |= REDRAW_DOOR_2; } void DrawCompleteVideoDisplay() { #if 0 printf("::: %d, %d / %d, %d [%d] [%d, %d] [%d/%d]\n", VX, VY, EX, EY, game_status, gfx.vx, gfx.vy, tape.date, tape.length); #endif BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX3, DOOR_GFX_PAGEY2, gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy); BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX4 + VIDEO_CONTROL_XPOS, DOOR_GFX_PAGEY2 + VIDEO_CONTROL_YPOS, VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE, gfx.vx + VIDEO_CONTROL_XPOS, gfx.vy + VIDEO_CONTROL_YPOS); DrawVideoDisplay(VIDEO_ALL_OFF, 0); #if 1 if (tape.recording) { DrawVideoDisplay(VIDEO_STATE_REC_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); if (tape.pausing) DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0); } else if (tape.playing) { DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); if (tape.pausing) DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0); } else if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); } #else if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); } #endif BlitBitmap(drawto, bitmap_db_door, gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2); } void TapeDeactivateDisplayOn() { SetDrawDeactivationMask(REDRAW_FIELD); audio.sound_deactivated = TRUE; } void TapeDeactivateDisplayOff(boolean redraw_display) { SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; if (redraw_display) { RedrawPlayfield(TRUE, 0,0,0,0); DrawGameDoorValues(); } } /* ========================================================================= */ /* tape control functions */ /* ========================================================================= */ void TapeSetDateFromEpochSeconds(time_t epoch_seconds) { struct tm *lt = localtime(&epoch_seconds); tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday; } void TapeSetDateFromNow() { TapeSetDateFromEpochSeconds(time(NULL)); } void TapeErase() { int i; tape.counter = 0; tape.length = 0; tape.length_seconds = 0; if (leveldir_current) setString(&tape.level_identifier, leveldir_current->identifier); tape.level_nr = level_nr; tape.pos[tape.counter].delay = 0; tape.changed = TRUE; tape.random_seed = InitRND(level.random_seed); tape.file_version = FILE_VERSION_ACTUAL; tape.game_version = GAME_VERSION_ACTUAL; tape.engine_version = level.game_version; TapeSetDateFromNow(); for (i = 0; i < MAX_PLAYERS; i++) tape.player_participates[i] = FALSE; tape.centered_player_nr_next = -1; tape.set_centered_player = FALSE; } static void TapeRewind() { tape.counter = 0; tape.delay_played = 0; tape.pause_before_death = FALSE; tape.recording = FALSE; tape.playing = FALSE; tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.deactivate_display = FALSE; tape.auto_play = (global.autoplay_leveldir != NULL); tape.auto_play_level_solved = FALSE; tape.quick_resume = FALSE; tape.single_step = FALSE; tape.centered_player_nr_next = -1; tape.set_centered_player = FALSE; InitRND(tape.random_seed); } static void TapeSetRandomSeed(long random_seed) { tape.random_seed = InitRND(random_seed); } void TapeStartRecording(long random_seed) { if (!TAPE_IS_STOPPED(tape)) TapeStop(); TapeErase(); TapeRewind(); TapeSetRandomSeed(random_seed); tape.recording = TRUE; DrawVideoDisplay(VIDEO_STATE_REC_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); MapTapeWarpButton(); SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; } static void TapeStartGameRecording() { TapeStartRecording(level.random_seed); #if defined(NETWORK_AVALIABLE) if (options.network) { SendToServer_StartPlaying(); return; } #endif InitGame(); } static void TapeAppendRecording() { if (!tape.playing || !tape.pausing) return; tape.pos[tape.counter].delay = tape.delay_played; tape.playing = FALSE; tape.recording = TRUE; tape.changed = TRUE; TapeSetDateFromNow(); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0); #if 1 UpdateAndDisplayGameControlValues(); #endif } void TapeHaltRecording() { if (!tape.recording) return; tape.counter++; tape.pos[tape.counter].delay = 0; tape.length = tape.counter; tape.length_seconds = GetTapeLength(); } void TapeStopRecording() { TapeHaltRecording(); tape.recording = FALSE; tape.pausing = FALSE; DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0); MapTapeEjectButton(); } void TapeRecordAction(byte action_raw[MAX_PLAYERS]) { byte action[MAX_PLAYERS]; int i; if (!tape.recording) /* (record action even when tape is paused) */ return; if (tape.counter >= MAX_TAPE_LEN - 1) { TapeStopRecording(); return; } for (i = 0; i < MAX_PLAYERS; i++) action[i] = action_raw[i]; if (tape.set_centered_player) { for (i = 0; i < MAX_PLAYERS; i++) if (tape.centered_player_nr_next == i || tape.centered_player_nr_next == -1) action[i] |= KEY_SET_FOCUS; tape.set_centered_player = FALSE; } if (tape.pos[tape.counter].delay > 0) /* already stored action */ { boolean changed_events = FALSE; for (i = 0; i < MAX_PLAYERS; i++) if (tape.pos[tape.counter].action[i] != action[i]) changed_events = TRUE; if (changed_events || tape.pos[tape.counter].delay >= 255) { tape.counter++; tape.pos[tape.counter].delay = 0; } else tape.pos[tape.counter].delay++; } if (tape.pos[tape.counter].delay == 0) /* store new action */ { for (i = 0; i < MAX_PLAYERS; i++) tape.pos[tape.counter].action[i] = action[i]; tape.pos[tape.counter].delay++; } } void TapeTogglePause(boolean toggle_manual) { int state = 0; if (tape.pause_before_death) state |= VIDEO_STATE_PBEND_OFF; else if (tape.fast_forward) state |= VIDEO_STATE_FFWD_OFF; tape.pausing = !tape.pausing; tape.fast_forward = FALSE; tape.pause_before_death = FALSE; if (tape.single_step && toggle_manual) tape.single_step = FALSE; state |= (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF); if (tape.playing) state |= VIDEO_STATE_PLAY_ON; else state |= (tape.single_step ? VIDEO_STATE_1STEP_ON : VIDEO_STATE_1STEP_OFF); DrawVideoDisplay(state, 0); if (tape.warp_forward) { TapeStopWarpForward(); if (tape.quick_resume) { tape.quick_resume = FALSE; TapeAppendRecording(); if (!CheckEngineSnapshot()) SaveEngineSnapshot(); } } } void TapeStartPlaying() { if (TAPE_IS_EMPTY(tape)) return; if (!TAPE_IS_STOPPED(tape)) TapeStop(); TapeRewind(); tape.playing = TRUE; DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); MapTapeWarpButton(); SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; } static void TapeStartGamePlaying() { TapeStartPlaying(); InitGame(); } void TapeStopPlaying() { tape.playing = FALSE; tape.pausing = FALSE; if (tape.warp_forward) TapeStopWarpForward(); DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0); MapTapeEjectButton(); } byte *TapePlayAction() { static byte action[MAX_PLAYERS]; int i; if (!tape.playing || tape.pausing) return NULL; if (tape.pause_before_death) /* stop 10 seconds before player gets killed */ { if (!(FrameCounter % 20)) { if ((FrameCounter / 20) % 2) DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY); else DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY); } if (tape.warp_forward) { if (tape.deactivate_display) DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY); else DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY); } if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH) { TapeTogglePause(TAPE_TOGGLE_MANUAL); return NULL; } } else if (tape.fast_forward) { if ((FrameCounter / 20) % 2) DrawVideoDisplay(VIDEO_STATE_FFWD_ON, VIDEO_DISPLAY_LABEL_ONLY); else DrawVideoDisplay(VIDEO_STATE_FFWD_OFF, VIDEO_DISPLAY_LABEL_ONLY); if (tape.warp_forward) { if (tape.deactivate_display) DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY); else DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY); } } #if 0 /* !!! this makes things much slower !!! */ else if (tape.warp_forward) { if ((FrameCounter / 20) % 2) DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_LABEL_ONLY); else DrawVideoDisplay(VIDEO_STATE_WARP_OFF, VIDEO_DISPLAY_LABEL_ONLY); DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY); } #endif if (tape.counter >= tape.length) /* end of tape reached */ { if (tape.warp_forward && !tape.auto_play) TapeTogglePause(TAPE_TOGGLE_MANUAL); else TapeStop(); return NULL; } for (i = 0; i < MAX_PLAYERS; i++) action[i] = tape.pos[tape.counter].action[i]; tape.set_centered_player = FALSE; tape.centered_player_nr_next = -999; for (i = 0; i < MAX_PLAYERS; i++) { if (action[i] & KEY_SET_FOCUS) { tape.set_centered_player = TRUE; tape.centered_player_nr_next = (tape.centered_player_nr_next == -999 ? i : -1); } action[i] &= ~KEY_SET_FOCUS; } tape.delay_played++; if (tape.delay_played >= tape.pos[tape.counter].delay) { tape.counter++; tape.delay_played = 0; } return action; } void TapeStop() { TapeStopRecording(); TapeStopPlaying(); DrawVideoDisplay(VIDEO_STATE_OFF, 0); if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); } } unsigned int GetTapeLength() { unsigned int tape_length = 0; int i; if (TAPE_IS_EMPTY(tape)) return(0); for (i = 0; i < tape.length; i++) tape_length += tape.pos[i].delay; return(tape_length * GAME_FRAME_DELAY / 1000); } static void TapeStartWarpForward() { tape.warp_forward = TRUE; if (!tape.fast_forward && !tape.pause_before_death) { tape.pausing = FALSE; tape.deactivate_display = TRUE; TapeDeactivateDisplayOn(); } if (tape.fast_forward || tape.pause_before_death) DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY); else DrawVideoDisplay(VIDEO_STATE_WARP_ON, 0); } static void TapeStopWarpForward() { int state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF); tape.warp_forward = FALSE; tape.deactivate_display = FALSE; TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING); if (tape.pause_before_death) state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON; else if (tape.fast_forward) state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON; else state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON; DrawVideoDisplay(state, 0); } static void TapeSingleStep() { if (options.network) return; if (!tape.pausing) TapeTogglePause(TAPE_TOGGLE_MANUAL); tape.single_step = !tape.single_step; DrawVideoDisplay((tape.single_step ? VIDEO_STATE_1STEP_ON : VIDEO_STATE_1STEP_OFF), 0); } void TapeQuickSave() { if (game_status == GAME_MODE_MAIN) { Request("No game that can be saved !", REQ_CONFIRM); return; } if (game_status != GAME_MODE_PLAYING) return; if (tape.recording) TapeHaltRecording(); /* prepare tape for saving on-the-fly */ if (TAPE_IS_EMPTY(tape)) { Request("No tape that can be saved !", REQ_CONFIRM); return; } if (SaveTapeChecked(tape.level_nr)) SaveEngineSnapshot(); } void TapeQuickLoad() { char *filename = getTapeFilename(level_nr); if (!fileExists(filename)) { Request("No tape for this level !", REQ_CONFIRM); return; } if (tape.recording && !Request("Stop recording and load tape ?", REQ_ASK | REQ_STAY_CLOSED)) { OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); return; } if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN) return; if (CheckEngineSnapshot()) { TapeStartGamePlaying(); LoadEngineSnapshot(); DrawCompleteVideoDisplay(); tape.playing = TRUE; tape.pausing = TRUE; TapeStopWarpForward(); TapeAppendRecording(); if (FrameCounter > 0) return; } TapeStop(); TapeErase(); LoadTape(level_nr); if (!TAPE_IS_EMPTY(tape)) { TapeStartGamePlaying(); TapeStartWarpForward(); tape.quick_resume = TRUE; } else /* this should not happen (basically checked above) */ { int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0); Request("No tape for this level !", REQ_CONFIRM | reopen_door); } } void InsertSolutionTape() { if (!TAPE_IS_EMPTY(tape)) return; LoadSolutionTape(level_nr); if (TAPE_IS_EMPTY(tape)) Request("No solution tape for this level !", REQ_CONFIRM); DrawCompleteVideoDisplay(); } /* ------------------------------------------------------------------------- * * tape autoplay functions * ------------------------------------------------------------------------- */ void AutoPlayTape() { static LevelDirTree *autoplay_leveldir = NULL; static boolean autoplay_initialized = FALSE; static int autoplay_level_nr = -1; static int num_levels_played = 0; static int num_levels_solved = 0; static int num_tape_missing = 0; static boolean level_failed[MAX_TAPES_PER_SET]; static boolean tape_missing[MAX_TAPES_PER_SET]; int i; if (autoplay_initialized) { /* just finished auto-playing tape */ printf("%s.\n", tape.auto_play_level_solved ? "solved" : "NOT SOLVED"); num_levels_played++; if (tape.auto_play_level_solved) num_levels_solved++; else if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET) level_failed[level_nr] = TRUE; } else { DrawCompleteVideoDisplay(); audio.sound_enabled = FALSE; autoplay_leveldir = getTreeInfoFromIdentifier(leveldir_first, global.autoplay_leveldir); if (autoplay_leveldir == NULL) Error(ERR_EXIT, "no such level identifier: '%s'", global.autoplay_leveldir); leveldir_current = autoplay_leveldir; if (autoplay_leveldir->first_level < 0) autoplay_leveldir->first_level = 0; if (autoplay_leveldir->last_level >= MAX_TAPES_PER_SET) autoplay_leveldir->last_level = MAX_TAPES_PER_SET - 1; autoplay_level_nr = autoplay_leveldir->first_level; printf_line("=", 79); printf("Automatically playing level tapes\n"); printf_line("-", 79); printf("Level series identifier: '%s'\n", autoplay_leveldir->identifier); printf("Level series name: '%s'\n", autoplay_leveldir->name); printf("Level series author: '%s'\n", autoplay_leveldir->author); printf("Number of levels: %d\n", autoplay_leveldir->levels); printf_line("=", 79); printf("\n"); for (i = 0; i < MAX_TAPES_PER_SET; i++) { level_failed[i] = FALSE; tape_missing[i] = FALSE; } autoplay_initialized = TRUE; } while (autoplay_level_nr <= autoplay_leveldir->last_level) { level_nr = autoplay_level_nr++; if (!global.autoplay_all && !global.autoplay_level[level_nr]) continue; TapeErase(); printf("Level %03d: ", level_nr); LoadLevel(level_nr); if (level.no_valid_file) { printf("(no level)\n"); continue; } #if 0 /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */ printf("(only testing level)\n"); continue; #endif LoadSolutionTape(level_nr); if (tape.no_valid_file) { num_tape_missing++; if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET) tape_missing[level_nr] = TRUE; printf("(no tape)\n"); continue; } printf("playing tape ... "); TapeStartGamePlaying(); TapeStartWarpForward(); return; } printf("\n"); printf_line("=", 79); printf("Number of levels played: %d\n", num_levels_played); printf("Number of levels solved: %d (%d%%)\n", num_levels_solved, (num_levels_played ? num_levels_solved * 100 / num_levels_played :0)); printf_line("-", 79); printf("Summary (for automatic parsing by scripts):\n"); printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)", autoplay_leveldir->identifier, num_levels_solved, num_levels_played, (num_levels_played ? num_levels_solved * 100 / num_levels_played :0)); if (num_levels_played != num_levels_solved) { printf(", FAILED:"); for (i = 0; i < MAX_TAPES_PER_SET; i++) if (level_failed[i]) printf(" %03d", i); } #if 0 if (num_tape_missing > 0) { printf(", NO TAPE:"); for (i = 0; i < MAX_TAPES_PER_SET; i++) if (tape_missing[i]) printf(" %03d", i); } #endif printf("\n"); printf_line("=", 79); CloseAllAndExit(0); } /* ---------- new tape button stuff ---------------------------------------- */ /* graphic position values for tape buttons */ #define TAPE_BUTTON_XSIZE 18 #define TAPE_BUTTON_YSIZE 18 #define TAPE_BUTTON_XPOS 5 #define TAPE_BUTTON_YPOS 77 #define TAPE_BUTTON_EJECT_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE) #define TAPE_BUTTON_EXTRA_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE) #define TAPE_BUTTON_STOP_XPOS (TAPE_BUTTON_XPOS + 1 * TAPE_BUTTON_XSIZE) #define TAPE_BUTTON_PAUSE_XPOS (TAPE_BUTTON_XPOS + 2 * TAPE_BUTTON_XSIZE) #define TAPE_BUTTON_RECORD_XPOS (TAPE_BUTTON_XPOS + 3 * TAPE_BUTTON_XSIZE) #define TAPE_BUTTON_PLAY_XPOS (TAPE_BUTTON_XPOS + 4 * TAPE_BUTTON_XSIZE) static struct { int x, y; int gadget_id; char *infotext; } tapebutton_info[NUM_TAPE_BUTTONS] = { { TAPE_BUTTON_EJECT_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_EJECT, "eject tape" }, { TAPE_BUTTON_EXTRA_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_EXTRA, "extra functions" }, { TAPE_BUTTON_STOP_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_STOP, "stop tape" }, { TAPE_BUTTON_PAUSE_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_PAUSE, "pause tape" }, { TAPE_BUTTON_RECORD_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_RECORD, "record tape" }, { TAPE_BUTTON_PLAY_XPOS, TAPE_BUTTON_YPOS, TAPE_CTRL_ID_PLAY, "play tape" } }; void CreateTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y; int id = i; gd_xoffset = tapebutton_info[i].x; gd_yoffset = tapebutton_info[i].y; gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset; gd_y = DOOR_GFX_PAGEY2 + gd_yoffset; if (i == TAPE_CTRL_ID_EXTRA) { gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, tapebutton_info[i].infotext, GDI_X, VX + gd_xoffset, GDI_Y, VY + gd_yoffset, GDI_WIDTH, TAPE_BUTTON_XSIZE, GDI_HEIGHT, TAPE_BUTTON_YSIZE, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, GD_EVENT_RELEASED, GDI_CALLBACK_ACTION, HandleTapeButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); tape_gadget[id] = gi; } } void FreeTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) FreeGadget(tape_gadget[i]); } void MapTapeEjectButton() { UnmapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]); MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]); } void MapTapeWarpButton() { UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]); MapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]); } void MapTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) if (i != TAPE_CTRL_ID_EXTRA) MapGadget(tape_gadget[i]); if (tape.recording || tape.playing) MapTapeWarpButton(); } void UnmapTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) UnmapGadget(tape_gadget[i]); } static void HandleTapeButtonsExt(int id) { if (game_status != GAME_MODE_MAIN && game_status != GAME_MODE_PLAYING) return; switch (id) { case TAPE_CTRL_ID_EJECT: TapeStop(); if (TAPE_IS_EMPTY(tape)) { LoadTape(level_nr); if (TAPE_IS_EMPTY(tape)) Request("No tape for this level !", REQ_CONFIRM); } else { if (tape.changed) SaveTapeChecked(tape.level_nr); TapeErase(); } DrawCompleteVideoDisplay(); break; case TAPE_CTRL_ID_EXTRA: if (tape.playing) { if (!tape.warp_forward) /* PLAY -> WARP FORWARD PLAY */ { TapeStartWarpForward(); } else /* WARP FORWARD PLAY -> PLAY */ { TapeStopWarpForward(); } } else if (tape.recording) TapeSingleStep(); break; case TAPE_CTRL_ID_STOP: TapeStop(); break; case TAPE_CTRL_ID_PAUSE: TapeTogglePause(TAPE_TOGGLE_MANUAL); break; case TAPE_CTRL_ID_RECORD: if (TAPE_IS_STOPPED(tape)) TapeStartGameRecording(); else if (tape.pausing) { if (tape.playing) /* PLAY -> PAUSE -> RECORD */ TapeAppendRecording(); else TapeTogglePause(TAPE_TOGGLE_MANUAL); } break; case TAPE_CTRL_ID_PLAY: if (TAPE_IS_EMPTY(tape)) break; if (TAPE_IS_STOPPED(tape)) { TapeStartGamePlaying(); } else if (tape.playing) { if (tape.pausing) /* PAUSE -> PLAY */ { TapeTogglePause(TAPE_TOGGLE_MANUAL); } else if (!tape.fast_forward) /* PLAY -> FAST FORWARD PLAY */ { tape.fast_forward = TRUE; DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0); } else if (!tape.pause_before_death) /* FFWD PLAY -> AUTO PAUSE */ { tape.pause_before_death = TRUE; DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_ON, 0); } else /* AUTO PAUSE -> NORMAL PLAY */ { if (tape.warp_forward) TapeStopWarpForward(); tape.fast_forward = FALSE; tape.pause_before_death = FALSE; DrawVideoDisplay(VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PLAY_ON, 0); } } break; default: break; } } static void HandleTapeButtons(struct GadgetInfo *gi) { HandleTapeButtonsExt(gi->custom_id); } void HandleTapeButtonKeys(Key key) { boolean use_extra = (tape.recording || tape.playing); if (key == setup.shortcut.tape_eject) HandleTapeButtonsExt(use_extra ? TAPE_CTRL_ID_EXTRA : TAPE_CTRL_ID_EJECT); else if (key == setup.shortcut.tape_stop) HandleTapeButtonsExt(TAPE_CTRL_ID_STOP); else if (key == setup.shortcut.tape_pause) HandleTapeButtonsExt(TAPE_CTRL_ID_PAUSE); else if (key == setup.shortcut.tape_record) HandleTapeButtonsExt(TAPE_CTRL_ID_RECORD); else if (key == setup.shortcut.tape_play) HandleTapeButtonsExt(TAPE_CTRL_ID_PLAY); } rocksndiamonds-3.3.0.1+dfsg1/src/main.h0000644000175000017500000030646611400010742016516 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * main.h * ***********************************************************/ #ifndef MAIN_H #define MAIN_H #include #include #include #include #include #include #include #include "libgame/libgame.h" #include "game_em/game_em.h" #include "game_sp/game_sp.h" #include "conf_gfx.h" /* include auto-generated data structure definitions */ #include "conf_snd.h" /* include auto-generated data structure definitions */ #include "conf_mus.h" /* include auto-generated data structure definitions */ #define IMG_UNDEFINED (-1) #define IMG_EMPTY IMG_EMPTY_SPACE #define IMG_SP_EMPTY IMG_EMPTY_SPACE #define IMG_SP_EMPTY_SPACE IMG_EMPTY_SPACE #define IMG_EXPLOSION IMG_DEFAULT_EXPLODING #define IMG_CHAR_START IMG_CHAR_SPACE #define IMG_STEEL_CHAR_START IMG_STEEL_CHAR_SPACE #define IMG_CUSTOM_START IMG_CUSTOM_1 #define SND_UNDEFINED (-1) #define MUS_UNDEFINED (-1) #if 0 #define WIN_XSIZE 672 #define WIN_YSIZE 560 #endif #define DEFAULT_FULLSCREEN_MODE "800x600" #if 0 #define SCR_FIELDX 17 #define SCR_FIELDY 17 #endif #define MAX_BUF_XSIZE (SCR_FIELDX + 2) #define MAX_BUF_YSIZE (SCR_FIELDY + 2) #define MIN_LEV_FIELDX 3 #define MIN_LEV_FIELDY 3 #define STD_LEV_FIELDX 64 #define STD_LEV_FIELDY 32 #define MAX_LEV_FIELDX MAX_PLAYFIELD_WIDTH #define MAX_LEV_FIELDY MAX_PLAYFIELD_HEIGHT #define MIN_SCROLL_DELAY 0 #define STD_SCROLL_DELAY 3 #define MAX_SCROLL_DELAY 8 #define SCREENX(a) ((a) - scroll_x) #define SCREENY(a) ((a) - scroll_y) #define LEVELX(a) ((a) + scroll_x) #define LEVELY(a) ((a) + scroll_y) #define IN_FIELD(x, y, xsize, ysize) ((x) >= 0 && (x) < (xsize) && \ (y) >= 0 && (y) < (ysize)) #define IN_FIELD_MINMAX(x, y, xmin, ymin, xmax, ymax) \ ((x) >= (xmin) && (x) <= (xmax) && \ (y) >= (ymin) && (y) <= (ymax)) #define IN_VIS_FIELD(x, y) IN_FIELD(x, y, SCR_FIELDX, SCR_FIELDY) #define IN_LEV_FIELD(x, y) IN_FIELD(x, y, lev_fieldx, lev_fieldy) #define IN_SCR_FIELD(x, y) IN_FIELD_MINMAX(x,y, BX1,BY1, BX2,BY2) /* values for configurable properties (custom elem's only, else pre-defined) */ /* (never change these values, as they are stored in level files!) */ #define EP_DIGGABLE 0 #define EP_COLLECTIBLE_ONLY 1 #define EP_DONT_RUN_INTO 2 #define EP_DONT_COLLIDE_WITH 3 #define EP_DONT_TOUCH 4 #define EP_INDESTRUCTIBLE 5 #define EP_SLIPPERY 6 #define EP_CAN_CHANGE 7 #define EP_CAN_MOVE 8 #define EP_CAN_FALL 9 #define EP_CAN_SMASH_PLAYER 10 #define EP_CAN_SMASH_ENEMIES 11 #define EP_CAN_SMASH_EVERYTHING 12 #define EP_EXPLODES_BY_FIRE 13 #define EP_EXPLODES_SMASHED 14 #define EP_EXPLODES_IMPACT 15 #define EP_WALKABLE_OVER 16 #define EP_WALKABLE_INSIDE 17 #define EP_WALKABLE_UNDER 18 #define EP_PASSABLE_OVER 19 #define EP_PASSABLE_INSIDE 20 #define EP_PASSABLE_UNDER 21 #define EP_DROPPABLE 22 #define EP_EXPLODES_1X1_OLD 23 #define EP_PUSHABLE 24 #define EP_EXPLODES_CROSS_OLD 25 #define EP_PROTECTED 26 #define EP_CAN_MOVE_INTO_ACID 27 #define EP_THROWABLE 28 #define EP_CAN_EXPLODE 29 #define EP_GRAVITY_REACHABLE 30 #define EP_DONT_GET_HIT_BY 31 /* values for pre-defined properties */ /* (from here on, values can be changed by inserting new values) */ #define EP_PLAYER 32 #define EP_CAN_PASS_MAGIC_WALL 33 #define EP_CAN_PASS_DC_MAGIC_WALL 34 #define EP_SWITCHABLE 35 #define EP_BD_ELEMENT 36 #define EP_SP_ELEMENT 37 #define EP_SB_ELEMENT 38 #define EP_GEM 39 #define EP_FOOD_DARK_YAMYAM 40 #define EP_FOOD_PENGUIN 41 #define EP_FOOD_PIG 42 #define EP_HISTORIC_WALL 43 #define EP_HISTORIC_SOLID 44 #define EP_CLASSIC_ENEMY 45 #define EP_BELT 46 #define EP_BELT_ACTIVE 47 #define EP_BELT_SWITCH 48 #define EP_TUBE 49 #define EP_ACID_POOL 50 #define EP_KEYGATE 51 #define EP_AMOEBOID 52 #define EP_AMOEBALIVE 53 #define EP_HAS_EDITOR_CONTENT 54 #define EP_CAN_TURN_EACH_MOVE 55 #define EP_CAN_GROW 56 #define EP_ACTIVE_BOMB 57 #define EP_INACTIVE 58 /* values for special configurable properties (depending on level settings) */ #define EP_EM_SLIPPERY_WALL 59 /* values for special graphics properties (no effect on game engine) */ #define EP_GFX_CRUMBLED 60 /* values for derived properties (determined from properties above) */ #define EP_ACCESSIBLE_OVER 61 #define EP_ACCESSIBLE_INSIDE 62 #define EP_ACCESSIBLE_UNDER 63 #define EP_WALKABLE 64 #define EP_PASSABLE 65 #define EP_ACCESSIBLE 66 #define EP_COLLECTIBLE 67 #define EP_SNAPPABLE 68 #define EP_WALL 69 #define EP_SOLID_FOR_PUSHING 70 #define EP_DRAGONFIRE_PROOF 71 #define EP_EXPLOSION_PROOF 72 #define EP_CAN_SMASH 73 #define EP_EXPLODES_3X3_OLD 74 #define EP_CAN_EXPLODE_BY_FIRE 75 #define EP_CAN_EXPLODE_SMASHED 76 #define EP_CAN_EXPLODE_IMPACT 77 #define EP_SP_PORT 78 #define EP_CAN_EXPLODE_BY_DRAGONFIRE 79 #define EP_CAN_EXPLODE_BY_EXPLOSION 80 #define EP_COULD_MOVE_INTO_ACID 81 #define EP_MAYBE_DONT_COLLIDE_WITH 82 #define EP_CAN_BE_CLONED_BY_ANDROID 83 /* values for internal purpose only (level editor) */ #define EP_WALK_TO_OBJECT 84 #define EP_DEADLY 85 #define EP_EDITOR_CASCADE 86 #define EP_EDITOR_CASCADE_ACTIVE 87 #define EP_EDITOR_CASCADE_INACTIVE 88 /* values for internal purpose only (game engine) */ #define EP_HAS_ACTION 89 #define EP_CAN_CHANGE_OR_HAS_ACTION 90 /* values for internal purpose only (other) */ #define EP_OBSOLETE 91 #define NUM_ELEMENT_PROPERTIES 92 #define NUM_EP_BITFIELDS ((NUM_ELEMENT_PROPERTIES + 31) / 32) #define EP_BITFIELD_BASE_NR 0 #define EP_BITMASK_BASE_DEFAULT (1 << EP_CAN_MOVE_INTO_ACID) #define EP_BITMASK_DEFAULT 0 #define PROPERTY_BIT(p) (1 << ((p) % 32)) #define PROPERTY_VAR(e,p) (element_info[e].properties[(p) / 32]) #define HAS_PROPERTY(e,p) ((PROPERTY_VAR(e, p) & PROPERTY_BIT(p)) != 0) #define SET_PROPERTY(e,p,v) ((v) ? \ (PROPERTY_VAR(e,p) |= PROPERTY_BIT(p)) : \ (PROPERTY_VAR(e,p) &= ~PROPERTY_BIT(p))) /* values for change events for custom elements (stored in level file) */ #define CE_DELAY 0 #define CE_TOUCHED_BY_PLAYER 1 #define CE_PRESSED_BY_PLAYER 2 #define CE_PUSHED_BY_PLAYER 3 #define CE_DROPPED_BY_PLAYER 4 #define CE_HITTING_SOMETHING 5 #define CE_IMPACT 6 #define CE_SMASHED 7 #define CE_TOUCHING_X 8 #define CE_CHANGE_OF_X 9 #define CE_EXPLOSION_OF_X 10 #define CE_PLAYER_TOUCHES_X 11 #define CE_PLAYER_PRESSES_X 12 #define CE_PLAYER_PUSHES_X 13 #define CE_PLAYER_COLLECTS_X 14 #define CE_PLAYER_DROPS_X 15 #define CE_VALUE_GETS_ZERO 16 #define CE_VALUE_GETS_ZERO_OF_X 17 #define CE_BY_OTHER_ACTION 18 #define CE_BY_DIRECT_ACTION 19 #define CE_PLAYER_DIGS_X 20 #define CE_ENTERED_BY_PLAYER 21 #define CE_LEFT_BY_PLAYER 22 #define CE_PLAYER_ENTERS_X 23 #define CE_PLAYER_LEAVES_X 24 #define CE_SWITCHED 25 #define CE_SWITCH_OF_X 26 #define CE_HIT_BY_SOMETHING 27 #define CE_HITTING_X 28 #define CE_HIT_BY_X 29 #define CE_BLOCKED 30 #define CE_SWITCHED_BY_PLAYER 31 #define CE_PLAYER_SWITCHES_X 32 #define CE_SNAPPED_BY_PLAYER 33 #define CE_PLAYER_SNAPS_X 34 #define CE_MOVE_OF_X 35 #define CE_DIGGING_X 36 #define CE_CREATION_OF_X 37 #define CE_SCORE_GETS_ZERO 38 #define CE_SCORE_GETS_ZERO_OF_X 39 #define CE_VALUE_CHANGES 40 #define CE_VALUE_CHANGES_OF_X 41 #define CE_SCORE_CHANGES 42 #define CE_SCORE_CHANGES_OF_X 43 #define NUM_CHANGE_EVENTS 44 #define NUM_CE_BITFIELDS ((NUM_CHANGE_EVENTS + 31) / 32) #define CE_BITMASK_DEFAULT 0 #define CH_EVENT_BITFIELD_NR(e) (e / 32) #define CH_EVENT_BIT(e) (1 << ((e) % 32)) #define CH_EVENT_VAR(e,c) (element_info[e].change->has_event[c]) #define CH_ANY_EVENT_VAR(e,c) (element_info[e].has_change_event[c]) #define PAGE_HAS_CHANGE_EVENT(p,c) ((p)->has_event[c]) #define HAS_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ CH_EVENT_VAR(e,c)) #define HAS_ANY_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ CH_ANY_EVENT_VAR(e,c)) #define SET_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ? \ CH_EVENT_VAR(e,c) = (v) : 0) #define SET_ANY_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ? \ CH_ANY_EVENT_VAR(e,c) = (v) : 0) /* values for player bitmasks */ #define PLAYER_BITS_NONE 0 #define PLAYER_BITS_1 (1 << 0) #define PLAYER_BITS_2 (1 << 1) #define PLAYER_BITS_3 (1 << 2) #define PLAYER_BITS_4 (1 << 3) #define PLAYER_BITS_ANY (PLAYER_BITS_1 | \ PLAYER_BITS_2 | \ PLAYER_BITS_3 | \ PLAYER_BITS_4) #define PLAYER_BITS_TRIGGER (1 << 4) #define PLAYER_BITS_ACTION (1 << 5) /* values for move directions (bits 0 - 3: basic move directions) */ #define MV_BIT_PREVIOUS 4 #define MV_BIT_TRIGGER 5 #define MV_BIT_TRIGGER_BACK 6 #define MV_BIT_NORMAL MV_BIT_TRIGGER #define MV_BIT_REVERSE MV_BIT_TRIGGER_BACK #define MV_PREVIOUS (1 << MV_BIT_PREVIOUS) #define MV_TRIGGER (1 << MV_BIT_TRIGGER) #define MV_TRIGGER_BACK (1 << MV_BIT_TRIGGER_BACK) #define MV_NORMAL (1 << MV_BIT_NORMAL) #define MV_REVERSE (1 << MV_BIT_REVERSE) /* values for move stepsize */ #define STEPSIZE_NOT_MOVING 0 #define STEPSIZE_VERY_SLOW 1 #define STEPSIZE_SLOW 2 #define STEPSIZE_NORMAL 4 #define STEPSIZE_FAST 8 #define STEPSIZE_VERY_FAST 16 #define STEPSIZE_EVEN_FASTER 32 #define STEPSIZE_SLOWER 50 /* (symbolic value only) */ #define STEPSIZE_FASTER 200 /* (symbolic value only) */ #define STEPSIZE_RESET 100 /* (symbolic value only) */ /* values for change side for custom elements */ #define CH_SIDE_NONE MV_NONE #define CH_SIDE_LEFT MV_LEFT #define CH_SIDE_RIGHT MV_RIGHT #define CH_SIDE_TOP MV_UP #define CH_SIDE_BOTTOM MV_DOWN #define CH_SIDE_LEFT_RIGHT MV_HORIZONTAL #define CH_SIDE_TOP_BOTTOM MV_VERTICAL #define CH_SIDE_ANY MV_ANY_DIRECTION /* values for change player for custom elements */ #define CH_PLAYER_NONE PLAYER_BITS_NONE #define CH_PLAYER_1 PLAYER_BITS_1 #define CH_PLAYER_2 PLAYER_BITS_2 #define CH_PLAYER_3 PLAYER_BITS_3 #define CH_PLAYER_4 PLAYER_BITS_4 #define CH_PLAYER_ANY PLAYER_BITS_ANY /* values for change page for custom elements */ #define CH_PAGE_ANY_FILE (0xff) #define CH_PAGE_ANY (0xffffffff) /* values for change power for custom elements */ #define CP_WHEN_EMPTY 0 #define CP_WHEN_DIGGABLE 1 #define CP_WHEN_DESTRUCTIBLE 2 #define CP_WHEN_COLLECTIBLE 3 #define CP_WHEN_REMOVABLE 4 #define CP_WHEN_WALKABLE 5 /* values for change actions for custom elements (stored in level file) */ #define CA_NO_ACTION 0 #define CA_EXIT_PLAYER 1 #define CA_KILL_PLAYER 2 #define CA_MOVE_PLAYER 3 #define CA_RESTART_LEVEL 4 #define CA_SHOW_ENVELOPE 5 #define CA_SET_LEVEL_TIME 6 #define CA_SET_LEVEL_GEMS 7 #define CA_SET_LEVEL_SCORE 8 #define CA_SET_LEVEL_WIND 9 #define CA_SET_PLAYER_GRAVITY 10 #define CA_SET_PLAYER_KEYS 11 #define CA_SET_PLAYER_SPEED 12 #define CA_SET_PLAYER_SHIELD 13 #define CA_SET_PLAYER_ARTWORK 14 #define CA_SET_CE_SCORE 15 #define CA_SET_CE_VALUE 16 #define CA_SET_ENGINE_SCAN_MODE 17 #define CA_SET_PLAYER_INVENTORY 18 #define CA_SET_CE_ARTWORK 19 #define CA_SET_LEVEL_RANDOM_SEED 20 #define CA_HEADLINE_LEVEL_ACTIONS 250 #define CA_HEADLINE_PLAYER_ACTIONS 251 #define CA_HEADLINE_CE_ACTIONS 252 #define CA_HEADLINE_ENGINE_ACTIONS 253 #define CA_UNDEFINED 255 /* values for change action mode for custom elements */ #define CA_MODE_UNDEFINED 0 #define CA_MODE_SET 1 #define CA_MODE_ADD 2 #define CA_MODE_SUBTRACT 3 #define CA_MODE_MULTIPLY 4 #define CA_MODE_DIVIDE 5 #define CA_MODE_MODULO 6 /* values for change action parameters for custom elements */ #define CA_ARG_MIN 0 #define CA_ARG_0 0 #define CA_ARG_1 1 #define CA_ARG_2 2 #define CA_ARG_3 3 #define CA_ARG_4 4 #define CA_ARG_5 5 #define CA_ARG_6 6 #define CA_ARG_7 7 #define CA_ARG_8 8 #define CA_ARG_9 9 #define CA_ARG_10 10 #define CA_ARG_100 100 #define CA_ARG_1000 1000 #define CA_ARG_MAX 9999 #define CA_ARG_PLAYER 10000 #define CA_ARG_PLAYER_1 (CA_ARG_PLAYER + PLAYER_BITS_1) #define CA_ARG_PLAYER_2 (CA_ARG_PLAYER + PLAYER_BITS_2) #define CA_ARG_PLAYER_3 (CA_ARG_PLAYER + PLAYER_BITS_3) #define CA_ARG_PLAYER_4 (CA_ARG_PLAYER + PLAYER_BITS_4) #define CA_ARG_PLAYER_ANY (CA_ARG_PLAYER + PLAYER_BITS_ANY) #define CA_ARG_PLAYER_TRIGGER (CA_ARG_PLAYER + PLAYER_BITS_TRIGGER) #define CA_ARG_PLAYER_ACTION (CA_ARG_PLAYER + PLAYER_BITS_ACTION) #define CA_ARG_PLAYER_HEADLINE (CA_ARG_PLAYER + 999) #define CA_ARG_NUMBER 11000 #define CA_ARG_NUMBER_MIN (CA_ARG_NUMBER + 0) #define CA_ARG_NUMBER_MAX (CA_ARG_NUMBER + 1) #define CA_ARG_NUMBER_RESET (CA_ARG_NUMBER + 2) #define CA_ARG_NUMBER_CE_SCORE (CA_ARG_NUMBER + 3) #define CA_ARG_NUMBER_CE_VALUE (CA_ARG_NUMBER + 4) #define CA_ARG_NUMBER_CE_DELAY (CA_ARG_NUMBER + 5) #define CA_ARG_NUMBER_LEVEL_TIME (CA_ARG_NUMBER + 6) #define CA_ARG_NUMBER_LEVEL_GEMS (CA_ARG_NUMBER + 7) #define CA_ARG_NUMBER_LEVEL_SCORE (CA_ARG_NUMBER + 8) #define CA_ARG_NUMBER_HEADLINE (CA_ARG_NUMBER + 999) #define CA_ARG_ELEMENT 12000 #define CA_ARG_ELEMENT_RESET (CA_ARG_ELEMENT + 0) #define CA_ARG_ELEMENT_TARGET (CA_ARG_ELEMENT + 1) #define CA_ARG_ELEMENT_TRIGGER (CA_ARG_ELEMENT + 2) #define CA_ARG_ELEMENT_ACTION (CA_ARG_ELEMENT + 7) #define CA_ARG_ELEMENT_HEADLINE (CA_ARG_ELEMENT + 997) #define CA_ARG_ELEMENT_CV_TARGET (CA_ARG_ELEMENT_TARGET) #define CA_ARG_ELEMENT_CV_TRIGGER (CA_ARG_ELEMENT_TRIGGER) #define CA_ARG_ELEMENT_CV_ACTION (CA_ARG_ELEMENT_ACTION) #define CA_ARG_ELEMENT_CV_HEADLINE (CA_ARG_ELEMENT_HEADLINE) #define CA_ARG_ELEMENT_NR_TARGET (CA_ARG_ELEMENT + 3) #define CA_ARG_ELEMENT_NR_TRIGGER (CA_ARG_ELEMENT + 4) #define CA_ARG_ELEMENT_NR_ACTION (CA_ARG_ELEMENT + 8) #define CA_ARG_ELEMENT_NR_HEADLINE (CA_ARG_ELEMENT + 998) #define CA_ARG_ELEMENT_CS_TARGET (CA_ARG_ELEMENT + 5) #define CA_ARG_ELEMENT_CS_TRIGGER (CA_ARG_ELEMENT + 6) #define CA_ARG_ELEMENT_CS_ACTION (CA_ARG_ELEMENT + 9) #define CA_ARG_ELEMENT_CS_HEADLINE (CA_ARG_ELEMENT + 999) #define CA_ARG_SPEED 13000 #define CA_ARG_SPEED_NOT_MOVING (CA_ARG_SPEED + STEPSIZE_NOT_MOVING) #define CA_ARG_SPEED_VERY_SLOW (CA_ARG_SPEED + STEPSIZE_VERY_SLOW) #define CA_ARG_SPEED_SLOW (CA_ARG_SPEED + STEPSIZE_SLOW) #define CA_ARG_SPEED_NORMAL (CA_ARG_SPEED + STEPSIZE_NORMAL) #define CA_ARG_SPEED_FAST (CA_ARG_SPEED + STEPSIZE_FAST) #define CA_ARG_SPEED_VERY_FAST (CA_ARG_SPEED + STEPSIZE_VERY_FAST) #define CA_ARG_SPEED_EVEN_FASTER (CA_ARG_SPEED + STEPSIZE_EVEN_FASTER) #define CA_ARG_SPEED_SLOWER (CA_ARG_SPEED + STEPSIZE_SLOWER) #define CA_ARG_SPEED_FASTER (CA_ARG_SPEED + STEPSIZE_FASTER) #define CA_ARG_SPEED_RESET (CA_ARG_SPEED + STEPSIZE_RESET) #define CA_ARG_SPEED_HEADLINE (CA_ARG_SPEED + 999) #define CA_ARG_GRAVITY 14000 #define CA_ARG_GRAVITY_OFF (CA_ARG_GRAVITY + 0) #define CA_ARG_GRAVITY_ON (CA_ARG_GRAVITY + 1) #define CA_ARG_GRAVITY_TOGGLE (CA_ARG_GRAVITY + 2) #define CA_ARG_GRAVITY_HEADLINE (CA_ARG_GRAVITY + 999) #define CA_ARG_DIRECTION 15000 #define CA_ARG_DIRECTION_NONE (CA_ARG_DIRECTION + MV_NONE) #define CA_ARG_DIRECTION_LEFT (CA_ARG_DIRECTION + MV_LEFT) #define CA_ARG_DIRECTION_RIGHT (CA_ARG_DIRECTION + MV_RIGHT) #define CA_ARG_DIRECTION_UP (CA_ARG_DIRECTION + MV_UP) #define CA_ARG_DIRECTION_DOWN (CA_ARG_DIRECTION + MV_DOWN) #define CA_ARG_DIRECTION_TRIGGER (CA_ARG_DIRECTION + MV_TRIGGER) #define CA_ARG_DIRECTION_TRIGGER_BACK (CA_ARG_DIRECTION + MV_TRIGGER_BACK) #define CA_ARG_DIRECTION_HEADLINE (CA_ARG_DIRECTION + 999) #define CA_ARG_SHIELD 16000 #define CA_ARG_SHIELD_OFF (CA_ARG_SHIELD + 0) #define CA_ARG_SHIELD_NORMAL (CA_ARG_SHIELD + 1) #define CA_ARG_SHIELD_DEADLY (CA_ARG_SHIELD + 2) #define CA_ARG_SHIELD_HEADLINE (CA_ARG_SHIELD + 999) #define CA_ARG_SCAN_MODE 17000 #define CA_ARG_SCAN_MODE_NORMAL (CA_ARG_SCAN_MODE + MV_NORMAL) #define CA_ARG_SCAN_MODE_REVERSE (CA_ARG_SCAN_MODE + MV_REVERSE) #define CA_ARG_SCAN_MODE_HEADLINE (CA_ARG_SCAN_MODE + 999) #define CA_ARG_INVENTORY 18000 #define CA_ARG_INVENTORY_RESET (CA_ARG_INVENTORY + 0) #define CA_ARG_INVENTORY_RM_TARGET (CA_ARG_INVENTORY + 1) #define CA_ARG_INVENTORY_RM_TRIGGER (CA_ARG_INVENTORY + 2) #define CA_ARG_INVENTORY_RM_ACTION (CA_ARG_INVENTORY + 3) #define CA_ARG_INVENTORY_RM_FIRST (CA_ARG_INVENTORY + 4) #define CA_ARG_INVENTORY_RM_LAST (CA_ARG_INVENTORY + 5) #define CA_ARG_INVENTORY_RM_ALL (CA_ARG_INVENTORY + 6) #define CA_ARG_INVENTORY_HEADLINE (CA_ARG_INVENTORY + 998) #define CA_ARG_INVENTORY_RM_HEADLINE (CA_ARG_INVENTORY + 999) #define CA_ARG_UNDEFINED 65535 /* values for custom move patterns (bits 0 - 3: basic move directions) */ #define MV_BIT_TOWARDS_PLAYER 4 #define MV_BIT_AWAY_FROM_PLAYER 5 #define MV_BIT_ALONG_LEFT_SIDE 6 #define MV_BIT_ALONG_RIGHT_SIDE 7 #define MV_BIT_TURNING_LEFT 8 #define MV_BIT_TURNING_RIGHT 9 #define MV_BIT_WHEN_PUSHED 10 #define MV_BIT_MAZE_RUNNER 11 #define MV_BIT_MAZE_HUNTER 12 #define MV_BIT_WHEN_DROPPED 13 #define MV_BIT_TURNING_LEFT_RIGHT 14 #define MV_BIT_TURNING_RIGHT_LEFT 15 #define MV_BIT_TURNING_RANDOM 16 #define MV_BIT_WIND_DIRECTION 17 /* values for custom move patterns */ #define MV_TOWARDS_PLAYER (1 << MV_BIT_TOWARDS_PLAYER) #define MV_AWAY_FROM_PLAYER (1 << MV_BIT_AWAY_FROM_PLAYER) #define MV_ALONG_LEFT_SIDE (1 << MV_BIT_ALONG_LEFT_SIDE) #define MV_ALONG_RIGHT_SIDE (1 << MV_BIT_ALONG_RIGHT_SIDE) #define MV_TURNING_LEFT (1 << MV_BIT_TURNING_LEFT) #define MV_TURNING_RIGHT (1 << MV_BIT_TURNING_RIGHT) #define MV_WHEN_PUSHED (1 << MV_BIT_WHEN_PUSHED) #define MV_MAZE_RUNNER (1 << MV_BIT_MAZE_RUNNER) #define MV_MAZE_HUNTER (1 << MV_BIT_MAZE_HUNTER) #define MV_MAZE_RUNNER_STYLE (MV_MAZE_RUNNER | MV_MAZE_HUNTER) #define MV_WHEN_DROPPED (1 << MV_BIT_WHEN_DROPPED) #define MV_TURNING_LEFT_RIGHT (1 << MV_BIT_TURNING_LEFT_RIGHT) #define MV_TURNING_RIGHT_LEFT (1 << MV_BIT_TURNING_RIGHT_LEFT) #define MV_TURNING_RANDOM (1 << MV_BIT_TURNING_RANDOM) #define MV_WIND_DIRECTION (1 << MV_BIT_WIND_DIRECTION) /* values for initial move direction */ #define MV_START_NONE (MV_NONE) #define MV_START_AUTOMATIC (MV_NONE) #define MV_START_LEFT (MV_LEFT) #define MV_START_RIGHT (MV_RIGHT) #define MV_START_UP (MV_UP) #define MV_START_DOWN (MV_DOWN) #define MV_START_RANDOM (MV_ALL_DIRECTIONS) #define MV_START_PREVIOUS (MV_PREVIOUS) /* values for elements left behind by custom elements */ #define LEAVE_TYPE_UNLIMITED 0 #define LEAVE_TYPE_LIMITED 1 /* values for slippery property for custom elements */ #define SLIPPERY_ANY_RANDOM 0 #define SLIPPERY_ANY_LEFT_RIGHT 1 #define SLIPPERY_ANY_RIGHT_LEFT 2 #define SLIPPERY_ONLY_LEFT 3 #define SLIPPERY_ONLY_RIGHT 4 /* values for explosion type for custom elements */ #define EXPLODES_3X3 0 #define EXPLODES_1X1 1 #define EXPLODES_CROSS 2 /* macros for configurable properties */ #define IS_DIGGABLE(e) HAS_PROPERTY(e, EP_DIGGABLE) #define IS_COLLECTIBLE_ONLY(e) HAS_PROPERTY(e, EP_COLLECTIBLE_ONLY) #define DONT_RUN_INTO(e) HAS_PROPERTY(e, EP_DONT_RUN_INTO) #define DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_DONT_COLLIDE_WITH) #define DONT_TOUCH(e) HAS_PROPERTY(e, EP_DONT_TOUCH) #define IS_INDESTRUCTIBLE(e) HAS_PROPERTY(e, EP_INDESTRUCTIBLE) #define IS_SLIPPERY(e) HAS_PROPERTY(e, EP_SLIPPERY) #define CAN_CHANGE(e) HAS_PROPERTY(e, EP_CAN_CHANGE) #define CAN_MOVE(e) HAS_PROPERTY(e, EP_CAN_MOVE) #define CAN_FALL(e) HAS_PROPERTY(e, EP_CAN_FALL) #define CAN_SMASH_PLAYER(e) HAS_PROPERTY(e, EP_CAN_SMASH_PLAYER) #define CAN_SMASH_ENEMIES(e) HAS_PROPERTY(e, EP_CAN_SMASH_ENEMIES) #define CAN_SMASH_EVERYTHING(e) HAS_PROPERTY(e, EP_CAN_SMASH_EVERYTHING) #define EXPLODES_BY_FIRE(e) HAS_PROPERTY(e, EP_EXPLODES_BY_FIRE) #define EXPLODES_SMASHED(e) HAS_PROPERTY(e, EP_EXPLODES_SMASHED) #define EXPLODES_IMPACT(e) HAS_PROPERTY(e, EP_EXPLODES_IMPACT) #define IS_WALKABLE_OVER(e) HAS_PROPERTY(e, EP_WALKABLE_OVER) #define IS_WALKABLE_INSIDE(e) HAS_PROPERTY(e, EP_WALKABLE_INSIDE) #define IS_WALKABLE_UNDER(e) HAS_PROPERTY(e, EP_WALKABLE_UNDER) #define IS_PASSABLE_OVER(e) HAS_PROPERTY(e, EP_PASSABLE_OVER) #define IS_PASSABLE_INSIDE(e) HAS_PROPERTY(e, EP_PASSABLE_INSIDE) #define IS_PASSABLE_UNDER(e) HAS_PROPERTY(e, EP_PASSABLE_UNDER) #define IS_DROPPABLE(e) HAS_PROPERTY(e, EP_DROPPABLE) #define EXPLODES_1X1_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_1X1_OLD) #define IS_PUSHABLE(e) HAS_PROPERTY(e, EP_PUSHABLE) #define EXPLODES_CROSS_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_CROSS_OLD) #define IS_PROTECTED(e) HAS_PROPERTY(e, EP_PROTECTED) #define CAN_MOVE_INTO_ACID(e) HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID) #define IS_THROWABLE(e) HAS_PROPERTY(e, EP_THROWABLE) #define CAN_EXPLODE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE) #define IS_GRAVITY_REACHABLE(e) HAS_PROPERTY(e, EP_GRAVITY_REACHABLE) #define DONT_GET_HIT_BY(e) HAS_PROPERTY(e, EP_DONT_GET_HIT_BY) /* macros for special configurable properties */ #define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL) /* macros for special graphics properties */ #define GFX_CRUMBLED(e) HAS_PROPERTY(GFX_ELEMENT(e), EP_GFX_CRUMBLED) /* macros for pre-defined properties */ #define ELEM_IS_PLAYER(e) HAS_PROPERTY(e, EP_PLAYER) #define CAN_PASS_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_MAGIC_WALL) #define CAN_PASS_DC_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_DC_MAGIC_WALL) #define IS_SWITCHABLE(e) HAS_PROPERTY(e, EP_SWITCHABLE) #define IS_BD_ELEMENT(e) HAS_PROPERTY(e, EP_BD_ELEMENT) #define IS_SP_ELEMENT(e) HAS_PROPERTY(e, EP_SP_ELEMENT) #define IS_SB_ELEMENT(e) HAS_PROPERTY(e, EP_SB_ELEMENT) #define IS_GEM(e) HAS_PROPERTY(e, EP_GEM) #define IS_FOOD_DARK_YAMYAM(e) HAS_PROPERTY(e, EP_FOOD_DARK_YAMYAM) #define IS_FOOD_PENGUIN(e) HAS_PROPERTY(e, EP_FOOD_PENGUIN) #define IS_FOOD_PIG(e) HAS_PROPERTY(e, EP_FOOD_PIG) #define IS_HISTORIC_WALL(e) HAS_PROPERTY(e, EP_HISTORIC_WALL) #define IS_HISTORIC_SOLID(e) HAS_PROPERTY(e, EP_HISTORIC_SOLID) #define IS_CLASSIC_ENEMY(e) HAS_PROPERTY(e, EP_CLASSIC_ENEMY) #define IS_BELT(e) HAS_PROPERTY(e, EP_BELT) #define IS_BELT_ACTIVE(e) HAS_PROPERTY(e, EP_BELT_ACTIVE) #define IS_BELT_SWITCH(e) HAS_PROPERTY(e, EP_BELT_SWITCH) #define IS_TUBE(e) HAS_PROPERTY(e, EP_TUBE) #define IS_ACID_POOL(e) HAS_PROPERTY(e, EP_ACID_POOL) #define IS_KEYGATE(e) HAS_PROPERTY(e, EP_KEYGATE) #define IS_AMOEBOID(e) HAS_PROPERTY(e, EP_AMOEBOID) #define IS_AMOEBALIVE(e) HAS_PROPERTY(e, EP_AMOEBALIVE) #define HAS_EDITOR_CONTENT(e) HAS_PROPERTY(e, EP_HAS_EDITOR_CONTENT) #define CAN_TURN_EACH_MOVE(e) HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE) #define CAN_GROW(e) HAS_PROPERTY(e, EP_CAN_GROW) #define IS_ACTIVE_BOMB(e) HAS_PROPERTY(e, EP_ACTIVE_BOMB) #define IS_INACTIVE(e) HAS_PROPERTY(e, EP_INACTIVE) /* macros for derived properties */ #define IS_ACCESSIBLE_OVER(e) HAS_PROPERTY(e, EP_ACCESSIBLE_OVER) #define IS_ACCESSIBLE_INSIDE(e) HAS_PROPERTY(e, EP_ACCESSIBLE_INSIDE) #define IS_ACCESSIBLE_UNDER(e) HAS_PROPERTY(e, EP_ACCESSIBLE_UNDER) #define IS_WALKABLE(e) HAS_PROPERTY(e, EP_WALKABLE) #define IS_PASSABLE(e) HAS_PROPERTY(e, EP_PASSABLE) #define IS_ACCESSIBLE(e) HAS_PROPERTY(e, EP_ACCESSIBLE) #define IS_COLLECTIBLE(e) HAS_PROPERTY(e, EP_COLLECTIBLE) #define IS_SNAPPABLE(e) HAS_PROPERTY(e, EP_SNAPPABLE) #define IS_WALL(e) HAS_PROPERTY(e, EP_WALL) #define IS_SOLID_FOR_PUSHING(e) HAS_PROPERTY(e, EP_SOLID_FOR_PUSHING) #define IS_DRAGONFIRE_PROOF(e) HAS_PROPERTY(e, EP_DRAGONFIRE_PROOF) #define IS_EXPLOSION_PROOF(e) HAS_PROPERTY(e, EP_EXPLOSION_PROOF) #define CAN_SMASH(e) HAS_PROPERTY(e, EP_CAN_SMASH) #define EXPLODES_3X3_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_3X3_OLD) #define CAN_EXPLODE_BY_FIRE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE) #define CAN_EXPLODE_SMASHED(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED) #define CAN_EXPLODE_IMPACT(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT) #define IS_SP_PORT(e) HAS_PROPERTY(e, EP_SP_PORT) #define CAN_EXPLODE_BY_DRAGONFIRE(e) \ HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE) #define CAN_EXPLODE_BY_EXPLOSION(e) \ HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION) #define COULD_MOVE_INTO_ACID(e) HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID) #define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH) #define CAN_BE_CLONED_BY_ANDROID(e) \ HAS_PROPERTY(e, EP_CAN_BE_CLONED_BY_ANDROID) #define IS_EDITOR_CASCADE(e) HAS_PROPERTY(e, EP_EDITOR_CASCADE) #define IS_EDITOR_CASCADE_ACTIVE(e) \ HAS_PROPERTY(e, EP_EDITOR_CASCADE_ACTIVE) #define IS_EDITOR_CASCADE_INACTIVE(e) \ HAS_PROPERTY(e, EP_EDITOR_CASCADE_INACTIVE) #define HAS_ACTION(e) HAS_PROPERTY(e, EP_HAS_ACTION) #define CAN_CHANGE_OR_HAS_ACTION(e) \ HAS_PROPERTY(e, EP_CAN_CHANGE_OR_HAS_ACTION) #define IS_OBSOLETE(e) HAS_PROPERTY(e, EP_OBSOLETE) /* special macros used in game engine */ #define IS_FILE_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_FILE_ELEMENTS) #define IS_DRAWABLE_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_DRAWABLE_ELEMENTS) #define IS_RUNTIME_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_RUNTIME_ELEMENTS) #define IS_VALID_ELEMENT(e) ((e) >= 0 && \ (e) <= MAX_NUM_ELEMENTS) #define IS_CUSTOM_ELEMENT(e) ((e) >= EL_CUSTOM_START && \ (e) <= EL_CUSTOM_END) #define IS_GROUP_ELEMENT(e) ((e) >= EL_GROUP_START && \ (e) <= EL_GROUP_END) #define IS_CLIPBOARD_ELEMENT(e) ((e) >= EL_INTERNAL_CLIPBOARD_START && \ (e) <= EL_INTERNAL_CLIPBOARD_END) #define IS_INTERNAL_ELEMENT(e) ((e) >= EL_INTERNAL_START && \ (e) <= EL_INTERNAL_END) #define IS_ENVELOPE(e) ((e) >= EL_ENVELOPE_1 && \ (e) <= EL_ENVELOPE_4) #define IS_RND_KEY(e) ((e) >= EL_KEY_1 && \ (e) <= EL_KEY_4) #define IS_EM_KEY(e) ((e) >= EL_EM_KEY_1 && \ (e) <= EL_EM_KEY_4) #define IS_EMC_KEY(e) ((e) >= EL_EMC_KEY_5 && \ (e) <= EL_EMC_KEY_8) #define IS_KEY(e) (IS_RND_KEY(e) || \ IS_EM_KEY(e) || \ IS_EMC_KEY(e)) #define RND_KEY_NR(e) ((e) - EL_KEY_1) #define EM_KEY_NR(e) ((e) - EL_EM_KEY_1) #define EMC_KEY_NR(e) ((e) - EL_EMC_KEY_5 + 4) #define KEY_NR(e) (IS_RND_KEY(e) ? RND_KEY_NR(e) : \ IS_EM_KEY(e) ? EM_KEY_NR(e) : \ IS_EMC_KEY(e) ? EMC_KEY_NR(e) : 0) #define IS_RND_GATE(e) ((e) >= EL_GATE_1 && \ (e) <= EL_GATE_4) #define IS_EM_GATE(e) ((e) >= EL_EM_GATE_1 && \ (e) <= EL_EM_GATE_4) #define IS_EMC_GATE(e) ((e) >= EL_EMC_GATE_5 && \ (e) <= EL_EMC_GATE_8) #define IS_DC_GATE(e) ((e) == EL_DC_GATE_WHITE) #define IS_GATE(e) (IS_RND_GATE(e) || \ IS_EM_GATE(e) || \ IS_EMC_GATE(e) || \ IS_DC_GATE(e)) #define RND_GATE_NR(e) ((e) - EL_GATE_1) #define EM_GATE_NR(e) ((e) - EL_EM_GATE_1) #define EMC_GATE_NR(e) ((e) - EL_EMC_GATE_5 + 4) #define GATE_NR(e) (IS_RND_GATE(e) ? RND_GATE_NR(e) : \ IS_EM_GATE(e) ? EM_GATE_NR(e) : \ IS_EMC_GATE(e) ? EMC_GATE_NR(e) : 0) #define IS_RND_GATE_GRAY(e) ((e) >= EL_GATE_1_GRAY && \ (e) <= EL_GATE_4_GRAY) #define IS_RND_GATE_GRAY_ACTIVE(e) ((e) >= EL_GATE_1_GRAY_ACTIVE && \ (e) <= EL_GATE_4_GRAY_ACTIVE) #define IS_EM_GATE_GRAY(e) ((e) >= EL_EM_GATE_1_GRAY && \ (e) <= EL_EM_GATE_4_GRAY) #define IS_EM_GATE_GRAY_ACTIVE(e) ((e) >= EL_EM_GATE_1_GRAY_ACTIVE && \ (e) <= EL_EM_GATE_4_GRAY_ACTIVE) #define IS_EMC_GATE_GRAY(e) ((e) >= EL_EMC_GATE_5_GRAY && \ (e) <= EL_EMC_GATE_8_GRAY) #define IS_EMC_GATE_GRAY_ACTIVE(e) ((e) >= EL_EMC_GATE_5_GRAY_ACTIVE && \ (e) <= EL_EMC_GATE_8_GRAY_ACTIVE) #define IS_DC_GATE_GRAY(e) ((e) == EL_DC_GATE_WHITE_GRAY) #define IS_DC_GATE_GRAY_ACTIVE(e) ((e) == EL_DC_GATE_WHITE_GRAY_ACTIVE) #define IS_GATE_GRAY(e) (IS_RND_GATE_GRAY(e) || \ IS_EM_GATE_GRAY(e) || \ IS_EMC_GATE_GRAY(e) || \ IS_DC_GATE_GRAY(e)) #define IS_GATE_GRAY_ACTIVE(e) (IS_RND_GATE_GRAY_ACTIVE(e) || \ IS_EM_GATE_GRAY_ACTIVE(e) || \ IS_EMC_GATE_GRAY_ACTIVE(e) || \ IS_DC_GATE_GRAY_ACTIVE(e)) #define RND_GATE_GRAY_NR(e) ((e) - EL_GATE_1_GRAY) #define RND_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_GATE_1_GRAY_ACTIVE) #define EM_GATE_GRAY_NR(e) ((e) - EL_EM_GATE_1_GRAY) #define EM_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EM_GATE_1_GRAY_ACTIVE) #define EMC_GATE_GRAY_NR(e) ((e) - EL_EMC_GATE_5_GRAY + 4) #define EMC_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EMC_GATE_5_GRAY_ACTIVE + 4) #define GATE_GRAY_NR(e) (IS_RND_GATE_GRAY(e) ? RND_GATE_GRAY_NR(e) : \ IS_EM_GATE_GRAY(e) ? EM_GATE_GRAY_NR(e) : \ IS_EMC_GATE_GRAY(e) ? EMC_GATE_GRAY_NR(e) : 0) #define IS_ACID_POOL_OR_ACID(e) (IS_ACID_POOL(e) || (e) == EL_ACID) #define IS_EMC_PILLAR(e) ((e) >= EL_EMC_WALL_1 && \ (e) <= EL_EMC_WALL_3) #define IS_SP_CHIP(e) ((e) == EL_SP_CHIP_SINGLE || \ (e) == EL_SP_CHIP_LEFT || \ (e) == EL_SP_CHIP_RIGHT || \ (e) == EL_SP_CHIP_TOP || \ (e) == EL_SP_CHIP_BOTTOM) #define IS_SP_HARDWARE_BASE(e) ((e) == EL_SP_HARDWARE_BASE_1 || \ (e) == EL_SP_HARDWARE_BASE_2 || \ (e) == EL_SP_HARDWARE_BASE_3 || \ (e) == EL_SP_HARDWARE_BASE_4 || \ (e) == EL_SP_HARDWARE_BASE_5 || \ (e) == EL_SP_HARDWARE_BASE_6) #define IS_DC_STEELWALL_2(e) ((e) >= EL_DC_STEELWALL_2_LEFT && \ (e) <= EL_DC_STEELWALL_2_SINGLE) #if 1 #if 1 #define GFX_ELEMENT(e) (element_info[e].gfx_element) #else #define GFX_ELEMENT(e) (element_info[e].gfx_element == \ (element_info[e].use_gfx_element ? \ element_info[e].gfx_element : e) ? \ element_info[e].gfx_element : \ element_info[e].gfx_element + \ 0 * printf("::: %d: %d <-> %d\n", \ e, \ element_info[e].gfx_element, \ element_info[e].use_gfx_element ? \ element_info[e].gfx_element : e)) #endif #else #define GFX_ELEMENT(e) (element_info[e].use_gfx_element ? \ element_info[e].gfx_element : e) #endif /* !!! CHECK THIS !!! */ #if 1 #define TILE_GFX_ELEMENT(x, y) \ (GfxElement[x][y] != EL_UNDEFINED && \ Feld[x][y] != EL_EXPLOSION ? \ GfxElement[x][y] : Feld[x][y]) #else #define TILE_GFX_ELEMENT(x, y) \ GFX_ELEMENT(GfxElement[x][y] != EL_UNDEFINED && \ Feld[x][y] != EL_EXPLOSION ? \ GfxElement[x][y] : Feld[x][y]) #endif /* !!! "use sound" deactivated due to problems with level "bug machine" !!! */ /* (solution: add separate "use sound of element" to level file and editor) */ #if 0 #define SND_ELEMENT(e) GFX_ELEMENT(e) #else #define SND_ELEMENT(e) (e) #endif #define GROUP_NR(e) ((e) - EL_GROUP_START) #define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE) #define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START)) #define IS_EQUAL_OR_IN_GROUP(e, ge) \ (ge == EL_ANY_ELEMENT ? TRUE : \ IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge)) #define IS_PLAYER(x, y) (ELEM_IS_PLAYER(StorePlayer[x][y])) #define IS_FREE(x, y) (Feld[x][y] == EL_EMPTY && !IS_PLAYER(x, y)) #define IS_FREE_OR_PLAYER(x, y) (Feld[x][y] == EL_EMPTY) #define IS_MOVING(x,y) (MovPos[x][y] != 0) #define IS_FALLING(x,y) (MovPos[x][y] != 0 && MovDir[x][y] == MV_DOWN) #define IS_BLOCKED(x,y) (Feld[x][y] == EL_BLOCKED) #define IS_MV_DIAGONAL(x) ((x) & MV_HORIZONTAL && (x) & MV_VERTICAL) #define EL_CHANGED(e) ((e) == EL_ROCK ? EL_EMERALD : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ (e) == EL_EMERALD ? EL_DIAMOND : \ (e) == EL_EMERALD_YELLOW ? EL_DIAMOND : \ (e) == EL_EMERALD_RED ? EL_DIAMOND : \ (e) == EL_EMERALD_PURPLE ? EL_DIAMOND : \ EL_ROCK) #define EL_CHANGED_BD(e) ((e) == EL_ROCK ? EL_BD_DIAMOND : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ EL_BD_ROCK) #define EL_CHANGED_DC(e) ((e) == EL_ROCK ? EL_EMERALD : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ (e) == EL_EMERALD ? EL_DIAMOND : \ (e) == EL_EMERALD_YELLOW ? EL_DIAMOND : \ (e) == EL_EMERALD_RED ? EL_DIAMOND : \ (e) == EL_EMERALD_PURPLE ? EL_DIAMOND : \ (e) == EL_PEARL ? EL_BOMB : \ (e) == EL_CRYSTAL ? EL_CRYSTAL : \ EL_ROCK) #define IS_DRAWABLE(e) ((e) < EL_BLOCKED) #define IS_NOT_DRAWABLE(e) ((e) >= EL_BLOCKED) #define TAPE_IS_EMPTY(x) ((x).length == 0) #define TAPE_IS_STOPPED(x) (!(x).recording && !(x).playing) #define PLAYERINFO(x,y) (&stored_player[StorePlayer[x][y]-EL_PLAYER_1]) #define SHIELD_ON(p) ((p)->shield_normal_time_left > 0) #define ENEMY_PROTECTED_FIELD(x,y) (IS_PROTECTED(Feld[x][y]) || \ IS_PROTECTED(Back[x][y])) #define EXPLOSION_PROTECTED_FIELD(x,y) (IS_EXPLOSION_PROOF(Feld[x][y])) #define PLAYER_ENEMY_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) || \ ENEMY_PROTECTED_FIELD(x, y)) #define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) || \ EXPLOSION_PROTECTED_FIELD(x, y)) #define PLAYER_SWITCHING(p,x,y) ((p)->is_switching && \ (p)->switch_x == (x) && (p)->switch_y == (y)) #define PLAYER_DROPPING(p,x,y) ((p)->is_dropping && \ (p)->drop_x == (x) && (p)->drop_y == (y)) #define PLAYER_NR_GFX(g,i) ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_1)) #define GET_PLAYER_ELEMENT(e) ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? \ (e) : EL_PLAYER_1) #define GET_PLAYER_NR(e) (GET_PLAYER_ELEMENT(e) - EL_PLAYER_1) #define ANIM_FRAMES(g) (graphic_info[g].anim_frames) #define ANIM_DELAY(g) (graphic_info[g].anim_delay) #define ANIM_MODE(g) (graphic_info[g].anim_mode) #define IS_ANIM_MODE_CE(g) (graphic_info[g].anim_mode & (ANIM_CE_VALUE | \ ANIM_CE_SCORE | \ ANIM_CE_DELAY)) #define IS_ANIMATED(g) (ANIM_FRAMES(g) > 1) #define IS_NEW_DELAY(f, g) ((f) % ANIM_DELAY(g) == 0) #define IS_NEW_FRAME(f, g) (IS_ANIMATED(g) && IS_NEW_DELAY(f, g)) #define IS_NEXT_FRAME(f, g) (IS_NEW_FRAME(f, g) && (f) > 0) #define IS_LOOP_SOUND(s) (sound_info[s].loop) #define IS_SPECIAL_GFX_ARG(a) ((a) >= 0 && (a) < NUM_SPECIAL_GFX_ARGS) #define EL_CASCADE_ACTIVE(e) (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e)) #define EL_CASCADE_INACTIVE(e) (IS_EDITOR_CASCADE_ACTIVE(e) ? (e) - 1 : (e)) #define EL_CASCADE_TOGGLE(e) (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : \ IS_EDITOR_CASCADE_ACTIVE(e) ? (e) - 1 : (e)) #define EL_NAME(e) ((e) >= 0 ? element_info[e].token_name : "(?)") #define MV_TEXT(d) ((d) == MV_NONE ? "MV_NONE" : \ (d) == MV_LEFT ? "MV_LEFT" : \ (d) == MV_RIGHT ? "MV_RIGHT" : \ (d) == MV_UP ? "MV_UP" : \ (d) == MV_DOWN ? "MV_DOWN" : "(various)") #define ELEMENT_ACTIVE(e) (ActiveElement[e]) #define BUTTON_ACTIVE(b) (ActiveButton[b]) #define FONT_ACTIVE(f) (ActiveFont[f]) /* fundamental game speed values */ #define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */ #define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */ /* boundaries of arrays etc. */ #define MAX_LEVEL_NAME_LEN 32 #define MAX_LEVEL_AUTHOR_LEN 32 #define MAX_ELEMENT_NAME_LEN 32 #define MAX_TAPES_PER_SET 1024 #define MAX_SCORE_ENTRIES 100 #define MAX_NUM_TITLE_IMAGES 5 #define MAX_NUM_TITLE_MESSAGES 5 #define MAX_NUM_AMOEBA 100 #define NUM_ENVELOPES 4 #define MIN_ENVELOPE_XSIZE 1 #define MIN_ENVELOPE_YSIZE 1 #define MAX_ENVELOPE_XSIZE 30 #define MAX_ENVELOPE_YSIZE 20 #define MAX_ENVELOPE_TEXT_LEN (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE) #define MIN_CHANGE_PAGES 1 #define MAX_CHANGE_PAGES 32 #define MIN_ELEMENTS_IN_GROUP 1 #define MAX_ELEMENTS_IN_GROUP 16 #define MIN_ANDROID_ELEMENTS 1 #define MAX_ANDROID_ELEMENTS 16 /* values for elements with content */ #define MIN_ELEMENT_CONTENTS 1 #define STD_ELEMENT_CONTENTS 4 #define MAX_ELEMENT_CONTENTS 8 /* values for initial player inventory */ #define MIN_INITIAL_INVENTORY_SIZE 1 #define MAX_INITIAL_INVENTORY_SIZE 8 /* often used screen positions */ #if 0 #define SX 8 #define SY 8 #define REAL_SX (SX - 2) #define REAL_SY (SY - 2) #define DX 566 #define DY 60 #define VX DX #define VY 400 #define EX DX #define EY (VY - 44) #endif #define TILESIZE 32 #define TILEX TILESIZE #define TILEY TILESIZE #define MINI_TILESIZE (TILESIZE / 2) #define MINI_TILEX MINI_TILESIZE #define MINI_TILEY MINI_TILESIZE #define MICRO_TILESIZE (TILESIZE / 8) #define MICRO_TILEX MICRO_TILESIZE #define MICRO_TILEY MICRO_TILESIZE #define MIDPOSX (SCR_FIELDX / 2) #define MIDPOSY (SCR_FIELDY / 2) #define SXSIZE (SCR_FIELDX * TILEX) #define SYSIZE (SCR_FIELDY * TILEY) #define FXSIZE ((SCR_FIELDX + 2) * TILEX) #define FYSIZE ((SCR_FIELDY + 2) * TILEY) #define DXSIZE 100 #define DYSIZE 280 #define VXSIZE DXSIZE #define VYSIZE 100 #define EXSIZE DXSIZE #define EYSIZE (VYSIZE + 44) #define FULL_SXSIZE (2 + SXSIZE + 2) #define FULL_SYSIZE (2 + SYSIZE + 2) #define MICROLEVEL_XSIZE ((STD_LEV_FIELDX + 2) * MICRO_TILEX) #define MICROLEVEL_YSIZE ((STD_LEV_FIELDY + 2) * MICRO_TILEY) #define MICROLEVEL_XPOS (SX + (SXSIZE - MICROLEVEL_XSIZE) / 2) #define MICROLEVEL_YPOS (SY + 12 * TILEY - MICRO_TILEY) #define MICROLABEL1_YPOS (MICROLEVEL_YPOS - 36) #define MICROLABEL2_YPOS (MICROLEVEL_YPOS + MICROLEVEL_YSIZE + 7) /* values for GfxRedraw */ #define GFX_REDRAW_NONE (0) #define GFX_REDRAW_TILE (1 << 0) #define GFX_REDRAW_TILE_CRUMBLED (1 << 1) #define GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS (1 << 2) #define GFX_REDRAW_TILE_TWINKLED (1 << 3) /* score for elements */ #define SC_EMERALD 0 #define SC_DIAMOND 1 #define SC_BUG 2 #define SC_SPACESHIP 3 #define SC_YAMYAM 4 #define SC_ROBOT 5 #define SC_PACMAN 6 #define SC_NUT 7 #define SC_DYNAMITE 8 #define SC_KEY 9 #define SC_TIME_BONUS 10 #define SC_CRYSTAL 11 #define SC_PEARL 12 #define SC_SHIELD 13 #define SC_UNKNOWN_14 14 #define SC_UNKNOWN_15 15 #define LEVEL_SCORE_ELEMENTS 16 /* level elements with score */ /* "real" level file elements */ #define EL_UNDEFINED -1 #define EL_EMPTY_SPACE 0 #define EL_EMPTY EL_EMPTY_SPACE #define EL_SAND 1 #define EL_WALL 2 #define EL_WALL_SLIPPERY 3 #define EL_ROCK 4 #define EL_KEY_OBSOLETE 5 /* obsolete; now EL_KEY_1 */ #define EL_EMERALD 6 #define EL_EXIT_CLOSED 7 #define EL_PLAYER_OBSOLETE 8 /* obsolete; now EL_PLAYER_1 */ #define EL_BUG 9 #define EL_SPACESHIP 10 #define EL_YAMYAM 11 #define EL_ROBOT 12 #define EL_STEELWALL 13 #define EL_DIAMOND 14 #define EL_AMOEBA_DEAD 15 #define EL_QUICKSAND_EMPTY 16 #define EL_QUICKSAND_FULL 17 #define EL_AMOEBA_DROP 18 #define EL_BOMB 19 #define EL_MAGIC_WALL 20 #define EL_SPEED_PILL 21 #define EL_ACID 22 #define EL_AMOEBA_WET 23 #define EL_AMOEBA_DRY 24 #define EL_NUT 25 #define EL_GAME_OF_LIFE 26 #define EL_BIOMAZE 27 #define EL_DYNAMITE_ACTIVE 28 #define EL_STONEBLOCK 29 #define EL_ROBOT_WHEEL 30 #define EL_ROBOT_WHEEL_ACTIVE 31 #define EL_KEY_1 32 #define EL_KEY_2 33 #define EL_KEY_3 34 #define EL_KEY_4 35 #define EL_GATE_1 36 #define EL_GATE_2 37 #define EL_GATE_3 38 #define EL_GATE_4 39 #define EL_GATE_1_GRAY 40 #define EL_GATE_2_GRAY 41 #define EL_GATE_3_GRAY 42 #define EL_GATE_4_GRAY 43 #define EL_DYNAMITE 44 #define EL_PACMAN 45 #define EL_INVISIBLE_WALL 46 #define EL_LAMP 47 #define EL_LAMP_ACTIVE 48 #define EL_WALL_EMERALD 49 #define EL_WALL_DIAMOND 50 #define EL_AMOEBA_FULL 51 #define EL_BD_AMOEBA 52 #define EL_TIME_ORB_FULL 53 #define EL_TIME_ORB_EMPTY 54 #define EL_EXPANDABLE_WALL 55 #define EL_BD_DIAMOND 56 #define EL_EMERALD_YELLOW 57 #define EL_WALL_BD_DIAMOND 58 #define EL_WALL_EMERALD_YELLOW 59 #define EL_DARK_YAMYAM 60 #define EL_BD_MAGIC_WALL 61 #define EL_INVISIBLE_STEELWALL 62 #define EL_SOKOBAN_FIELD_PLAYER 63 #define EL_DYNABOMB_INCREASE_NUMBER 64 #define EL_DYNABOMB_INCREASE_SIZE 65 #define EL_DYNABOMB_INCREASE_POWER 66 #define EL_SOKOBAN_OBJECT 67 #define EL_SOKOBAN_FIELD_EMPTY 68 #define EL_SOKOBAN_FIELD_FULL 69 #define EL_BD_BUTTERFLY_RIGHT 70 #define EL_BD_BUTTERFLY_UP 71 #define EL_BD_BUTTERFLY_LEFT 72 #define EL_BD_BUTTERFLY_DOWN 73 #define EL_BD_FIREFLY_RIGHT 74 #define EL_BD_FIREFLY_UP 75 #define EL_BD_FIREFLY_LEFT 76 #define EL_BD_FIREFLY_DOWN 77 #define EL_BD_BUTTERFLY_1 EL_BD_BUTTERFLY_DOWN #define EL_BD_BUTTERFLY_2 EL_BD_BUTTERFLY_LEFT #define EL_BD_BUTTERFLY_3 EL_BD_BUTTERFLY_UP #define EL_BD_BUTTERFLY_4 EL_BD_BUTTERFLY_RIGHT #define EL_BD_FIREFLY_1 EL_BD_FIREFLY_LEFT #define EL_BD_FIREFLY_2 EL_BD_FIREFLY_DOWN #define EL_BD_FIREFLY_3 EL_BD_FIREFLY_RIGHT #define EL_BD_FIREFLY_4 EL_BD_FIREFLY_UP #define EL_BD_BUTTERFLY 78 #define EL_BD_FIREFLY 79 #define EL_PLAYER_1 80 #define EL_PLAYER_2 81 #define EL_PLAYER_3 82 #define EL_PLAYER_4 83 #define EL_BUG_RIGHT 84 #define EL_BUG_UP 85 #define EL_BUG_LEFT 86 #define EL_BUG_DOWN 87 #define EL_SPACESHIP_RIGHT 88 #define EL_SPACESHIP_UP 89 #define EL_SPACESHIP_LEFT 90 #define EL_SPACESHIP_DOWN 91 #define EL_PACMAN_RIGHT 92 #define EL_PACMAN_UP 93 #define EL_PACMAN_LEFT 94 #define EL_PACMAN_DOWN 95 #define EL_EMERALD_RED 96 #define EL_EMERALD_PURPLE 97 #define EL_WALL_EMERALD_RED 98 #define EL_WALL_EMERALD_PURPLE 99 #define EL_ACID_POOL_TOPLEFT 100 #define EL_ACID_POOL_TOPRIGHT 101 #define EL_ACID_POOL_BOTTOMLEFT 102 #define EL_ACID_POOL_BOTTOM 103 #define EL_ACID_POOL_BOTTOMRIGHT 104 #define EL_BD_WALL 105 #define EL_BD_ROCK 106 #define EL_EXIT_OPEN 107 #define EL_BLACK_ORB 108 #define EL_AMOEBA_TO_DIAMOND 109 #define EL_MOLE 110 #define EL_PENGUIN 111 #define EL_SATELLITE 112 #define EL_ARROW_LEFT 113 #define EL_ARROW_RIGHT 114 #define EL_ARROW_UP 115 #define EL_ARROW_DOWN 116 #define EL_PIG 117 #define EL_DRAGON 118 #define EL_EM_KEY_1_FILE_OBSOLETE 119 /* obsolete; now EL_EM_KEY_1 */ #define EL_CHAR_START 120 #define EL_CHAR_ASCII0 (EL_CHAR_START - 32) #define EL_CHAR_ASCII0_START (EL_CHAR_ASCII0 + 32) #include "conf_chr.h" /* include auto-generated data structure definitions */ #define EL_CHAR_ASCII0_END (EL_CHAR_ASCII0 + 111) #define EL_CHAR_END (EL_CHAR_START + 79) #define EL_CHAR(c) (EL_CHAR_ASCII0 + MAP_FONT_ASCII(c)) #define EL_EXPANDABLE_WALL_HORIZONTAL 200 #define EL_EXPANDABLE_WALL_VERTICAL 201 #define EL_EXPANDABLE_WALL_ANY 202 #define EL_EM_GATE_1 203 #define EL_EM_GATE_2 204 #define EL_EM_GATE_3 205 #define EL_EM_GATE_4 206 #define EL_EM_KEY_2_FILE_OBSOLETE 207 /* obsolete; now EL_EM_KEY_2 */ #define EL_EM_KEY_3_FILE_OBSOLETE 208 /* obsolete; now EL_EM_KEY_3 */ #define EL_EM_KEY_4_FILE_OBSOLETE 209 /* obsolete; now EL_EM_KEY_4 */ #define EL_SP_START 210 #define EL_SP_EMPTY_SPACE (EL_SP_START + 0) #define EL_SP_EMPTY EL_SP_EMPTY_SPACE #define EL_SP_ZONK (EL_SP_START + 1) #define EL_SP_BASE (EL_SP_START + 2) #define EL_SP_MURPHY (EL_SP_START + 3) #define EL_SP_INFOTRON (EL_SP_START + 4) #define EL_SP_CHIP_SINGLE (EL_SP_START + 5) #define EL_SP_HARDWARE_GRAY (EL_SP_START + 6) #define EL_SP_EXIT_CLOSED (EL_SP_START + 7) #define EL_SP_DISK_ORANGE (EL_SP_START + 8) #define EL_SP_PORT_RIGHT (EL_SP_START + 9) #define EL_SP_PORT_DOWN (EL_SP_START + 10) #define EL_SP_PORT_LEFT (EL_SP_START + 11) #define EL_SP_PORT_UP (EL_SP_START + 12) #define EL_SP_GRAVITY_PORT_RIGHT (EL_SP_START + 13) #define EL_SP_GRAVITY_PORT_DOWN (EL_SP_START + 14) #define EL_SP_GRAVITY_PORT_LEFT (EL_SP_START + 15) #define EL_SP_GRAVITY_PORT_UP (EL_SP_START + 16) #define EL_SP_SNIKSNAK (EL_SP_START + 17) #define EL_SP_DISK_YELLOW (EL_SP_START + 18) #define EL_SP_TERMINAL (EL_SP_START + 19) #define EL_SP_DISK_RED (EL_SP_START + 20) #define EL_SP_PORT_VERTICAL (EL_SP_START + 21) #define EL_SP_PORT_HORIZONTAL (EL_SP_START + 22) #define EL_SP_PORT_ANY (EL_SP_START + 23) #define EL_SP_ELECTRON (EL_SP_START + 24) #define EL_SP_BUGGY_BASE (EL_SP_START + 25) #define EL_SP_CHIP_LEFT (EL_SP_START + 26) #define EL_SP_CHIP_RIGHT (EL_SP_START + 27) #define EL_SP_HARDWARE_BASE_1 (EL_SP_START + 28) #define EL_SP_HARDWARE_GREEN (EL_SP_START + 29) #define EL_SP_HARDWARE_BLUE (EL_SP_START + 30) #define EL_SP_HARDWARE_RED (EL_SP_START + 31) #define EL_SP_HARDWARE_YELLOW (EL_SP_START + 32) #define EL_SP_HARDWARE_BASE_2 (EL_SP_START + 33) #define EL_SP_HARDWARE_BASE_3 (EL_SP_START + 34) #define EL_SP_HARDWARE_BASE_4 (EL_SP_START + 35) #define EL_SP_HARDWARE_BASE_5 (EL_SP_START + 36) #define EL_SP_HARDWARE_BASE_6 (EL_SP_START + 37) #define EL_SP_CHIP_TOP (EL_SP_START + 38) #define EL_SP_CHIP_BOTTOM (EL_SP_START + 39) #define EL_SP_END (EL_SP_START + 39) #define EL_EM_GATE_1_GRAY 250 #define EL_EM_GATE_2_GRAY 251 #define EL_EM_GATE_3_GRAY 252 #define EL_EM_GATE_4_GRAY 253 #define EL_EM_DYNAMITE 254 #define EL_EM_DYNAMITE_ACTIVE 255 #define EL_PEARL 256 #define EL_CRYSTAL 257 #define EL_WALL_PEARL 258 #define EL_WALL_CRYSTAL 259 #define EL_DC_GATE_WHITE 260 #define EL_DC_GATE_WHITE_GRAY 261 #define EL_DC_KEY_WHITE 262 #define EL_SHIELD_NORMAL 263 #define EL_EXTRA_TIME 264 #define EL_SWITCHGATE_OPEN 265 #define EL_SWITCHGATE_CLOSED 266 #define EL_SWITCHGATE_SWITCH_UP 267 #define EL_SWITCHGATE_SWITCH_DOWN 268 #define EL_UNUSED_269 269 #define EL_UNUSED_270 270 #define EL_CONVEYOR_BELT_1_LEFT 271 #define EL_CONVEYOR_BELT_1_MIDDLE 272 #define EL_CONVEYOR_BELT_1_RIGHT 273 #define EL_CONVEYOR_BELT_1_SWITCH_LEFT 274 #define EL_CONVEYOR_BELT_1_SWITCH_MIDDLE 275 #define EL_CONVEYOR_BELT_1_SWITCH_RIGHT 276 #define EL_CONVEYOR_BELT_2_LEFT 277 #define EL_CONVEYOR_BELT_2_MIDDLE 278 #define EL_CONVEYOR_BELT_2_RIGHT 279 #define EL_CONVEYOR_BELT_2_SWITCH_LEFT 280 #define EL_CONVEYOR_BELT_2_SWITCH_MIDDLE 281 #define EL_CONVEYOR_BELT_2_SWITCH_RIGHT 282 #define EL_CONVEYOR_BELT_3_LEFT 283 #define EL_CONVEYOR_BELT_3_MIDDLE 284 #define EL_CONVEYOR_BELT_3_RIGHT 285 #define EL_CONVEYOR_BELT_3_SWITCH_LEFT 286 #define EL_CONVEYOR_BELT_3_SWITCH_MIDDLE 287 #define EL_CONVEYOR_BELT_3_SWITCH_RIGHT 288 #define EL_CONVEYOR_BELT_4_LEFT 289 #define EL_CONVEYOR_BELT_4_MIDDLE 290 #define EL_CONVEYOR_BELT_4_RIGHT 291 #define EL_CONVEYOR_BELT_4_SWITCH_LEFT 292 #define EL_CONVEYOR_BELT_4_SWITCH_MIDDLE 293 #define EL_CONVEYOR_BELT_4_SWITCH_RIGHT 294 #define EL_LANDMINE 295 #define EL_ENVELOPE_OBSOLETE 296 /* obsolete; now EL_ENVELOPE_1 */ #define EL_LIGHT_SWITCH 297 #define EL_LIGHT_SWITCH_ACTIVE 298 #define EL_SIGN_EXCLAMATION 299 #define EL_SIGN_RADIOACTIVITY 300 #define EL_SIGN_STOP 301 #define EL_SIGN_WHEELCHAIR 302 #define EL_SIGN_PARKING 303 #define EL_SIGN_NO_ENTRY 304 #define EL_SIGN_UNUSED_1 305 #define EL_SIGN_GIVE_WAY 306 #define EL_SIGN_ENTRY_FORBIDDEN 307 #define EL_SIGN_EMERGENCY_EXIT 308 #define EL_SIGN_YIN_YANG 309 #define EL_SIGN_UNUSED_2 310 #define EL_MOLE_LEFT 311 #define EL_MOLE_RIGHT 312 #define EL_MOLE_UP 313 #define EL_MOLE_DOWN 314 #define EL_STEELWALL_SLIPPERY 315 #define EL_INVISIBLE_SAND 316 #define EL_DX_UNKNOWN_15 317 #define EL_DX_UNKNOWN_42 318 #define EL_UNUSED_319 319 #define EL_UNUSED_320 320 #define EL_SHIELD_DEADLY 321 #define EL_TIMEGATE_OPEN 322 #define EL_TIMEGATE_CLOSED 323 #define EL_TIMEGATE_SWITCH_ACTIVE 324 #define EL_TIMEGATE_SWITCH 325 #define EL_BALLOON 326 #define EL_BALLOON_SWITCH_LEFT 327 #define EL_BALLOON_SWITCH_RIGHT 328 #define EL_BALLOON_SWITCH_UP 329 #define EL_BALLOON_SWITCH_DOWN 330 #define EL_BALLOON_SWITCH_ANY 331 #define EL_EMC_STEELWALL_1 332 #define EL_EMC_STEELWALL_2 333 #define EL_EMC_STEELWALL_3 334 #define EL_EMC_STEELWALL_4 335 #define EL_EMC_WALL_1 336 #define EL_EMC_WALL_2 337 #define EL_EMC_WALL_3 338 #define EL_EMC_WALL_4 339 #define EL_EMC_WALL_5 340 #define EL_EMC_WALL_6 341 #define EL_EMC_WALL_7 342 #define EL_EMC_WALL_8 343 #define EL_TUBE_ANY 344 #define EL_TUBE_VERTICAL 345 #define EL_TUBE_HORIZONTAL 346 #define EL_TUBE_VERTICAL_LEFT 347 #define EL_TUBE_VERTICAL_RIGHT 348 #define EL_TUBE_HORIZONTAL_UP 349 #define EL_TUBE_HORIZONTAL_DOWN 350 #define EL_TUBE_LEFT_UP 351 #define EL_TUBE_LEFT_DOWN 352 #define EL_TUBE_RIGHT_UP 353 #define EL_TUBE_RIGHT_DOWN 354 #define EL_SPRING 355 #define EL_TRAP 356 #define EL_DX_SUPABOMB 357 #define EL_UNUSED_358 358 #define EL_UNUSED_359 359 /* ---------- begin of custom elements section ----------------------------- */ #define EL_CUSTOM_START 360 #include "conf_cus.h" /* include auto-generated data structure definitions */ #define NUM_CUSTOM_ELEMENTS 256 #define EL_CUSTOM_END 615 /* ---------- end of custom elements section ------------------------------- */ #define EL_EM_KEY_1 616 #define EL_EM_KEY_2 617 #define EL_EM_KEY_3 618 #define EL_EM_KEY_4 619 #define EL_ENVELOPE_1 620 #define EL_ENVELOPE_2 621 #define EL_ENVELOPE_3 622 #define EL_ENVELOPE_4 623 /* ---------- begin of group elements section ------------------------------ */ #define EL_GROUP_START 624 #include "conf_grp.h" /* include auto-generated data structure definitions */ #define NUM_GROUP_ELEMENTS 32 #define EL_GROUP_END 655 /* ---------- end of custom elements section ------------------------------- */ #define EL_UNKNOWN 656 #define EL_TRIGGER_ELEMENT 657 #define EL_TRIGGER_PLAYER 658 /* SP style elements */ #define EL_SP_GRAVITY_ON_PORT_RIGHT 659 #define EL_SP_GRAVITY_ON_PORT_DOWN 660 #define EL_SP_GRAVITY_ON_PORT_LEFT 661 #define EL_SP_GRAVITY_ON_PORT_UP 662 #define EL_SP_GRAVITY_OFF_PORT_RIGHT 663 #define EL_SP_GRAVITY_OFF_PORT_DOWN 664 #define EL_SP_GRAVITY_OFF_PORT_LEFT 665 #define EL_SP_GRAVITY_OFF_PORT_UP 666 /* EMC style elements */ #define EL_BALLOON_SWITCH_NONE 667 #define EL_EMC_GATE_5 668 #define EL_EMC_GATE_6 669 #define EL_EMC_GATE_7 670 #define EL_EMC_GATE_8 671 #define EL_EMC_GATE_5_GRAY 672 #define EL_EMC_GATE_6_GRAY 673 #define EL_EMC_GATE_7_GRAY 674 #define EL_EMC_GATE_8_GRAY 675 #define EL_EMC_KEY_5 676 #define EL_EMC_KEY_6 677 #define EL_EMC_KEY_7 678 #define EL_EMC_KEY_8 679 #define EL_EMC_ANDROID 680 #define EL_EMC_GRASS 681 #define EL_EMC_MAGIC_BALL 682 #define EL_EMC_MAGIC_BALL_ACTIVE 683 #define EL_EMC_MAGIC_BALL_SWITCH 684 #define EL_EMC_MAGIC_BALL_SWITCH_ACTIVE 685 #define EL_EMC_SPRING_BUMPER 686 #define EL_EMC_PLANT 687 #define EL_EMC_LENSES 688 #define EL_EMC_MAGNIFIER 689 #define EL_EMC_WALL_9 690 #define EL_EMC_WALL_10 691 #define EL_EMC_WALL_11 692 #define EL_EMC_WALL_12 693 #define EL_EMC_WALL_13 694 #define EL_EMC_WALL_14 695 #define EL_EMC_WALL_15 696 #define EL_EMC_WALL_16 697 #define EL_EMC_WALL_SLIPPERY_1 698 #define EL_EMC_WALL_SLIPPERY_2 699 #define EL_EMC_WALL_SLIPPERY_3 700 #define EL_EMC_WALL_SLIPPERY_4 701 #define EL_EMC_FAKE_GRASS 702 #define EL_EMC_FAKE_ACID 703 #define EL_EMC_DRIPPER 704 #define EL_TRIGGER_CE_VALUE 705 #define EL_TRIGGER_CE_SCORE 706 #define EL_CURRENT_CE_VALUE 707 #define EL_CURRENT_CE_SCORE 708 #define EL_YAMYAM_LEFT 709 #define EL_YAMYAM_RIGHT 710 #define EL_YAMYAM_UP 711 #define EL_YAMYAM_DOWN 712 #define EL_BD_EXPANDABLE_WALL 713 #define EL_PREV_CE_8 714 #define EL_PREV_CE_7 715 #define EL_PREV_CE_6 716 #define EL_PREV_CE_5 717 #define EL_PREV_CE_4 718 #define EL_PREV_CE_3 719 #define EL_PREV_CE_2 720 #define EL_PREV_CE_1 721 #define EL_SELF 722 #define EL_NEXT_CE_1 723 #define EL_NEXT_CE_2 724 #define EL_NEXT_CE_3 725 #define EL_NEXT_CE_4 726 #define EL_NEXT_CE_5 727 #define EL_NEXT_CE_6 728 #define EL_NEXT_CE_7 729 #define EL_NEXT_CE_8 730 #define EL_ANY_ELEMENT 731 #define EL_STEEL_CHAR_START 732 #define EL_STEEL_CHAR_ASCII0 (EL_STEEL_CHAR_START - 32) #define EL_STEEL_CHAR_ASCII0_START (EL_STEEL_CHAR_ASCII0 + 32) /* (auto-generated data structure definitions included with normal chars) */ #define EL_STEEL_CHAR_ASCII0_END (EL_STEEL_CHAR_ASCII0 + 111) #define EL_STEEL_CHAR_END (EL_STEEL_CHAR_START + 79) #define EL_STEEL_CHAR(c) (EL_STEEL_CHAR_ASCII0+MAP_FONT_ASCII(c)) #define EL_SPERMS 812 #define EL_BULLET 813 #define EL_HEART 814 #define EL_CROSS 815 #define EL_FRANKIE 816 #define EL_SIGN_SPERMS 817 #define EL_SIGN_BULLET 818 #define EL_SIGN_HEART 819 #define EL_SIGN_CROSS 820 #define EL_SIGN_FRANKIE 821 #define EL_STEEL_EXIT_CLOSED 822 #define EL_STEEL_EXIT_OPEN 823 #define EL_DC_STEELWALL_1_LEFT 824 #define EL_DC_STEELWALL_1_RIGHT 825 #define EL_DC_STEELWALL_1_TOP 826 #define EL_DC_STEELWALL_1_BOTTOM 827 #define EL_DC_STEELWALL_1_HORIZONTAL 828 #define EL_DC_STEELWALL_1_VERTICAL 829 #define EL_DC_STEELWALL_1_TOPLEFT 830 #define EL_DC_STEELWALL_1_TOPRIGHT 831 #define EL_DC_STEELWALL_1_BOTTOMLEFT 832 #define EL_DC_STEELWALL_1_BOTTOMRIGHT 833 #define EL_DC_STEELWALL_1_TOPLEFT_2 834 #define EL_DC_STEELWALL_1_TOPRIGHT_2 835 #define EL_DC_STEELWALL_1_BOTTOMLEFT_2 836 #define EL_DC_STEELWALL_1_BOTTOMRIGHT_2 837 #define EL_DC_STEELWALL_2_LEFT 838 #define EL_DC_STEELWALL_2_RIGHT 839 #define EL_DC_STEELWALL_2_TOP 840 #define EL_DC_STEELWALL_2_BOTTOM 841 #define EL_DC_STEELWALL_2_HORIZONTAL 842 #define EL_DC_STEELWALL_2_VERTICAL 843 #define EL_DC_STEELWALL_2_MIDDLE 844 #define EL_DC_STEELWALL_2_SINGLE 845 #define EL_DC_SWITCHGATE_SWITCH_UP 846 #define EL_DC_SWITCHGATE_SWITCH_DOWN 847 #define EL_DC_TIMEGATE_SWITCH 848 #define EL_DC_TIMEGATE_SWITCH_ACTIVE 849 #define EL_DC_LANDMINE 850 #define EL_EXPANDABLE_STEELWALL 851 #define EL_EXPANDABLE_STEELWALL_HORIZONTAL 852 #define EL_EXPANDABLE_STEELWALL_VERTICAL 853 #define EL_EXPANDABLE_STEELWALL_ANY 854 #define EL_EM_EXIT_CLOSED 855 #define EL_EM_EXIT_OPEN 856 #define EL_EM_STEEL_EXIT_CLOSED 857 #define EL_EM_STEEL_EXIT_OPEN 858 #define EL_DC_GATE_FAKE_GRAY 859 #define EL_DC_MAGIC_WALL 860 #define EL_QUICKSAND_FAST_EMPTY 861 #define EL_QUICKSAND_FAST_FULL 862 #define EL_FROM_LEVEL_TEMPLATE 863 #define NUM_FILE_ELEMENTS 864 /* "real" (and therefore drawable) runtime elements */ #define EL_FIRST_RUNTIME_REAL NUM_FILE_ELEMENTS #define EL_DYNABOMB_PLAYER_1_ACTIVE (EL_FIRST_RUNTIME_REAL + 0) #define EL_DYNABOMB_PLAYER_2_ACTIVE (EL_FIRST_RUNTIME_REAL + 1) #define EL_DYNABOMB_PLAYER_3_ACTIVE (EL_FIRST_RUNTIME_REAL + 2) #define EL_DYNABOMB_PLAYER_4_ACTIVE (EL_FIRST_RUNTIME_REAL + 3) #define EL_SP_DISK_RED_ACTIVE (EL_FIRST_RUNTIME_REAL + 4) #define EL_SWITCHGATE_OPENING (EL_FIRST_RUNTIME_REAL + 5) #define EL_SWITCHGATE_CLOSING (EL_FIRST_RUNTIME_REAL + 6) #define EL_TIMEGATE_OPENING (EL_FIRST_RUNTIME_REAL + 7) #define EL_TIMEGATE_CLOSING (EL_FIRST_RUNTIME_REAL + 8) #define EL_PEARL_BREAKING (EL_FIRST_RUNTIME_REAL + 9) #define EL_TRAP_ACTIVE (EL_FIRST_RUNTIME_REAL + 10) #define EL_INVISIBLE_STEELWALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 11) #define EL_INVISIBLE_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 12) #define EL_INVISIBLE_SAND_ACTIVE (EL_FIRST_RUNTIME_REAL + 13) #define EL_CONVEYOR_BELT_1_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 14) #define EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 15) #define EL_CONVEYOR_BELT_1_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 16) #define EL_CONVEYOR_BELT_2_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 17) #define EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 18) #define EL_CONVEYOR_BELT_2_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 19) #define EL_CONVEYOR_BELT_3_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 20) #define EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 21) #define EL_CONVEYOR_BELT_3_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 22) #define EL_CONVEYOR_BELT_4_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 23) #define EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 24) #define EL_CONVEYOR_BELT_4_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 25) #define EL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 26) #define EL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 27) #define EL_STEEL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 28) #define EL_STEEL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 29) #define EL_EM_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 30) #define EL_EM_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 31) #define EL_EM_STEEL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 32) #define EL_EM_STEEL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 33) #define EL_SP_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 34) #define EL_SP_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 35) #define EL_SP_EXIT_OPEN (EL_FIRST_RUNTIME_REAL + 36) #define EL_SP_TERMINAL_ACTIVE (EL_FIRST_RUNTIME_REAL + 37) #define EL_SP_BUGGY_BASE_ACTIVATING (EL_FIRST_RUNTIME_REAL + 38) #define EL_SP_BUGGY_BASE_ACTIVE (EL_FIRST_RUNTIME_REAL + 39) #define EL_SP_MURPHY_CLONE (EL_FIRST_RUNTIME_REAL + 40) #define EL_AMOEBA_DROPPING (EL_FIRST_RUNTIME_REAL + 41) #define EL_QUICKSAND_EMPTYING (EL_FIRST_RUNTIME_REAL + 42) #define EL_QUICKSAND_FAST_EMPTYING (EL_FIRST_RUNTIME_REAL + 43) #define EL_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 44) #define EL_BD_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 45) #define EL_DC_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 46) #define EL_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 47) #define EL_BD_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 48) #define EL_DC_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 49) #define EL_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 50) #define EL_BD_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 51) #define EL_DC_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 52) #define EL_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 53) #define EL_BD_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 54) #define EL_DC_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 55) #define EL_EMC_FAKE_GRASS_ACTIVE (EL_FIRST_RUNTIME_REAL + 56) #define EL_GATE_1_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 57) #define EL_GATE_2_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 58) #define EL_GATE_3_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 59) #define EL_GATE_4_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 60) #define EL_EM_GATE_1_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 61) #define EL_EM_GATE_2_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 62) #define EL_EM_GATE_3_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 63) #define EL_EM_GATE_4_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 64) #define EL_EMC_GATE_5_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 65) #define EL_EMC_GATE_6_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 66) #define EL_EMC_GATE_7_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 67) #define EL_EMC_GATE_8_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 68) #define EL_DC_GATE_WHITE_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 69) #define EL_EMC_DRIPPER_ACTIVE (EL_FIRST_RUNTIME_REAL + 70) #define EL_EMC_SPRING_BUMPER_ACTIVE (EL_FIRST_RUNTIME_REAL + 71) #define NUM_DRAWABLE_ELEMENTS (EL_FIRST_RUNTIME_REAL + 72) /* "unreal" (and therefore not drawable) runtime elements */ #define EL_FIRST_RUNTIME_UNREAL (NUM_DRAWABLE_ELEMENTS) #define EL_BLOCKED (EL_FIRST_RUNTIME_UNREAL + 0) #define EL_EXPLOSION (EL_FIRST_RUNTIME_UNREAL + 1) #define EL_NUT_BREAKING (EL_FIRST_RUNTIME_UNREAL + 2) #define EL_DIAMOND_BREAKING (EL_FIRST_RUNTIME_UNREAL + 3) #define EL_ACID_SPLASH_LEFT (EL_FIRST_RUNTIME_UNREAL + 4) #define EL_ACID_SPLASH_RIGHT (EL_FIRST_RUNTIME_UNREAL + 5) #define EL_AMOEBA_GROWING (EL_FIRST_RUNTIME_UNREAL + 6) #define EL_AMOEBA_SHRINKING (EL_FIRST_RUNTIME_UNREAL + 7) #define EL_EXPANDABLE_WALL_GROWING (EL_FIRST_RUNTIME_UNREAL + 8) #define EL_EXPANDABLE_STEELWALL_GROWING (EL_FIRST_RUNTIME_UNREAL + 9) #define EL_FLAMES (EL_FIRST_RUNTIME_UNREAL + 10) #define EL_PLAYER_IS_LEAVING (EL_FIRST_RUNTIME_UNREAL + 11) #define EL_PLAYER_IS_EXPLODING_1 (EL_FIRST_RUNTIME_UNREAL + 12) #define EL_PLAYER_IS_EXPLODING_2 (EL_FIRST_RUNTIME_UNREAL + 13) #define EL_PLAYER_IS_EXPLODING_3 (EL_FIRST_RUNTIME_UNREAL + 14) #define EL_PLAYER_IS_EXPLODING_4 (EL_FIRST_RUNTIME_UNREAL + 15) #define EL_QUICKSAND_FILLING (EL_FIRST_RUNTIME_UNREAL + 16) #define EL_QUICKSAND_FAST_FILLING (EL_FIRST_RUNTIME_UNREAL + 17) #define EL_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 18) #define EL_BD_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 19) #define EL_DC_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 20) #define EL_ELEMENT_SNAPPING (EL_FIRST_RUNTIME_UNREAL + 21) #define EL_DIAGONAL_SHRINKING (EL_FIRST_RUNTIME_UNREAL + 22) #define EL_DIAGONAL_GROWING (EL_FIRST_RUNTIME_UNREAL + 23) #define NUM_RUNTIME_ELEMENTS (EL_FIRST_RUNTIME_UNREAL + 24) /* dummy elements (never used as game elements, only used as graphics) */ #define EL_FIRST_DUMMY NUM_RUNTIME_ELEMENTS #define EL_STEELWALL_TOPLEFT (EL_FIRST_DUMMY + 0) #define EL_STEELWALL_TOPRIGHT (EL_FIRST_DUMMY + 1) #define EL_STEELWALL_BOTTOMLEFT (EL_FIRST_DUMMY + 2) #define EL_STEELWALL_BOTTOMRIGHT (EL_FIRST_DUMMY + 3) #define EL_STEELWALL_HORIZONTAL (EL_FIRST_DUMMY + 4) #define EL_STEELWALL_VERTICAL (EL_FIRST_DUMMY + 5) #define EL_INVISIBLE_STEELWALL_TOPLEFT (EL_FIRST_DUMMY + 6) #define EL_INVISIBLE_STEELWALL_TOPRIGHT (EL_FIRST_DUMMY + 7) #define EL_INVISIBLE_STEELWALL_BOTTOMLEFT (EL_FIRST_DUMMY + 8) #define EL_INVISIBLE_STEELWALL_BOTTOMRIGHT (EL_FIRST_DUMMY + 9) #define EL_INVISIBLE_STEELWALL_HORIZONTAL (EL_FIRST_DUMMY + 10) #define EL_INVISIBLE_STEELWALL_VERTICAL (EL_FIRST_DUMMY + 11) #define EL_DYNABOMB (EL_FIRST_DUMMY + 12) #define EL_DYNABOMB_ACTIVE (EL_FIRST_DUMMY + 13) #define EL_DYNABOMB_PLAYER_1 (EL_FIRST_DUMMY + 14) #define EL_DYNABOMB_PLAYER_2 (EL_FIRST_DUMMY + 15) #define EL_DYNABOMB_PLAYER_3 (EL_FIRST_DUMMY + 16) #define EL_DYNABOMB_PLAYER_4 (EL_FIRST_DUMMY + 17) #define EL_SHIELD_NORMAL_ACTIVE (EL_FIRST_DUMMY + 18) #define EL_SHIELD_DEADLY_ACTIVE (EL_FIRST_DUMMY + 19) #define EL_AMOEBA (EL_FIRST_DUMMY + 20) #define EL_DEFAULT (EL_FIRST_DUMMY + 21) #define EL_BD_DEFAULT (EL_FIRST_DUMMY + 22) #define EL_SP_DEFAULT (EL_FIRST_DUMMY + 23) #define EL_SB_DEFAULT (EL_FIRST_DUMMY + 24) #define EL_GRAPHIC_1 (EL_FIRST_DUMMY + 25) #define EL_GRAPHIC_2 (EL_FIRST_DUMMY + 26) #define EL_GRAPHIC_3 (EL_FIRST_DUMMY + 27) #define EL_GRAPHIC_4 (EL_FIRST_DUMMY + 28) #define EL_GRAPHIC_5 (EL_FIRST_DUMMY + 29) #define EL_GRAPHIC_6 (EL_FIRST_DUMMY + 30) #define EL_GRAPHIC_7 (EL_FIRST_DUMMY + 31) #define EL_GRAPHIC_8 (EL_FIRST_DUMMY + 32) /* internal elements (only used for internal purposes like copying) */ #define EL_FIRST_INTERNAL (EL_FIRST_DUMMY + 33) #define EL_INTERNAL_CLIPBOARD_CUSTOM (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_CLIPBOARD_CHANGE (EL_FIRST_INTERNAL + 1) #define EL_INTERNAL_CLIPBOARD_GROUP (EL_FIRST_INTERNAL + 2) #define EL_INTERNAL_DUMMY (EL_FIRST_INTERNAL + 3) #define EL_INTERNAL_CASCADE_BD (EL_FIRST_INTERNAL + 4) #define EL_INTERNAL_CASCADE_BD_ACTIVE (EL_FIRST_INTERNAL + 5) #define EL_INTERNAL_CASCADE_EM (EL_FIRST_INTERNAL + 6) #define EL_INTERNAL_CASCADE_EM_ACTIVE (EL_FIRST_INTERNAL + 7) #define EL_INTERNAL_CASCADE_EMC (EL_FIRST_INTERNAL + 8) #define EL_INTERNAL_CASCADE_EMC_ACTIVE (EL_FIRST_INTERNAL + 9) #define EL_INTERNAL_CASCADE_RND (EL_FIRST_INTERNAL + 10) #define EL_INTERNAL_CASCADE_RND_ACTIVE (EL_FIRST_INTERNAL + 11) #define EL_INTERNAL_CASCADE_SB (EL_FIRST_INTERNAL + 12) #define EL_INTERNAL_CASCADE_SB_ACTIVE (EL_FIRST_INTERNAL + 13) #define EL_INTERNAL_CASCADE_SP (EL_FIRST_INTERNAL + 14) #define EL_INTERNAL_CASCADE_SP_ACTIVE (EL_FIRST_INTERNAL + 15) #define EL_INTERNAL_CASCADE_DC (EL_FIRST_INTERNAL + 16) #define EL_INTERNAL_CASCADE_DC_ACTIVE (EL_FIRST_INTERNAL + 17) #define EL_INTERNAL_CASCADE_DX (EL_FIRST_INTERNAL + 18) #define EL_INTERNAL_CASCADE_DX_ACTIVE (EL_FIRST_INTERNAL + 19) #define EL_INTERNAL_CASCADE_CHARS (EL_FIRST_INTERNAL + 20) #define EL_INTERNAL_CASCADE_CHARS_ACTIVE (EL_FIRST_INTERNAL + 21) #define EL_INTERNAL_CASCADE_STEEL_CHARS (EL_FIRST_INTERNAL + 22) #define EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE (EL_FIRST_INTERNAL + 23) #define EL_INTERNAL_CASCADE_CE (EL_FIRST_INTERNAL + 24) #define EL_INTERNAL_CASCADE_CE_ACTIVE (EL_FIRST_INTERNAL + 25) #define EL_INTERNAL_CASCADE_GE (EL_FIRST_INTERNAL + 26) #define EL_INTERNAL_CASCADE_GE_ACTIVE (EL_FIRST_INTERNAL + 27) #define EL_INTERNAL_CASCADE_REF (EL_FIRST_INTERNAL + 28) #define EL_INTERNAL_CASCADE_REF_ACTIVE (EL_FIRST_INTERNAL + 29) #define EL_INTERNAL_CASCADE_USER (EL_FIRST_INTERNAL + 30) #define EL_INTERNAL_CASCADE_USER_ACTIVE (EL_FIRST_INTERNAL + 31) #define EL_INTERNAL_CASCADE_DYNAMIC (EL_FIRST_INTERNAL + 32) #define EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE (EL_FIRST_INTERNAL + 33) #define EL_INTERNAL_CLIPBOARD_START (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_CLIPBOARD_END (EL_FIRST_INTERNAL + 2) #define EL_INTERNAL_START (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_END (EL_FIRST_INTERNAL + 33) #define MAX_NUM_ELEMENTS (EL_FIRST_INTERNAL + 34) /* values for graphics/sounds action types */ #define ACTION_DEFAULT 0 #define ACTION_WAITING 1 #define ACTION_FALLING 2 #define ACTION_MOVING 3 #define ACTION_DIGGING 4 #define ACTION_SNAPPING 5 #define ACTION_COLLECTING 6 #define ACTION_DROPPING 7 #define ACTION_PUSHING 8 #define ACTION_WALKING 9 #define ACTION_PASSING 10 #define ACTION_IMPACT 11 #define ACTION_BREAKING 12 #define ACTION_ACTIVATING 13 #define ACTION_DEACTIVATING 14 #define ACTION_OPENING 15 #define ACTION_CLOSING 16 #define ACTION_ATTACKING 17 #define ACTION_GROWING 18 #define ACTION_SHRINKING 19 #define ACTION_ACTIVE 20 #define ACTION_FILLING 21 #define ACTION_EMPTYING 22 #define ACTION_CHANGING 23 #define ACTION_EXPLODING 24 #define ACTION_BORING 25 #define ACTION_BORING_1 26 #define ACTION_BORING_2 27 #define ACTION_BORING_3 28 #define ACTION_BORING_4 29 #define ACTION_BORING_5 30 #define ACTION_BORING_6 31 #define ACTION_BORING_7 32 #define ACTION_BORING_8 33 #define ACTION_BORING_9 34 #define ACTION_BORING_10 35 #define ACTION_SLEEPING 36 #define ACTION_SLEEPING_1 37 #define ACTION_SLEEPING_2 38 #define ACTION_SLEEPING_3 39 #define ACTION_AWAKENING 40 #define ACTION_DYING 41 #define ACTION_TURNING 42 #define ACTION_TURNING_FROM_LEFT 43 #define ACTION_TURNING_FROM_RIGHT 44 #define ACTION_TURNING_FROM_UP 45 #define ACTION_TURNING_FROM_DOWN 46 #define ACTION_SMASHED_BY_ROCK 47 #define ACTION_SMASHED_BY_SPRING 48 #define ACTION_EATING 49 #define ACTION_TWINKLING 50 #define ACTION_SPLASHING 51 #define ACTION_PAGE_1 52 #define ACTION_PAGE_2 53 #define ACTION_PAGE_3 54 #define ACTION_PAGE_4 55 #define ACTION_PAGE_5 56 #define ACTION_PAGE_6 57 #define ACTION_PAGE_7 58 #define ACTION_PAGE_8 59 #define ACTION_PAGE_9 60 #define ACTION_PAGE_10 61 #define ACTION_PAGE_11 62 #define ACTION_PAGE_12 63 #define ACTION_PAGE_13 64 #define ACTION_PAGE_14 65 #define ACTION_PAGE_15 66 #define ACTION_PAGE_16 67 #define ACTION_PAGE_17 68 #define ACTION_PAGE_18 69 #define ACTION_PAGE_19 70 #define ACTION_PAGE_20 71 #define ACTION_PAGE_21 72 #define ACTION_PAGE_22 73 #define ACTION_PAGE_23 74 #define ACTION_PAGE_24 75 #define ACTION_PAGE_25 76 #define ACTION_PAGE_26 77 #define ACTION_PAGE_27 78 #define ACTION_PAGE_28 79 #define ACTION_PAGE_29 80 #define ACTION_PAGE_30 81 #define ACTION_PAGE_31 82 #define ACTION_PAGE_32 83 #define ACTION_OTHER 84 #define NUM_ACTIONS 85 #define ACTION_BORING_LAST ACTION_BORING_10 #define ACTION_SLEEPING_LAST ACTION_SLEEPING_3 /* values for special image configuration suffixes (must match game mode) */ #define GFX_SPECIAL_ARG_DEFAULT 0 #define GFX_SPECIAL_ARG_LOADING 1 #define GFX_SPECIAL_ARG_TITLE_INITIAL 2 #define GFX_SPECIAL_ARG_TITLE 3 #define GFX_SPECIAL_ARG_MAIN 4 #define GFX_SPECIAL_ARG_LEVELS 5 #define GFX_SPECIAL_ARG_SCORES 6 #define GFX_SPECIAL_ARG_EDITOR 7 #define GFX_SPECIAL_ARG_INFO 8 #define GFX_SPECIAL_ARG_SETUP 9 #define GFX_SPECIAL_ARG_PLAYING 10 #define GFX_SPECIAL_ARG_DOOR 11 #define GFX_SPECIAL_ARG_PANEL 12 #define GFX_SPECIAL_ARG_PREVIEW 13 #define GFX_SPECIAL_ARG_CRUMBLED 14 #define NUM_SPECIAL_GFX_ARGS 15 /* these additional definitions are currently only used for draw offsets */ #define GFX_SPECIAL_ARG_INFO_MAIN 0 #define GFX_SPECIAL_ARG_INFO_TITLE 1 #define GFX_SPECIAL_ARG_INFO_ELEMENTS 2 #define GFX_SPECIAL_ARG_INFO_MUSIC 3 #define GFX_SPECIAL_ARG_INFO_CREDITS 4 #define GFX_SPECIAL_ARG_INFO_PROGRAM 5 #define GFX_SPECIAL_ARG_INFO_VERSION 6 #define GFX_SPECIAL_ARG_INFO_LEVELSET 7 #define NUM_SPECIAL_GFX_INFO_ARGS 8 /* these additional definitions are currently only used for draw offsets */ #define GFX_SPECIAL_ARG_SETUP_MAIN 0 #define GFX_SPECIAL_ARG_SETUP_GAME 1 #define GFX_SPECIAL_ARG_SETUP_EDITOR 2 #define GFX_SPECIAL_ARG_SETUP_GRAPHICS 3 #define GFX_SPECIAL_ARG_SETUP_SOUND 4 #define GFX_SPECIAL_ARG_SETUP_ARTWORK 5 #define GFX_SPECIAL_ARG_SETUP_INPUT 6 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS 7 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1 8 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2 9 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3 10 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4 11 #define GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK 12 #define GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER 13 #define NUM_SPECIAL_GFX_SETUP_ARGS 14 /* values for image configuration suffixes */ #define GFX_ARG_X 0 #define GFX_ARG_Y 1 #define GFX_ARG_XPOS 2 #define GFX_ARG_YPOS 3 #define GFX_ARG_WIDTH 4 #define GFX_ARG_HEIGHT 5 #define GFX_ARG_VERTICAL 6 #define GFX_ARG_OFFSET 7 #define GFX_ARG_XOFFSET 8 #define GFX_ARG_YOFFSET 9 #define GFX_ARG_2ND_MOVEMENT_TILE 10 #define GFX_ARG_2ND_VERTICAL 11 #define GFX_ARG_2ND_OFFSET 12 #define GFX_ARG_2ND_XOFFSET 13 #define GFX_ARG_2ND_YOFFSET 14 #define GFX_ARG_2ND_SWAP_TILES 15 #define GFX_ARG_FRAMES 16 #define GFX_ARG_FRAMES_PER_LINE 17 #define GFX_ARG_START_FRAME 18 #define GFX_ARG_DELAY 19 #define GFX_ARG_ANIM_MODE 20 #define GFX_ARG_GLOBAL_SYNC 21 #define GFX_ARG_CRUMBLED_LIKE 22 #define GFX_ARG_DIGGABLE_LIKE 23 #define GFX_ARG_BORDER_SIZE 24 #define GFX_ARG_STEP_OFFSET 25 #define GFX_ARG_STEP_DELAY 26 #define GFX_ARG_DIRECTION 27 #define GFX_ARG_POSITION 28 #define GFX_ARG_DRAW_XOFFSET 29 #define GFX_ARG_DRAW_YOFFSET 30 #define GFX_ARG_DRAW_MASKED 31 #define GFX_ARG_ANIM_DELAY_FIXED 32 #define GFX_ARG_ANIM_DELAY_RANDOM 33 #define GFX_ARG_POST_DELAY_FIXED 34 #define GFX_ARG_POST_DELAY_RANDOM 35 #define GFX_ARG_NAME 36 #define GFX_ARG_SCALE_UP_FACTOR 37 #define GFX_ARG_CLONE_FROM 38 #define GFX_ARG_FADE_MODE 39 #define GFX_ARG_FADE_DELAY 40 #define GFX_ARG_POST_DELAY 41 #define GFX_ARG_AUTO_DELAY 42 #define GFX_ARG_ALIGN 43 #define GFX_ARG_VALIGN 44 #define GFX_ARG_SORT_PRIORITY 45 #define GFX_ARG_CLASS 46 #define GFX_ARG_STYLE 47 #define NUM_GFX_ARGS 48 /* values for sound configuration suffixes */ #define SND_ARG_MODE_LOOP 0 #define SND_ARG_VOLUME 1 #define SND_ARG_PRIORITY 2 #define NUM_SND_ARGS 3 /* values for music configuration suffixes */ #define MUS_ARG_MODE_LOOP 0 #define NUM_MUS_ARGS 1 /* values for font configuration (definitions must match those from main.c) */ #define FONT_INITIAL_1 0 #define FONT_INITIAL_2 1 #define FONT_INITIAL_3 2 #define FONT_INITIAL_4 3 #define FONT_TITLE_1 4 #define FONT_TITLE_2 5 #define FONT_MENU_1_ACTIVE 6 #define FONT_MENU_2_ACTIVE 7 #define FONT_MENU_1 8 #define FONT_MENU_2 9 #define FONT_TEXT_1_ACTIVE 10 #define FONT_TEXT_2_ACTIVE 11 #define FONT_TEXT_3_ACTIVE 12 #define FONT_TEXT_4_ACTIVE 13 #define FONT_TEXT_1 14 #define FONT_TEXT_2 15 #define FONT_TEXT_3 16 #define FONT_TEXT_4 17 #define FONT_ENVELOPE_1 18 #define FONT_ENVELOPE_2 19 #define FONT_ENVELOPE_3 20 #define FONT_ENVELOPE_4 21 #define FONT_INPUT_1_ACTIVE 22 #define FONT_INPUT_2_ACTIVE 23 #define FONT_INPUT_1 24 #define FONT_INPUT_2 25 #define FONT_OPTION_OFF 26 #define FONT_OPTION_ON 27 #define FONT_VALUE_1 28 #define FONT_VALUE_2 29 #define FONT_VALUE_OLD 30 #define FONT_LEVEL_NUMBER_ACTIVE 31 #define FONT_LEVEL_NUMBER 32 #define FONT_TAPE_RECORDER 33 #define FONT_GAME_INFO 34 #define FONT_INFO_ELEMENTS 35 #define FONT_INFO_LEVELSET 36 #define NUM_FONTS 37 #define NUM_INITIAL_FONTS 4 #if 0 #define FONT_ACTIVE(f) \ ((f) == FONT_MENU_1 ? FONT_MENU_1_ACTIVE : \ (f) == FONT_MENU_2 ? FONT_MENU_2_ACTIVE : \ (f) == FONT_TEXT_1 ? FONT_TEXT_1_ACTIVE : \ (f) == FONT_TEXT_2 ? FONT_TEXT_2_ACTIVE : \ (f) == FONT_TEXT_3 ? FONT_TEXT_3_ACTIVE : \ (f) == FONT_TEXT_4 ? FONT_TEXT_4_ACTIVE : \ (f) == FONT_INPUT_1 ? FONT_INPUT_1_ACTIVE : \ (f) == FONT_INPUT_2 ? FONT_INPUT_2_ACTIVE : \ (f) == FONT_LEVEL_NUMBER ? FONT_LEVEL_NUMBER_ACTIVE : \ (f)) #endif /* values for game_status (must match special image configuration suffixes) */ #define GAME_MODE_DEFAULT 0 #define GAME_MODE_LOADING 1 #define GAME_MODE_TITLE_INITIAL 2 #define GAME_MODE_TITLE 3 #define GAME_MODE_MAIN 4 #define GAME_MODE_LEVELS 5 #define GAME_MODE_SCORES 6 #define GAME_MODE_EDITOR 7 #define GAME_MODE_INFO 8 #define GAME_MODE_SETUP 9 #define GAME_MODE_PLAYING 10 #define GAME_MODE_PSEUDO_DOOR 11 #define GAME_MODE_PSEUDO_PANEL 12 #define GAME_MODE_PSEUDO_PREVIEW 13 #define GAME_MODE_PSEUDO_CRUMBLED 14 /* there are no special config file suffixes for these modes */ #define GAME_MODE_PSEUDO_TYPENAME 15 #define GAME_MODE_QUIT 16 /* special definitions currently only used for custom artwork configuration */ #define MUSIC_PREFIX_BACKGROUND 0 #define NUM_MUSIC_PREFIXES 1 #define MAX_LEVELS 1000 /* definitions for demo animation lists */ #define HELPANIM_LIST_NEXT -1 #define HELPANIM_LIST_END -999 /* program information and versioning definitions */ #define PROGRAM_VERSION_MAJOR 3 #define PROGRAM_VERSION_MINOR 3 #define PROGRAM_VERSION_PATCH 0 #define PROGRAM_VERSION_BUILD 1 #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" #define PROGRAM_AUTHOR_STRING "Holger Schemel" #define PROGRAM_COPYRIGHT_STRING "Copyright ©1995-2010 by Holger Schemel" #define PROGRAM_EMAIL_STRING "info@artsoft.org" #define PROGRAM_WEBSITE_STRING "http://www.artsoft.org/" #define PROGRAM_GAME_BY_STRING "A Game by Artsoft Entertainment" #define PROGRAM_UNIX_DATADIR_STRING ".rocksndiamonds" #if defined(CREATE_SPECIAL_EDITION_RND_JUE) #undef PROGRAM_TITLE_STRING #define PROGRAM_TITLE_STRING "R'n'D jue" #undef PROGRAM_UNIX_DATADIR_STRING #define PROGRAM_UNIX_DATADIR_STRING ".rnd_jue" #endif #define ICON_TITLE_STRING PROGRAM_TITLE_STRING #define COOKIE_PREFIX "ROCKSNDIAMONDS" #define FILENAME_PREFIX "Rocks" #define USERDATA_DIRECTORY_WIN32 PROGRAM_TITLE_STRING #define USERDATA_DIRECTORY_MACOSX PROGRAM_TITLE_STRING #define USERDATA_DIRECTORY_UNIX PROGRAM_UNIX_DATADIR_STRING #define USERDATA_DIRECTORY_DOS "userdata" #if defined(PLATFORM_WIN32) #define USERDATA_DIRECTORY USERDATA_DIRECTORY_WIN32 #elif defined(PLATFORM_MACOSX) #define USERDATA_DIRECTORY USERDATA_DIRECTORY_MACOSX #elif defined(PLATFORM_UNIX) #define USERDATA_DIRECTORY USERDATA_DIRECTORY_UNIX #else #define USERDATA_DIRECTORY USERDATA_DIRECTORY_DOS #endif #define X11_ICON_FILENAME "rocks_icon.xbm" #define X11_ICONMASK_FILENAME "rocks_iconmask.xbm" #define SDL_ICON_FILENAME "rocks_icon_32x32.pcx" #define MSDOS_POINTER_FILENAME "mouse.pcx" /* file version numbers for resource files (levels, tapes, score, setup, etc.) ** currently supported/known file version numbers: ** 1.0 (old) ** 1.2 (still in use) ** 1.4 (still in use) ** 2.0 (actual) */ #define FILE_VERSION_1_0 VERSION_IDENT(1,0,0,0) #define FILE_VERSION_1_2 VERSION_IDENT(1,2,0,0) #define FILE_VERSION_1_4 VERSION_IDENT(1,4,0,0) #define FILE_VERSION_2_0 VERSION_IDENT(2,0,0,0) #define FILE_VERSION_3_0 VERSION_IDENT(3,0,0,0) /* file version does not change for every program version, but is changed when new features are introduced that are incompatible with older file versions, so that they can be treated accordingly */ #define FILE_VERSION_ACTUAL FILE_VERSION_3_0 #define GAME_VERSION_1_0 FILE_VERSION_1_0 #define GAME_VERSION_1_2 FILE_VERSION_1_2 #define GAME_VERSION_1_4 FILE_VERSION_1_4 #define GAME_VERSION_2_0 FILE_VERSION_2_0 #define GAME_VERSION_3_0 FILE_VERSION_3_0 #define GAME_VERSION_ACTUAL VERSION_IDENT(PROGRAM_VERSION_MAJOR, \ PROGRAM_VERSION_MINOR, \ PROGRAM_VERSION_PATCH, \ PROGRAM_VERSION_BUILD) /* values for game_emulation */ #define EMU_NONE 0 #define EMU_BOULDERDASH 1 #define EMU_SOKOBAN 2 #define EMU_SUPAPLEX 3 /* values for level file type identifier */ #define LEVEL_FILE_TYPE_UNKNOWN 0 #define LEVEL_FILE_TYPE_RND 1 #define LEVEL_FILE_TYPE_BD 2 #define LEVEL_FILE_TYPE_EM 3 #define LEVEL_FILE_TYPE_SP 4 #define LEVEL_FILE_TYPE_DX 5 #define LEVEL_FILE_TYPE_SB 6 #define LEVEL_FILE_TYPE_DC 7 #define NUM_LEVEL_FILE_TYPES 8 /* values for game engine type identifier */ #define GAME_ENGINE_TYPE_UNKNOWN LEVEL_FILE_TYPE_UNKNOWN #define GAME_ENGINE_TYPE_RND LEVEL_FILE_TYPE_RND #define GAME_ENGINE_TYPE_EM LEVEL_FILE_TYPE_EM #define GAME_ENGINE_TYPE_SP LEVEL_FILE_TYPE_SP #define NUM_ENGINE_TYPES 4 struct BorderInfo { boolean draw_masked[NUM_SPECIAL_GFX_ARGS]; boolean draw_masked_when_fading; }; struct MenuMainButtonInfo { struct MenuPosInfo name; struct MenuPosInfo levels; struct MenuPosInfo scores; struct MenuPosInfo editor; struct MenuPosInfo info; struct MenuPosInfo game; struct MenuPosInfo setup; struct MenuPosInfo quit; struct MenuPosInfo prev_level; struct MenuPosInfo next_level; }; struct MenuMainTextInfo { struct TextPosInfo name; struct TextPosInfo levels; struct TextPosInfo scores; struct TextPosInfo editor; struct TextPosInfo info; struct TextPosInfo game; struct TextPosInfo setup; struct TextPosInfo quit; struct TextPosInfo first_level; struct TextPosInfo last_level; struct TextPosInfo level_number; struct TextPosInfo level_info_1; struct TextPosInfo level_info_2; struct TextPosInfo level_name; struct TextPosInfo level_author; struct TextPosInfo level_year; struct TextPosInfo level_imported_from; struct TextPosInfo level_imported_by; struct TextPosInfo level_tested_by; struct TextPosInfo title_1; struct TextPosInfo title_2; struct TextPosInfo title_3; }; struct MenuMainInputInfo { struct TextPosInfo name; }; struct MenuMainInfo { struct MenuMainButtonInfo button; struct MenuMainTextInfo text; struct MenuMainInputInfo input; }; struct TitleFadingInfo { int fade_mode; int fade_delay; int post_delay; int auto_delay; }; struct TitleMessageInfo { int x, y; int width, height; int chars, lines; int align, valign; int font; boolean autowrap; boolean centered; boolean parse_comments; int sort_priority; int fade_mode; int fade_delay; int post_delay; int auto_delay; }; struct InitInfo { struct MenuPosInfo busy; }; struct MenuInfo { int draw_xoffset[NUM_SPECIAL_GFX_ARGS]; int draw_yoffset[NUM_SPECIAL_GFX_ARGS]; int draw_xoffset_info[NUM_SPECIAL_GFX_INFO_ARGS]; int draw_yoffset_info[NUM_SPECIAL_GFX_INFO_ARGS]; int draw_xoffset_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int draw_yoffset_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int scrollbar_xoffset; int list_size[NUM_SPECIAL_GFX_ARGS]; struct TitleFadingInfo enter_menu; struct TitleFadingInfo leave_menu; struct TitleFadingInfo enter_screen[NUM_SPECIAL_GFX_ARGS]; struct TitleFadingInfo leave_screen[NUM_SPECIAL_GFX_ARGS]; struct TitleFadingInfo next_screen; int sound[NUM_SPECIAL_GFX_ARGS]; int music[NUM_SPECIAL_GFX_ARGS]; struct MenuMainInfo main; }; struct DoorInfo { int width; int height; int step_offset; int step_delay; int anim_mode; }; struct PreviewInfo { int x, y; int align, valign; int xsize, ysize; int xoffset, yoffset; int tile_size; int step_offset; int step_delay; int anim_mode; }; struct ViewportInfo { struct RectWithBorder window; struct RectWithBorder playfield[NUM_SPECIAL_GFX_ARGS]; struct RectWithBorder door_1[NUM_SPECIAL_GFX_ARGS]; struct RectWithBorder door_2[NUM_SPECIAL_GFX_ARGS]; }; struct HiScore { char Name[MAX_PLAYER_NAME_LEN + 1]; int Score; }; struct Content { int e[3][3]; }; struct EnvelopeInfo { int xsize; int ysize; boolean autowrap; boolean centered; char text[MAX_ENVELOPE_TEXT_LEN + 1]; }; struct LevelSetInfo { int music[MAX_LEVELS]; }; struct LevelFileInfo { int nr; int type; boolean packed; char *basename; char *filename; }; struct DateInfo { int year; int month; int day; enum { DATE_SRC_CLOCK, DATE_SRC_LEVELFILE } src; }; struct LevelInfo { struct LevelFileInfo file_info; int game_engine_type; /* level stored in native format for the alternative native game engines */ struct LevelInfo_EM *native_em_level; struct LevelInfo_SP *native_sp_level; int file_version; /* file format version the level is stored with */ int game_version; /* game release version the level was created with */ struct DateInfo creation_date; boolean encoding_16bit_field; /* level contains 16-bit elements */ boolean encoding_16bit_yamyam; /* yamyam contains 16-bit elements */ boolean encoding_16bit_amoeba; /* amoeba contains 16-bit elements */ int fieldx, fieldy; int time; /* available time (seconds) */ int gems_needed; char name[MAX_LEVEL_NAME_LEN + 1]; char author[MAX_LEVEL_AUTHOR_LEN + 1]; int random_seed; struct EnvelopeInfo envelope[NUM_ENVELOPES]; int score[LEVEL_SCORE_ELEMENTS]; struct Content yamyam_content[MAX_ELEMENT_CONTENTS]; int num_yamyam_contents; int amoeba_speed; int amoeba_content; int game_of_life[4]; int biomaze[4]; int time_magic_wall; int time_wheel; int time_light; int time_timegate; int shield_normal_time; int shield_deadly_time; int extra_time; int time_orb_time; int extra_time_score; int start_element[MAX_PLAYERS]; boolean use_start_element[MAX_PLAYERS]; int artwork_element[MAX_PLAYERS]; boolean use_artwork_element[MAX_PLAYERS]; int explosion_element[MAX_PLAYERS]; boolean use_explosion_element[MAX_PLAYERS]; /* values for the new EMC elements */ int android_move_time; int android_clone_time; boolean ball_random; boolean ball_state_initial; int ball_time; int lenses_score; int magnify_score; int slurp_score; int lenses_time; int magnify_time; int wind_direction_initial; struct Content ball_content[MAX_ELEMENT_CONTENTS]; int num_ball_contents; int num_android_clone_elements; int android_clone_element[MAX_ANDROID_ELEMENTS]; int can_move_into_acid_bits; /* bitfield to store property for elements */ int dont_collide_with_bits; /* bitfield to store property for elements */ int initial_player_stepsize[MAX_PLAYERS]; /* initial player speed */ boolean initial_player_gravity[MAX_PLAYERS]; boolean use_initial_inventory[MAX_PLAYERS]; int initial_inventory_size[MAX_PLAYERS]; int initial_inventory_content[MAX_PLAYERS][MAX_INITIAL_INVENTORY_SIZE]; boolean em_slippery_gems; /* EM style "gems slip from wall" behaviour */ boolean em_explodes_by_fire; /* EM style chain explosion behaviour */ boolean use_spring_bug; /* for compatibility with old levels */ boolean use_time_orb_bug; /* for compatibility with old levels */ boolean instant_relocation; /* no visual delay when relocating player */ boolean shifted_relocation; /* no level centering when relocating player */ boolean can_pass_to_walkable; /* player can pass to empty or walkable tile */ boolean grow_into_diggable; /* amoeba can grow into anything diggable */ boolean auto_exit_sokoban; /* automatically finish solved Sokoban levels */ boolean continuous_snapping; /* repeated snapping without releasing key */ boolean block_snap_field; /* snapping blocks field to show animation */ boolean block_last_field; /* player blocks previous field while moving */ boolean sp_block_last_field; /* player blocks previous field while moving */ /* ('int' instead of 'boolean' because used as selectbox value in editor) */ int use_step_counter; /* count steps instead of seconds for level */ short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean use_custom_template; /* use custom properties from template file */ boolean no_valid_file; /* set when level file missing or invalid */ boolean changed; /* set when level was changed in the editor */ /* runtime flags to handle bugs in old levels (not stored in level file) */ boolean use_action_after_change_bug; }; struct GlobalInfo { char *autoplay_leveldir; int autoplay_level[MAX_TAPES_PER_SET]; boolean autoplay_all; char *convert_leveldir; int convert_level_nr; char *create_images_dir; int num_toons; float frames_per_second; boolean fps_slowdown; int fps_slowdown_factor; /* global values for fading screens and masking borders */ int border_status; #if 0 int fading_status; int fading_type; #endif }; struct ElementChangeInfo { boolean can_change; /* use or ignore this change info */ boolean has_event[NUM_CHANGE_EVENTS]; /* change events */ int trigger_player; /* player triggering change */ int trigger_side; /* side triggering change */ int trigger_page; /* page triggering change */ int target_element; /* target element after change */ int delay_fixed; /* added frame delay before changed (fixed) */ int delay_random; /* added frame delay before changed (random) */ int delay_frames; /* either 1 (frames) or 50 (seconds; 50 fps) */ int initial_trigger_element; /* initial element triggering change */ struct Content target_content;/* elements for extended change target */ boolean use_target_content; /* use extended change target */ boolean only_if_complete; /* only use complete target content */ boolean use_random_replace; /* use random value for replacing elements */ int random_percentage; /* random value for replacing elements */ int replace_when; /* type of elements that can be replaced */ boolean explode; /* explode instead of change */ boolean has_action; /* execute action on specified condition */ int action_type; /* type of action */ int action_mode; /* mode of action */ int action_arg; /* parameter of action */ int action_element; /* element related to action */ /* ---------- internal values used at runtime when playing ---------- */ int trigger_element; /* element triggering change */ /* functions that are called before, while and after the change of an element -- currently only used for non-custom elements */ void (*pre_change_function)(int x, int y); void (*change_function)(int x, int y); void (*post_change_function)(int x, int y); short actual_trigger_element; /* element that actually triggered change */ int actual_trigger_side; /* element side that triggered the change */ int actual_trigger_player; /* player which actually triggered change */ int actual_trigger_player_bits; /* player bits of triggering players */ int actual_trigger_ce_value; /* CE value of element that triggered change */ int actual_trigger_ce_score; /* CE score of element that triggered change */ boolean can_change_or_has_action; /* can_change | has_action */ /* ---------- internal values used in level editor ---------- */ int direct_action; /* change triggered by actions on element */ int other_action; /* change triggered by other element actions */ }; struct ElementGroupInfo { int num_elements; /* number of elements in this group */ int element[MAX_ELEMENTS_IN_GROUP]; /* list of elements in this group */ int choice_mode; /* how to choose element from group */ /* ---------- internal values used at runtime when playing ---------- */ /* the following is the same as above, but with recursively resolved group elements (group elements may also contain further group elements!) */ int num_elements_resolved; short element_resolved[NUM_FILE_ELEMENTS]; int choice_pos; /* current element choice position */ }; struct ElementNameInfo { /* ---------- token and description strings ---------- */ char *token_name; /* element token used in config files */ char *class_name; /* element class used in config files */ char *editor_description; /* pre-defined description for level editor */ }; struct ElementInfo { /* ---------- token and description strings ---------- */ char *token_name; /* element token used in config files */ char *class_name; /* element class used in config files */ char *editor_description; /* pre-defined description for level editor */ char *custom_description; /* alternative description from config file */ char description[MAX_ELEMENT_NAME_LEN + 1]; /* for custom/group elements */ /* ---------- graphic and sound definitions ---------- */ int graphic[NUM_ACTIONS]; /* default graphics for several actions */ int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS_FULL]; /* special graphics for left/right/up/down */ int crumbled[NUM_ACTIONS]; /* crumbled graphics for several actions */ int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS_FULL]; /* crumbled graphics for left/right/up/down */ int special_graphic[NUM_SPECIAL_GFX_ARGS]; /* special graphics for certain screens */ int sound[NUM_ACTIONS]; /* default sounds for several actions */ /* ---------- special element property values ---------- */ unsigned long properties[NUM_EP_BITFIELDS]; /* element base properties */ boolean use_gfx_element; /* use custom graphic element */ int gfx_element_initial; /* initial optional custom graphic element */ int access_direction; /* accessible from which direction */ int collect_score_initial; /* initial score value for collecting */ int collect_count_initial; /* initial count value for collecting */ int ce_value_fixed_initial; /* initial value for custom variable (fix) */ int ce_value_random_initial; /* initial value for custom variable (rnd) */ boolean use_last_ce_value; /* use value from element before change */ int push_delay_fixed; /* constant delay before pushing */ int push_delay_random; /* additional random delay before pushing */ int drop_delay_fixed; /* constant delay after dropping */ int drop_delay_random; /* additional random delay after dropping */ int move_delay_fixed; /* constant delay after moving */ int move_delay_random; /* additional random delay after moving */ int move_pattern; /* direction movable element moves to */ int move_direction_initial; /* initial direction element moves to */ int move_stepsize; /* step size element moves with */ int move_enter_element; /* element that can be entered (and removed) */ int move_leave_element; /* element that can be left behind */ int move_leave_type; /* change (limited) or leave (unlimited) */ int slippery_type; /* how/where other elements slip away */ struct Content content; /* new elements after explosion */ int explosion_type; /* type of explosion, like 3x3, 3+3 or 1x1 */ int explosion_delay; /* duration of explosion of this element */ int ignition_delay; /* delay for explosion by other explosion */ struct ElementChangeInfo *change_page; /* actual list of change pages */ struct ElementChangeInfo *change; /* pointer to current change page */ int num_change_pages; /* actual number of change pages */ int current_change_page; /* currently edited change page */ struct ElementGroupInfo *group; /* pointer to element group info */ /* ---------- internal values used at runtime when playing ---------- */ boolean has_change_event[NUM_CHANGE_EVENTS]; int event_page_nr[NUM_CHANGE_EVENTS]; /* page number for each event */ struct ElementChangeInfo *event_page[NUM_CHANGE_EVENTS]; /* page for event */ boolean in_group[NUM_GROUP_ELEMENTS]; int gfx_element; /* runtime optional custom graphic element */ int collect_score; /* runtime score value for collecting */ /* count of this element on playfield, calculated after each frame */ int element_count; /* ---------- internal values used in level editor ---------- */ int access_type; /* walkable or passable */ int access_layer; /* accessible over/inside/under */ int access_protected; /* protection against deadly elements */ int walk_to_action; /* diggable/collectible/pushable */ int smash_targets; /* can smash player/enemies/everything */ int deadliness; /* deadly when running/colliding/touching */ boolean can_explode_by_fire; /* element explodes by fire */ boolean can_explode_smashed; /* element explodes when smashed */ boolean can_explode_impact; /* element explodes on impact */ boolean modified_settings; /* set for all modified custom elements */ }; struct FontInfo { char *token_name; /* font token used in config files */ int graphic; /* default graphic for this font */ int special_graphic[NUM_SPECIAL_GFX_ARGS]; /* special graphics for certain screens */ int special_bitmap_id[NUM_SPECIAL_GFX_ARGS]; /* internal bitmap ID for special graphics */ }; struct GraphicInfo { Bitmap *bitmap; int src_image_width; /* scaled bitmap size, but w/o small images */ int src_image_height; /* scaled bitmap size, but w/o small images */ int src_x, src_y; /* start position of animation frames */ int width, height; /* width/height of each animation frame */ int offset_x, offset_y; /* x/y offset to next animation frame */ int offset2_x, offset2_y; /* x/y offset to second movement tile */ boolean double_movement; /* animation has second movement tile */ int swap_double_tiles; /* explicitely force or forbid tile swapping */ int anim_frames; int anim_frames_per_line; int anim_start_frame; int anim_delay; /* important: delay of 1 means "no delay"! */ int anim_mode; boolean anim_global_sync; int crumbled_like; /* element for cloning crumble graphics */ int diggable_like; /* element for cloning digging graphics */ int border_size; /* border size for "crumbled" graphics */ int scale_up_factor; /* optional factor for scaling image up */ int clone_from; /* graphic for cloning *all* settings */ int anim_delay_fixed; /* optional delay values for bored and */ int anim_delay_random; /* sleeping player animations (animation */ int post_delay_fixed; /* intervall and following pause before */ int post_delay_random; /* next intervall (bored animation only) */ int step_offset; /* optional step offset of toon animations */ int step_delay; /* optional step delay of toon animations */ int draw_xoffset; /* optional offset for drawing font chars */ int draw_yoffset; /* optional offset for drawing font chars */ int draw_masked; /* optional setting for drawing envelope gfx */ int fade_mode; /* optional setting for drawing title screens */ int fade_delay; /* optional setting for drawing title screens */ int post_delay; /* optional setting for drawing title screens */ int auto_delay; /* optional setting for drawing title screens */ int align, valign; /* optional setting for drawing title screens */ int sort_priority; /* optional setting for drawing title screens */ int class; int style; boolean use_image_size; /* use image size as default width and height */ #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) Pixmap clip_mask; /* single-graphic-only clip mask for X11 */ GC clip_gc; /* single-graphic-only clip gc for X11 */ #endif }; struct SoundInfo { boolean loop; int volume; int priority; }; struct MusicInfo { boolean loop; }; struct MusicPrefixInfo { char *prefix; boolean is_loop_music; }; struct MusicFileInfo { char *basename; char *title_header; char *artist_header; char *album_header; char *year_header; char *title; char *artist; char *album; char *year; int music; boolean is_sound; struct MusicFileInfo *next; }; struct ElementActionInfo { char *suffix; int value; boolean is_loop_sound; }; struct ElementDirectionInfo { char *suffix; int value; }; struct SpecialSuffixInfo { char *suffix; int value; }; struct HelpAnimInfo { int element; int action; int direction; int delay; }; extern Bitmap *bitmap_db_store; extern Bitmap *bitmap_db_cross; extern Bitmap *bitmap_db_field; extern Bitmap *bitmap_db_panel; extern Bitmap *bitmap_db_door; extern Bitmap *bitmap_db_toons; extern Pixmap tile_clipmask[]; extern DrawBuffer *fieldbuffer; extern DrawBuffer *drawto_field; extern int game_status; extern boolean level_editor_test_game; extern boolean network_playing; #if defined(TARGET_SDL) extern boolean network_server; extern SDL_Thread *server_thread; #endif extern int key_joystick_mapping; #if 1 extern boolean redraw[MAX_LEV_FIELDX + 2][MAX_LEV_FIELDY + 2]; #else extern boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; #endif extern int redraw_x1, redraw_y1; extern short Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short AmoebaCnt[MAX_NUM_AMOEBA]; extern short AmoebaCnt2[MAX_NUM_AMOEBA]; extern short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int ActiveElement[MAX_NUM_ELEMENTS]; extern int ActiveButton[NUM_IMAGE_FILES]; extern int ActiveFont[NUM_FONTS]; extern int lev_fieldx, lev_fieldy; extern int scroll_x, scroll_y; extern int WIN_XSIZE, WIN_YSIZE; extern int SCR_FIELDX, SCR_FIELDY; extern int SX, SY; extern int REAL_SX, REAL_SY; extern int DX, DY; extern int VX, VY; extern int EX, EY; extern int dDX, dDY; extern int FX, FY; extern int ScrollStepSize; extern int ScreenMovDir, ScreenMovPos, ScreenGfxPos; extern int BorderElement; extern int GameFrameDelay; extern int FfwdFrameDelay; extern int BX1, BY1; extern int BX2, BY2; extern int SBX_Left, SBX_Right; extern int SBY_Upper, SBY_Lower; extern int ZX, ZY; extern int ExitX, ExitY; extern int AllPlayersGone; extern int TimeFrames, TimePlayed, TimeLeft, TapeTime; extern boolean network_player_action_received; extern int graphics_action_mapping[]; extern struct LevelSetInfo levelset; extern struct LevelInfo level, level_template; extern struct HiScore highscore[]; extern struct TapeInfo tape; extern struct GlobalInfo global; extern struct BorderInfo border; extern struct ViewportInfo viewport; extern struct TitleFadingInfo fading; extern struct TitleFadingInfo fading_none; extern struct TitleFadingInfo title_initial_default; extern struct TitleFadingInfo title_default; extern struct TitleMessageInfo titlemessage_initial_default; extern struct TitleMessageInfo titlemessage_initial[]; extern struct TitleMessageInfo titlemessage_default; extern struct TitleMessageInfo titlemessage[]; extern struct TitleMessageInfo readme; extern struct InitInfo init, init_last; extern struct MenuInfo menu; extern struct DoorInfo door_1, door_2; extern struct PreviewInfo preview; extern struct ElementInfo element_info[]; extern struct ElementNameInfo element_name_info[]; extern struct ElementActionInfo element_action_info[]; extern struct ElementDirectionInfo element_direction_info[]; extern struct SpecialSuffixInfo special_suffix_info[]; extern struct TokenIntPtrInfo image_config_vars[]; extern struct FontInfo font_info[]; extern struct MusicPrefixInfo music_prefix_info[]; extern struct GraphicInfo *graphic_info; extern struct SoundInfo *sound_info; extern struct MusicInfo *music_info; extern struct MusicFileInfo *music_file_info; extern struct HelpAnimInfo *helpanim_info; extern SetupFileHash *helptext_info; extern SetupFileHash *image_config_hash; extern SetupFileHash *element_token_hash; extern SetupFileHash *graphic_token_hash; extern SetupFileHash *font_token_hash; extern struct ConfigTypeInfo image_config_suffix[]; extern struct ConfigTypeInfo sound_config_suffix[]; extern struct ConfigTypeInfo music_config_suffix[]; extern struct ConfigInfo image_config[]; extern struct ConfigInfo sound_config[]; extern struct ConfigInfo music_config[]; extern struct ConfigInfo helpanim_config[]; extern struct ConfigInfo helptext_config[]; #endif /* MAIN_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_fnt.c0000644000175000017500000001232311375255512017364 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_fnt.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_FNT_C #define CONF_FNT_C /* values for font/graphics mapping configuration */ static struct { int font_nr; int special; int graphic; } font_to_graphic[] = { { FONT_INITIAL_1, -1, IMG_FONT_INITIAL_1 }, { FONT_INITIAL_2, -1, IMG_FONT_INITIAL_2 }, { FONT_INITIAL_3, -1, IMG_FONT_INITIAL_3 }, { FONT_INITIAL_4, -1, IMG_FONT_INITIAL_4 }, { FONT_TITLE_1, -1, IMG_FONT_TITLE_1 }, { FONT_TITLE_2, -1, IMG_FONT_TITLE_2 }, { FONT_TITLE_2, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TITLE_2_SETUP }, { FONT_MENU_1, -1, IMG_FONT_MENU_1 }, { FONT_MENU_1_ACTIVE, -1, IMG_FONT_MENU_1_ACTIVE }, { FONT_MENU_2, -1, IMG_FONT_MENU_2 }, { FONT_MENU_2_ACTIVE, -1, IMG_FONT_MENU_2_ACTIVE }, { FONT_TEXT_1, -1, IMG_FONT_TEXT_1 }, { FONT_TEXT_1, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_1_MAIN }, { FONT_TEXT_1, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_1_LEVELS }, { FONT_TEXT_1, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_1_SETUP }, { FONT_TEXT_1, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_1_PREVIEW }, { FONT_TEXT_1, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_1_SCORES }, { FONT_TEXT_1_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_1_ACTIVE_SCORES }, { FONT_TEXT_1, GFX_SPECIAL_ARG_PANEL, IMG_FONT_TEXT_1_PANEL }, { FONT_TEXT_1, GFX_SPECIAL_ARG_DOOR, IMG_FONT_TEXT_1_DOOR }, { FONT_TEXT_2, -1, IMG_FONT_TEXT_2 }, { FONT_TEXT_2, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_2_MAIN }, { FONT_TEXT_2, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_2_LEVELS }, { FONT_TEXT_2, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_2_SETUP }, { FONT_TEXT_2, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_2_PREVIEW }, { FONT_TEXT_2, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_2_SCORES }, { FONT_TEXT_2_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_2_ACTIVE_SCORES }, { FONT_TEXT_3, -1, IMG_FONT_TEXT_3 }, { FONT_TEXT_3, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_3_LEVELS }, { FONT_TEXT_3, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_3_SETUP }, { FONT_TEXT_3, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_3_PREVIEW }, { FONT_TEXT_3, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_3_SCORES }, { FONT_TEXT_3_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_3_ACTIVE_SCORES }, { FONT_TEXT_4, -1, IMG_FONT_TEXT_4 }, { FONT_TEXT_4, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_4_MAIN }, { FONT_TEXT_4, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_4_LEVELS }, { FONT_TEXT_4, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_4_SETUP }, { FONT_TEXT_4, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_4_SCORES }, { FONT_TEXT_4_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_4_ACTIVE_SCORES }, { FONT_ENVELOPE_1, -1, IMG_FONT_ENVELOPE_1 }, { FONT_ENVELOPE_2, -1, IMG_FONT_ENVELOPE_2 }, { FONT_ENVELOPE_3, -1, IMG_FONT_ENVELOPE_3 }, { FONT_ENVELOPE_4, -1, IMG_FONT_ENVELOPE_4 }, { FONT_INPUT_1, -1, IMG_FONT_INPUT_1 }, { FONT_INPUT_1, GFX_SPECIAL_ARG_MAIN, IMG_FONT_INPUT_1_MAIN }, { FONT_INPUT_1_ACTIVE, -1, IMG_FONT_INPUT_1_ACTIVE }, { FONT_INPUT_1_ACTIVE, GFX_SPECIAL_ARG_MAIN, IMG_FONT_INPUT_1_ACTIVE_MAIN }, { FONT_INPUT_1_ACTIVE, GFX_SPECIAL_ARG_SETUP, IMG_FONT_INPUT_1_ACTIVE_SETUP }, { FONT_INPUT_2, -1, IMG_FONT_INPUT_2 }, { FONT_INPUT_2_ACTIVE, -1, IMG_FONT_INPUT_2_ACTIVE }, { FONT_OPTION_OFF, -1, IMG_FONT_OPTION_OFF }, { FONT_OPTION_ON, -1, IMG_FONT_OPTION_ON }, { FONT_VALUE_1, -1, IMG_FONT_VALUE_1 }, { FONT_VALUE_2, -1, IMG_FONT_VALUE_2 }, { FONT_VALUE_OLD, -1, IMG_FONT_VALUE_OLD }, { FONT_LEVEL_NUMBER, -1, IMG_FONT_LEVEL_NUMBER }, { FONT_LEVEL_NUMBER_ACTIVE, -1, IMG_FONT_LEVEL_NUMBER_ACTIVE }, { FONT_TAPE_RECORDER, -1, IMG_FONT_TAPE_RECORDER }, { FONT_GAME_INFO, -1, IMG_FONT_GAME_INFO }, { FONT_INFO_ELEMENTS, -1, IMG_FONT_INFO_ELEMENTS }, { FONT_INFO_LEVELSET, -1, IMG_FONT_INFO_LEVELSET }, { -1, -1, -1 }, }; #endif /* CONF_FNT_C */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_act.c0000644000175000017500000001640411375255513017351 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_act.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_ACT_C #define CONF_ACT_C /* values for active states of elements and fonts */ static struct { int element; int element_active; } element_with_active_state[] = { { EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, EL_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_MAGIC_WALL, EL_DC_MAGIC_WALL_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_DYNABOMB, EL_DYNABOMB_ACTIVE }, { EL_DYNABOMB_PLAYER_1, EL_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_2, EL_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_3, EL_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_4, EL_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNAMITE, EL_DYNAMITE_ACTIVE }, { EL_EMC_DRIPPER, EL_EMC_DRIPPER_ACTIVE }, { EL_EMC_FAKE_GRASS, EL_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_GATE_5_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, EL_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, EL_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, EL_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL_SWITCH, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_SPRING_BUMPER, EL_EMC_SPRING_BUMPER_ACTIVE }, { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE }, { EL_EM_GATE_1_GRAY, EL_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, EL_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, EL_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, EL_EM_GATE_4_GRAY_ACTIVE }, { EL_GATE_1_GRAY, EL_GATE_1_GRAY_ACTIVE }, { EL_GATE_2_GRAY, EL_GATE_2_GRAY_ACTIVE }, { EL_GATE_3_GRAY, EL_GATE_3_GRAY_ACTIVE }, { EL_GATE_4_GRAY, EL_GATE_4_GRAY_ACTIVE }, { EL_INTERNAL_CASCADE_BD, EL_INTERNAL_CASCADE_BD_ACTIVE }, { EL_INTERNAL_CASCADE_CE, EL_INTERNAL_CASCADE_CE_ACTIVE }, { EL_INTERNAL_CASCADE_CHARS, EL_INTERNAL_CASCADE_CHARS_ACTIVE }, { EL_INTERNAL_CASCADE_DC, EL_INTERNAL_CASCADE_DC_ACTIVE }, { EL_INTERNAL_CASCADE_DX, EL_INTERNAL_CASCADE_DX_ACTIVE }, { EL_INTERNAL_CASCADE_DYNAMIC, EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE }, { EL_INTERNAL_CASCADE_EM, EL_INTERNAL_CASCADE_EM_ACTIVE }, { EL_INTERNAL_CASCADE_EMC, EL_INTERNAL_CASCADE_EMC_ACTIVE }, { EL_INTERNAL_CASCADE_GE, EL_INTERNAL_CASCADE_GE_ACTIVE }, { EL_INTERNAL_CASCADE_REF, EL_INTERNAL_CASCADE_REF_ACTIVE }, { EL_INTERNAL_CASCADE_RND, EL_INTERNAL_CASCADE_RND_ACTIVE }, { EL_INTERNAL_CASCADE_SB, EL_INTERNAL_CASCADE_SB_ACTIVE }, { EL_INTERNAL_CASCADE_SP, EL_INTERNAL_CASCADE_SP_ACTIVE }, { EL_INTERNAL_CASCADE_STEEL_CHARS, EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE }, { EL_INTERNAL_CASCADE_USER, EL_INTERNAL_CASCADE_USER_ACTIVE }, { EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE }, { EL_LAMP, EL_LAMP_ACTIVE }, { EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE }, { EL_MAGIC_WALL, EL_MAGIC_WALL_ACTIVE }, { EL_ROBOT_WHEEL, EL_ROBOT_WHEEL_ACTIVE }, { EL_SHIELD_DEADLY, EL_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_NORMAL, EL_SHIELD_NORMAL_ACTIVE }, { EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVE }, { EL_SP_DISK_RED, EL_SP_DISK_RED_ACTIVE }, { EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE }, { EL_TIMEGATE_SWITCH, EL_TIMEGATE_SWITCH_ACTIVE }, { EL_TRAP, EL_TRAP_ACTIVE }, { -1, -1 }, }; static struct { int button; int button_active; } button_with_active_state[] = { { IMG_MENU_BUTTON, IMG_MENU_BUTTON_ACTIVE }, { IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE }, { IMG_MENU_BUTTON_EDITOR, IMG_MENU_BUTTON_EDITOR_ACTIVE }, { IMG_MENU_BUTTON_ENTER_MENU, IMG_MENU_BUTTON_ENTER_MENU_ACTIVE }, { IMG_MENU_BUTTON_GAME, IMG_MENU_BUTTON_GAME_ACTIVE }, { IMG_MENU_BUTTON_INFO, IMG_MENU_BUTTON_INFO_ACTIVE }, { IMG_MENU_BUTTON_LEAVE_MENU, IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE }, { IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE }, { IMG_MENU_BUTTON_LEVELS, IMG_MENU_BUTTON_LEVELS_ACTIVE }, { IMG_MENU_BUTTON_NAME, IMG_MENU_BUTTON_NAME_ACTIVE }, { IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE }, { IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE }, { IMG_MENU_BUTTON_QUIT, IMG_MENU_BUTTON_QUIT_ACTIVE }, { IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE }, { IMG_MENU_BUTTON_SCORES, IMG_MENU_BUTTON_SCORES_ACTIVE }, { IMG_MENU_BUTTON_SETUP, IMG_MENU_BUTTON_SETUP_ACTIVE }, { IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE }, { -1, -1 }, }; static struct { int font_nr; int font_nr_active; } font_with_active_state[] = { { FONT_INPUT_1, FONT_INPUT_1_ACTIVE }, { FONT_INPUT_2, FONT_INPUT_2_ACTIVE }, { FONT_LEVEL_NUMBER, FONT_LEVEL_NUMBER_ACTIVE }, { FONT_MENU_1, FONT_MENU_1_ACTIVE }, { FONT_MENU_2, FONT_MENU_2_ACTIVE }, { FONT_TEXT_1, FONT_TEXT_1_ACTIVE }, { FONT_TEXT_2, FONT_TEXT_2_ACTIVE }, { FONT_TEXT_3, FONT_TEXT_3_ACTIVE }, { FONT_TEXT_4, FONT_TEXT_4_ACTIVE }, { -1, -1 }, }; #endif /* CONF_ACT_C */ rocksndiamonds-3.3.0.1+dfsg1/src/tools.h0000644000175000017500000001565511364266703016752 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tools.h * ***********************************************************/ #ifndef TOOLS_H #define TOOLS_H #include "main.h" #include "game.h" /* for SetDrawtoField */ #define DRAW_BUFFERED 1 #define DRAW_BACKBUFFER 2 /* for DrawElementShifted */ #define NO_CUTTING 0 #define CUT_ABOVE (1 << 0) #define CUT_BELOW (1 << 1) #define CUT_LEFT (1 << 2) #define CUT_RIGHT (1 << 3) /* for masking functions */ #define NO_MASKING 0 #define USE_MASKING 1 /* for MoveDoor */ #define DOOR_OPEN_1 (1 << 0) #define DOOR_OPEN_2 (1 << 1) #define DOOR_CLOSE_1 (1 << 2) #define DOOR_CLOSE_2 (1 << 3) #define DOOR_OPEN_ALL (DOOR_OPEN_1 | DOOR_OPEN_2) #define DOOR_CLOSE_ALL (DOOR_CLOSE_1 | DOOR_CLOSE_2) #define DOOR_ACTION_1 (DOOR_OPEN_1 | DOOR_CLOSE_1) #define DOOR_ACTION_2 (DOOR_OPEN_2 | DOOR_CLOSE_2) #define DOOR_ACTION (DOOR_ACTION_1 | DOOR_ACTION_2) #define DOOR_COPY_BACK (1 << 4) #define DOOR_NO_COPY_BACK (1 << 5) #define DOOR_NO_DELAY (1 << 6) #define DOOR_FORCE_REDRAW (1 << 7) #define DOOR_GET_STATE (1 << 8) #define DOOR_SET_STATE (1 << 9) /* for Request */ #define REQ_ASK (1 << 0) #define REQ_CONFIRM (1 << 1) #define REQ_PLAYER (1 << 2) #define REQ_STAY_OPEN (1 << 3) #define REQ_STAY_CLOSED (1 << 4) #define REQ_REOPEN (1 << 5) #define REQUEST_WAIT_FOR_INPUT (REQ_ASK | REQ_CONFIRM | REQ_PLAYER) void DumpTile(int, int); void DrawMaskedBorder_FIELD(); void DrawMaskedBorder_DOOR_1(); void DrawMaskedBorder_DOOR_2(); void DrawMaskedBorder_DOOR_3(); void DrawMaskedBorder_ALL(); void DrawMaskedBorder(int); void SetDrawtoField(int); void RedrawPlayfield(boolean, int, int, int, int); void BackToFront(); void FadeIn(int); void FadeOut(int); void FadeSetEnterMenu(); void FadeSetLeaveMenu(); void FadeSetEnterScreen(); void FadeSetNextScreen(); void FadeSetLeaveScreen(); void FadeSetFromType(int); void FadeSetDisabled(); void FadeSkipNextFadeIn(); void FadeSkipNextFadeOut(); void ClearField(); void SetWindowBackgroundImageIfDefined(int); void SetMainBackgroundImageIfDefined(int); void SetDoorBackgroundImageIfDefined(int); void SetWindowBackgroundImage(int); void SetMainBackgroundImage(int); void SetDoorBackgroundImage(int); void SetPanelBackground(); void DrawBackground(int, int, int, int); void DrawBackgroundForFont(int, int, int, int, int); void DrawBackgroundForGraphic(int, int, int, int, int); void MarkTileDirty(int, int); void SetBorderElement(); void FloodFillLevel(int, int, int, short[MAX_LEV_FIELDX][MAX_LEV_FIELDY], int, int); void SetRandomAnimationValue(int, int); int getGraphicAnimationFrame(int, int); void DrawGraphicAnimationExt(DrawBuffer *, int, int, int, int, int); void DrawGraphicAnimation(int, int, int); void DrawLevelGraphicAnimation(int, int, int); void DrawLevelElementAnimation(int, int, int); void DrawLevelGraphicAnimationIfNeeded(int, int, int); void DrawLevelElementAnimationIfNeeded(int, int, int); void DrawAllPlayers(void); void DrawPlayerField(int, int); void DrawPlayer(struct PlayerInfo *); void getSizedGraphicSource(int, int, int, Bitmap **, int *, int *); void getMiniGraphicSource(int, Bitmap **, int *, int *); void getGraphicSourceExt(int, int, Bitmap **, int *, int *, boolean); void getGraphicSource(int, int, Bitmap **, int *, int *); void DrawGraphic(int, int, int, int); void DrawGraphicExt(DrawBuffer *, int, int, int, int); void DrawGraphicThruMask(int, int, int, int); void DrawGraphicThruMaskExt(DrawBuffer *, int, int, int, int); void DrawSizedGraphic(int, int, int, int, int); void DrawSizedGraphicExt(DrawBuffer *, int, int, int, int, int); void DrawMiniGraphic(int, int, int); void DrawMiniGraphicExt(DrawBuffer *, int, int, int); void DrawScreenElementExt(int, int, int, int, int, int, int); void DrawLevelElementExt(int, int, int, int, int, int, int); void DrawScreenElementShifted(int, int, int, int, int, int); void DrawLevelElementShifted(int, int, int, int, int, int); void DrawScreenElementThruMask(int, int, int); void DrawLevelElementThruMask(int, int, int); void DrawLevelFieldThruMask(int, int); void DrawLevelFieldCrumbled(int, int); void DrawLevelFieldCrumbledDigging(int, int, int, int); void DrawLevelFieldCrumbledNeighbours(int, int); void DrawScreenElement(int, int, int); void DrawLevelElement(int, int, int); void DrawScreenField(int, int); void DrawLevelField(int, int); void DrawMiniElement(int, int, int); void DrawMiniElementOrWall(int, int, int, int); void ShowEnvelope(int); void ShowEnvelopeDoor(char *text, int); void DrawLevel(void); void DrawMiniLevel(int, int, int, int); void DrawPreviewLevel(boolean); void WaitForEventToContinue(); boolean Request(char *, unsigned int); unsigned int OpenDoor(unsigned int); unsigned int CloseDoor(unsigned int); unsigned int GetDoorState(void); unsigned int SetDoorState(unsigned int); unsigned int MoveDoor(unsigned int); void DrawSpecialEditorDoor(); void UndrawSpecialEditorDoor(); void CreateToolButtons(); void FreeToolButtons(); int map_element_RND_to_EM(int); int map_element_EM_to_RND(int); int map_direction_RND_to_EM(int); int map_direction_EM_to_RND(int); void map_android_clone_elements_RND_to_EM(struct LevelInfo *); void map_android_clone_elements_EM_to_RND(struct LevelInfo *); int map_element_RND_to_SP(int); int map_element_SP_to_RND(int); int map_action_SP_to_RND(int); int get_next_element(int); int el_act_dir2img(int, int, int); int el_act2img(int, int); int el_dir2img(int, int); int el2baseimg(int); int el2img(int); int el2edimg(int); int el2preimg(int); int el2panelimg(int); int font2baseimg(int); int getBeltNrFromBeltElement(int); int getBeltNrFromBeltActiveElement(int); int getBeltNrFromBeltSwitchElement(int); int getBeltDirNrFromBeltElement(int); int getBeltDirNrFromBeltSwitchElement(int); int getBeltDirFromBeltElement(int); int getBeltDirFromBeltSwitchElement(int); int getBeltElementFromBeltNrAndBeltDirNr(int, int); int getBeltElementFromBeltNrAndBeltDir(int, int); int getBeltSwitchElementFromBeltNrAndBeltDirNr(int, int); int getBeltSwitchElementFromBeltNrAndBeltDir(int, int); unsigned int InitRND(long); void InitGraphicInfo_EM(void); void PlayMenuSoundExt(int); void PlayMenuSound(); void PlayMenuSoundStereo(int, int); void PlayMenuSoundIfLoopExt(int); void PlayMenuSoundIfLoop(); void PlayMenuMusicExt(int); void PlayMenuMusic(); void PlaySoundActivating(); void PlaySoundSelecting(); void ToggleFullscreenIfNeeded(); void ChangeViewportPropertiesIfNeeded(); #endif /* TOOLS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_chr.h0000644000175000017500000002041011375255512017352 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_chr.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CHR_H #define CONF_CHR_H /* values for elements configuration (character elements) */ #define EL_CHAR_SPACE (EL_CHAR_ASCII0 + 32) #define EL_CHAR_EXCLAM (EL_CHAR_ASCII0 + 33) #define EL_CHAR_QUOTEDBL (EL_CHAR_ASCII0 + 34) #define EL_CHAR_NUMBERSIGN (EL_CHAR_ASCII0 + 35) #define EL_CHAR_DOLLAR (EL_CHAR_ASCII0 + 36) #define EL_CHAR_PERCENT (EL_CHAR_ASCII0 + 37) #define EL_CHAR_AMPERSAND (EL_CHAR_ASCII0 + 38) #define EL_CHAR_APOSTROPHE (EL_CHAR_ASCII0 + 39) #define EL_CHAR_PARENLEFT (EL_CHAR_ASCII0 + 40) #define EL_CHAR_PARENRIGHT (EL_CHAR_ASCII0 + 41) #define EL_CHAR_ASTERISK (EL_CHAR_ASCII0 + 42) #define EL_CHAR_PLUS (EL_CHAR_ASCII0 + 43) #define EL_CHAR_COMMA (EL_CHAR_ASCII0 + 44) #define EL_CHAR_MINUS (EL_CHAR_ASCII0 + 45) #define EL_CHAR_PERIOD (EL_CHAR_ASCII0 + 46) #define EL_CHAR_SLASH (EL_CHAR_ASCII0 + 47) #define EL_CHAR_0 (EL_CHAR_ASCII0 + 48) #define EL_CHAR_1 (EL_CHAR_ASCII0 + 49) #define EL_CHAR_2 (EL_CHAR_ASCII0 + 50) #define EL_CHAR_3 (EL_CHAR_ASCII0 + 51) #define EL_CHAR_4 (EL_CHAR_ASCII0 + 52) #define EL_CHAR_5 (EL_CHAR_ASCII0 + 53) #define EL_CHAR_6 (EL_CHAR_ASCII0 + 54) #define EL_CHAR_7 (EL_CHAR_ASCII0 + 55) #define EL_CHAR_8 (EL_CHAR_ASCII0 + 56) #define EL_CHAR_9 (EL_CHAR_ASCII0 + 57) #define EL_CHAR_COLON (EL_CHAR_ASCII0 + 58) #define EL_CHAR_SEMICOLON (EL_CHAR_ASCII0 + 59) #define EL_CHAR_LESS (EL_CHAR_ASCII0 + 60) #define EL_CHAR_EQUAL (EL_CHAR_ASCII0 + 61) #define EL_CHAR_GREATER (EL_CHAR_ASCII0 + 62) #define EL_CHAR_QUESTION (EL_CHAR_ASCII0 + 63) #define EL_CHAR_AT (EL_CHAR_ASCII0 + 64) #define EL_CHAR_A (EL_CHAR_ASCII0 + 65) #define EL_CHAR_B (EL_CHAR_ASCII0 + 66) #define EL_CHAR_C (EL_CHAR_ASCII0 + 67) #define EL_CHAR_D (EL_CHAR_ASCII0 + 68) #define EL_CHAR_E (EL_CHAR_ASCII0 + 69) #define EL_CHAR_F (EL_CHAR_ASCII0 + 70) #define EL_CHAR_G (EL_CHAR_ASCII0 + 71) #define EL_CHAR_H (EL_CHAR_ASCII0 + 72) #define EL_CHAR_I (EL_CHAR_ASCII0 + 73) #define EL_CHAR_J (EL_CHAR_ASCII0 + 74) #define EL_CHAR_K (EL_CHAR_ASCII0 + 75) #define EL_CHAR_L (EL_CHAR_ASCII0 + 76) #define EL_CHAR_M (EL_CHAR_ASCII0 + 77) #define EL_CHAR_N (EL_CHAR_ASCII0 + 78) #define EL_CHAR_O (EL_CHAR_ASCII0 + 79) #define EL_CHAR_P (EL_CHAR_ASCII0 + 80) #define EL_CHAR_Q (EL_CHAR_ASCII0 + 81) #define EL_CHAR_R (EL_CHAR_ASCII0 + 82) #define EL_CHAR_S (EL_CHAR_ASCII0 + 83) #define EL_CHAR_T (EL_CHAR_ASCII0 + 84) #define EL_CHAR_U (EL_CHAR_ASCII0 + 85) #define EL_CHAR_V (EL_CHAR_ASCII0 + 86) #define EL_CHAR_W (EL_CHAR_ASCII0 + 87) #define EL_CHAR_X (EL_CHAR_ASCII0 + 88) #define EL_CHAR_Y (EL_CHAR_ASCII0 + 89) #define EL_CHAR_Z (EL_CHAR_ASCII0 + 90) #define EL_CHAR_BRACKETLEFT (EL_CHAR_ASCII0 + 91) #define EL_CHAR_BACKSLASH (EL_CHAR_ASCII0 + 92) #define EL_CHAR_BRACKETRIGHT (EL_CHAR_ASCII0 + 93) #define EL_CHAR_ASCIICIRCUM (EL_CHAR_ASCII0 + 94) #define EL_CHAR_UNDERSCORE (EL_CHAR_ASCII0 + 95) #define EL_CHAR_COPYRIGHT (EL_CHAR_ASCII0 + 96) #define EL_CHAR_AUMLAUT (EL_CHAR_ASCII0 + 97) #define EL_CHAR_OUMLAUT (EL_CHAR_ASCII0 + 98) #define EL_CHAR_UUMLAUT (EL_CHAR_ASCII0 + 99) #define EL_CHAR_DEGREE (EL_CHAR_ASCII0 + 100) #define EL_CHAR_TRADEMARK (EL_CHAR_ASCII0 + 101) #define EL_CHAR_CURSOR (EL_CHAR_ASCII0 + 102) #define EL_CHAR_BUTTON (EL_CHAR_ASCII0 + 109) #define EL_CHAR_UP (EL_CHAR_ASCII0 + 110) #define EL_CHAR_DOWN (EL_CHAR_ASCII0 + 111) #define EL_STEEL_CHAR_SPACE (EL_STEEL_CHAR_ASCII0 + 32) #define EL_STEEL_CHAR_EXCLAM (EL_STEEL_CHAR_ASCII0 + 33) #define EL_STEEL_CHAR_QUOTEDBL (EL_STEEL_CHAR_ASCII0 + 34) #define EL_STEEL_CHAR_NUMBERSIGN (EL_STEEL_CHAR_ASCII0 + 35) #define EL_STEEL_CHAR_DOLLAR (EL_STEEL_CHAR_ASCII0 + 36) #define EL_STEEL_CHAR_PERCENT (EL_STEEL_CHAR_ASCII0 + 37) #define EL_STEEL_CHAR_AMPERSAND (EL_STEEL_CHAR_ASCII0 + 38) #define EL_STEEL_CHAR_APOSTROPHE (EL_STEEL_CHAR_ASCII0 + 39) #define EL_STEEL_CHAR_PARENLEFT (EL_STEEL_CHAR_ASCII0 + 40) #define EL_STEEL_CHAR_PARENRIGHT (EL_STEEL_CHAR_ASCII0 + 41) #define EL_STEEL_CHAR_ASTERISK (EL_STEEL_CHAR_ASCII0 + 42) #define EL_STEEL_CHAR_PLUS (EL_STEEL_CHAR_ASCII0 + 43) #define EL_STEEL_CHAR_COMMA (EL_STEEL_CHAR_ASCII0 + 44) #define EL_STEEL_CHAR_MINUS (EL_STEEL_CHAR_ASCII0 + 45) #define EL_STEEL_CHAR_PERIOD (EL_STEEL_CHAR_ASCII0 + 46) #define EL_STEEL_CHAR_SLASH (EL_STEEL_CHAR_ASCII0 + 47) #define EL_STEEL_CHAR_0 (EL_STEEL_CHAR_ASCII0 + 48) #define EL_STEEL_CHAR_1 (EL_STEEL_CHAR_ASCII0 + 49) #define EL_STEEL_CHAR_2 (EL_STEEL_CHAR_ASCII0 + 50) #define EL_STEEL_CHAR_3 (EL_STEEL_CHAR_ASCII0 + 51) #define EL_STEEL_CHAR_4 (EL_STEEL_CHAR_ASCII0 + 52) #define EL_STEEL_CHAR_5 (EL_STEEL_CHAR_ASCII0 + 53) #define EL_STEEL_CHAR_6 (EL_STEEL_CHAR_ASCII0 + 54) #define EL_STEEL_CHAR_7 (EL_STEEL_CHAR_ASCII0 + 55) #define EL_STEEL_CHAR_8 (EL_STEEL_CHAR_ASCII0 + 56) #define EL_STEEL_CHAR_9 (EL_STEEL_CHAR_ASCII0 + 57) #define EL_STEEL_CHAR_COLON (EL_STEEL_CHAR_ASCII0 + 58) #define EL_STEEL_CHAR_SEMICOLON (EL_STEEL_CHAR_ASCII0 + 59) #define EL_STEEL_CHAR_LESS (EL_STEEL_CHAR_ASCII0 + 60) #define EL_STEEL_CHAR_EQUAL (EL_STEEL_CHAR_ASCII0 + 61) #define EL_STEEL_CHAR_GREATER (EL_STEEL_CHAR_ASCII0 + 62) #define EL_STEEL_CHAR_QUESTION (EL_STEEL_CHAR_ASCII0 + 63) #define EL_STEEL_CHAR_AT (EL_STEEL_CHAR_ASCII0 + 64) #define EL_STEEL_CHAR_A (EL_STEEL_CHAR_ASCII0 + 65) #define EL_STEEL_CHAR_B (EL_STEEL_CHAR_ASCII0 + 66) #define EL_STEEL_CHAR_C (EL_STEEL_CHAR_ASCII0 + 67) #define EL_STEEL_CHAR_D (EL_STEEL_CHAR_ASCII0 + 68) #define EL_STEEL_CHAR_E (EL_STEEL_CHAR_ASCII0 + 69) #define EL_STEEL_CHAR_F (EL_STEEL_CHAR_ASCII0 + 70) #define EL_STEEL_CHAR_G (EL_STEEL_CHAR_ASCII0 + 71) #define EL_STEEL_CHAR_H (EL_STEEL_CHAR_ASCII0 + 72) #define EL_STEEL_CHAR_I (EL_STEEL_CHAR_ASCII0 + 73) #define EL_STEEL_CHAR_J (EL_STEEL_CHAR_ASCII0 + 74) #define EL_STEEL_CHAR_K (EL_STEEL_CHAR_ASCII0 + 75) #define EL_STEEL_CHAR_L (EL_STEEL_CHAR_ASCII0 + 76) #define EL_STEEL_CHAR_M (EL_STEEL_CHAR_ASCII0 + 77) #define EL_STEEL_CHAR_N (EL_STEEL_CHAR_ASCII0 + 78) #define EL_STEEL_CHAR_O (EL_STEEL_CHAR_ASCII0 + 79) #define EL_STEEL_CHAR_P (EL_STEEL_CHAR_ASCII0 + 80) #define EL_STEEL_CHAR_Q (EL_STEEL_CHAR_ASCII0 + 81) #define EL_STEEL_CHAR_R (EL_STEEL_CHAR_ASCII0 + 82) #define EL_STEEL_CHAR_S (EL_STEEL_CHAR_ASCII0 + 83) #define EL_STEEL_CHAR_T (EL_STEEL_CHAR_ASCII0 + 84) #define EL_STEEL_CHAR_U (EL_STEEL_CHAR_ASCII0 + 85) #define EL_STEEL_CHAR_V (EL_STEEL_CHAR_ASCII0 + 86) #define EL_STEEL_CHAR_W (EL_STEEL_CHAR_ASCII0 + 87) #define EL_STEEL_CHAR_X (EL_STEEL_CHAR_ASCII0 + 88) #define EL_STEEL_CHAR_Y (EL_STEEL_CHAR_ASCII0 + 89) #define EL_STEEL_CHAR_Z (EL_STEEL_CHAR_ASCII0 + 90) #define EL_STEEL_CHAR_BRACKETLEFT (EL_STEEL_CHAR_ASCII0 + 91) #define EL_STEEL_CHAR_BACKSLASH (EL_STEEL_CHAR_ASCII0 + 92) #define EL_STEEL_CHAR_BRACKETRIGHT (EL_STEEL_CHAR_ASCII0 + 93) #define EL_STEEL_CHAR_ASCIICIRCUM (EL_STEEL_CHAR_ASCII0 + 94) #define EL_STEEL_CHAR_UNDERSCORE (EL_STEEL_CHAR_ASCII0 + 95) #define EL_STEEL_CHAR_COPYRIGHT (EL_STEEL_CHAR_ASCII0 + 96) #define EL_STEEL_CHAR_AUMLAUT (EL_STEEL_CHAR_ASCII0 + 97) #define EL_STEEL_CHAR_OUMLAUT (EL_STEEL_CHAR_ASCII0 + 98) #define EL_STEEL_CHAR_UUMLAUT (EL_STEEL_CHAR_ASCII0 + 99) #define EL_STEEL_CHAR_DEGREE (EL_STEEL_CHAR_ASCII0 + 100) #define EL_STEEL_CHAR_TRADEMARK (EL_STEEL_CHAR_ASCII0 + 101) #define EL_STEEL_CHAR_CURSOR (EL_STEEL_CHAR_ASCII0 + 102) #define EL_STEEL_CHAR_BUTTON (EL_STEEL_CHAR_ASCII0 + 109) #define EL_STEEL_CHAR_UP (EL_STEEL_CHAR_ASCII0 + 110) #define EL_STEEL_CHAR_DOWN (EL_STEEL_CHAR_ASCII0 + 111) #endif /* CONF_CHR_C */ rocksndiamonds-3.3.0.1+dfsg1/src/config.h0000644000175000017500000000201210556000313017017 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * config.h * ***********************************************************/ #ifndef CONFIG_H #define CONFIG_H #include "main.h" char *getCompileDateString(void); char *getProgramReleaseVersionString(void); char *getProgramFullVersionString(void); char *getProgramVersionString(void); char *getProgramInitString(void); char *getWindowTitleString(void); #endif /* CONFIG_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_gfx.h0000644000175000017500000020116711375255512017374 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_gfx.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GFX_H #define CONF_GFX_H /* values for graphics configuration (normal elements) */ #define IMG_BD_WALL 0 #define IMG_BD_WALL_EDITOR 1 #define IMG_BD_ROCK 2 #define IMG_BD_ROCK_EDITOR 3 #define IMG_BD_ROCK_MOVING_LEFT 4 #define IMG_BD_ROCK_MOVING_RIGHT 5 #define IMG_BD_ROCK_PUSHING_LEFT 6 #define IMG_BD_ROCK_PUSHING_RIGHT 7 #define IMG_BD_DIAMOND 8 #define IMG_BD_DIAMOND_MOVING 9 #define IMG_BD_DIAMOND_FALLING 10 #define IMG_BD_MAGIC_WALL 11 #define IMG_BD_MAGIC_WALL_ACTIVE 12 #define IMG_BD_MAGIC_WALL_FILLING 13 #define IMG_BD_MAGIC_WALL_FULL 14 #define IMG_BD_MAGIC_WALL_EMPTYING 15 #define IMG_BD_MAGIC_WALL_DEAD 16 #define IMG_BD_AMOEBA 17 #define IMG_BD_AMOEBA_EDITOR 18 #define IMG_BD_BUTTERFLY 19 #define IMG_BD_BUTTERFLY_RIGHT 20 #define IMG_BD_BUTTERFLY_RIGHT_EDITOR 21 #define IMG_BD_BUTTERFLY_UP 22 #define IMG_BD_BUTTERFLY_UP_EDITOR 23 #define IMG_BD_BUTTERFLY_LEFT 24 #define IMG_BD_BUTTERFLY_LEFT_EDITOR 25 #define IMG_BD_BUTTERFLY_DOWN 26 #define IMG_BD_BUTTERFLY_DOWN_EDITOR 27 #define IMG_BD_FIREFLY 28 #define IMG_BD_FIREFLY_RIGHT 29 #define IMG_BD_FIREFLY_RIGHT_EDITOR 30 #define IMG_BD_FIREFLY_UP 31 #define IMG_BD_FIREFLY_UP_EDITOR 32 #define IMG_BD_FIREFLY_LEFT 33 #define IMG_BD_FIREFLY_LEFT_EDITOR 34 #define IMG_BD_FIREFLY_DOWN 35 #define IMG_BD_FIREFLY_DOWN_EDITOR 36 #define IMG_SP_DEFAULT_EXPLODING 37 #define IMG_SP_ZONK 38 #define IMG_SP_ZONK_MOVING_LEFT 39 #define IMG_SP_ZONK_MOVING_RIGHT 40 #define IMG_SP_ZONK_PUSHING_LEFT 41 #define IMG_SP_ZONK_PUSHING_RIGHT 42 #define IMG_SP_BASE 43 #define IMG_SP_BASE_DIGGING 44 #define IMG_SP_BASE_SNAPPING 45 #define IMG_SP_MURPHY 46 #define IMG_SP_MURPHY_MOVING_LEFT 47 #define IMG_SP_MURPHY_MOVING_RIGHT 48 #define IMG_SP_MURPHY_DIGGING_LEFT 49 #define IMG_SP_MURPHY_DIGGING_RIGHT 50 #define IMG_SP_MURPHY_COLLECTING_LEFT 51 #define IMG_SP_MURPHY_COLLECTING_RIGHT 52 #define IMG_SP_MURPHY_PUSHING_LEFT 53 #define IMG_SP_MURPHY_PUSHING_RIGHT 54 #define IMG_SP_MURPHY_SNAPPING_LEFT 55 #define IMG_SP_MURPHY_SNAPPING_RIGHT 56 #define IMG_SP_MURPHY_SNAPPING_UP 57 #define IMG_SP_MURPHY_SNAPPING_DOWN 58 #define IMG_SP_MURPHY_BORING 59 #define IMG_SP_MURPHY_BORING_1 60 #define IMG_SP_MURPHY_SLEEPING_LEFT 61 #define IMG_SP_MURPHY_SLEEPING_RIGHT 62 #define IMG_SP_MURPHY_DROPPING 63 #define IMG_SP_MURPHY_SHRINKING 64 #define IMG_SP_MURPHY_CLONE 65 #define IMG_SP_INFOTRON 66 #define IMG_SP_INFOTRON_EDITOR 67 #define IMG_SP_INFOTRON_MOVING_LEFT 68 #define IMG_SP_INFOTRON_MOVING_RIGHT 69 #define IMG_SP_INFOTRON_COLLECTING 70 #define IMG_SP_CHIP_SINGLE 71 #define IMG_SP_CHIP_LEFT 72 #define IMG_SP_CHIP_RIGHT 73 #define IMG_SP_CHIP_TOP 74 #define IMG_SP_CHIP_BOTTOM 75 #define IMG_SP_HARDWARE_GRAY 76 #define IMG_SP_HARDWARE_GREEN 77 #define IMG_SP_HARDWARE_BLUE 78 #define IMG_SP_HARDWARE_RED 79 #define IMG_SP_HARDWARE_YELLOW 80 #define IMG_SP_EXIT_CLOSED 81 #define IMG_SP_EXIT_OPENING 82 #define IMG_SP_EXIT_OPEN 83 #define IMG_SP_EXIT_CLOSING 84 #define IMG_SP_DISK_ORANGE 85 #define IMG_SP_DISK_YELLOW 86 #define IMG_SP_DISK_RED 87 #define IMG_SP_DISK_RED_COLLECTING 88 #define IMG_SP_DISK_RED_ACTIVE 89 #define IMG_SP_PORT_RIGHT 90 #define IMG_SP_PORT_DOWN 91 #define IMG_SP_PORT_LEFT 92 #define IMG_SP_PORT_UP 93 #define IMG_SP_PORT_HORIZONTAL 94 #define IMG_SP_PORT_VERTICAL 95 #define IMG_SP_PORT_ANY 96 #define IMG_SP_GRAVITY_PORT_RIGHT 97 #define IMG_SP_GRAVITY_PORT_RIGHT_EDITOR 98 #define IMG_SP_GRAVITY_PORT_DOWN 99 #define IMG_SP_GRAVITY_PORT_DOWN_EDITOR 100 #define IMG_SP_GRAVITY_PORT_LEFT 101 #define IMG_SP_GRAVITY_PORT_LEFT_EDITOR 102 #define IMG_SP_GRAVITY_PORT_UP 103 #define IMG_SP_GRAVITY_PORT_UP_EDITOR 104 #define IMG_SP_GRAVITY_ON_PORT_RIGHT 105 #define IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR 106 #define IMG_SP_GRAVITY_ON_PORT_DOWN 107 #define IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR 108 #define IMG_SP_GRAVITY_ON_PORT_LEFT 109 #define IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR 110 #define IMG_SP_GRAVITY_ON_PORT_UP 111 #define IMG_SP_GRAVITY_ON_PORT_UP_EDITOR 112 #define IMG_SP_GRAVITY_OFF_PORT_RIGHT 113 #define IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR 114 #define IMG_SP_GRAVITY_OFF_PORT_DOWN 115 #define IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR 116 #define IMG_SP_GRAVITY_OFF_PORT_LEFT 117 #define IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR 118 #define IMG_SP_GRAVITY_OFF_PORT_UP 119 #define IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR 120 #define IMG_SP_SNIKSNAK 121 #define IMG_SP_SNIKSNAK_LEFT 122 #define IMG_SP_SNIKSNAK_RIGHT 123 #define IMG_SP_SNIKSNAK_UP 124 #define IMG_SP_SNIKSNAK_DOWN 125 #define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP 126 #define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN 127 #define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP 128 #define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN 129 #define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT 130 #define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT 131 #define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT 132 #define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT 133 #define IMG_SP_ELECTRON 134 #define IMG_SP_ELECTRON_EDITOR 135 #define IMG_SP_ELECTRON_EXPLODING 136 #define IMG_SP_TERMINAL 137 #define IMG_SP_TERMINAL_EDITOR 138 #define IMG_SP_TERMINAL_ACTIVE 139 #define IMG_SP_BUGGY_BASE 140 #define IMG_SP_BUGGY_BASE_EDITOR 141 #define IMG_SP_BUGGY_BASE_ACTIVATING 142 #define IMG_SP_BUGGY_BASE_ACTIVE 143 #define IMG_SP_HARDWARE_BASE_1 144 #define IMG_SP_HARDWARE_BASE_2 145 #define IMG_SP_HARDWARE_BASE_3 146 #define IMG_SP_HARDWARE_BASE_4 147 #define IMG_SP_HARDWARE_BASE_5 148 #define IMG_SP_HARDWARE_BASE_6 149 #define IMG_SOKOBAN_OBJECT 150 #define IMG_SOKOBAN_OBJECT_EDITOR 151 #define IMG_SOKOBAN_FIELD_EMPTY 152 #define IMG_SOKOBAN_FIELD_FULL 153 #define IMG_SOKOBAN_FIELD_PLAYER 154 #define IMG_SOKOBAN_FIELD_PLAYER_EDITOR 155 #define IMG_EMPTY_SPACE 156 #define IMG_SAND 157 #define IMG_SAND_CRUMBLED 158 #define IMG_SAND_DIGGING_LEFT 159 #define IMG_SAND_DIGGING_RIGHT 160 #define IMG_SAND_DIGGING_UP 161 #define IMG_SAND_DIGGING_DOWN 162 #define IMG_SAND_DIGGING_LEFT_CRUMBLED 163 #define IMG_SAND_DIGGING_RIGHT_CRUMBLED 164 #define IMG_SAND_DIGGING_UP_CRUMBLED 165 #define IMG_SAND_DIGGING_DOWN_CRUMBLED 166 #define IMG_WALL 167 #define IMG_WALL_SLIPPERY 168 #define IMG_STEELWALL 169 #define IMG_ROCK 170 #define IMG_ROCK_MOVING_LEFT 171 #define IMG_ROCK_MOVING_RIGHT 172 #define IMG_ROCK_PUSHING_LEFT 173 #define IMG_ROCK_PUSHING_RIGHT 174 #define IMG_EMERALD 175 #define IMG_EMERALD_MOVING 176 #define IMG_EMERALD_FALLING 177 #define IMG_EMERALD_COLLECTING 178 #define IMG_DIAMOND 179 #define IMG_DIAMOND_MOVING 180 #define IMG_DIAMOND_FALLING 181 #define IMG_DIAMOND_COLLECTING 182 #define IMG_BOMB 183 #define IMG_NUT 184 #define IMG_NUT_BREAKING 185 #define IMG_DYNAMITE 186 #define IMG_DYNAMITE_EDITOR 187 #define IMG_DYNAMITE_ACTIVE 188 #define IMG_DYNAMITE_ACTIVE_EDITOR 189 #define IMG_EM_DYNAMITE 190 #define IMG_EM_DYNAMITE_ACTIVE 191 #define IMG_EM_DYNAMITE_ACTIVE_EDITOR 192 #define IMG_WALL_EMERALD 193 #define IMG_WALL_DIAMOND 194 #define IMG_BUG 195 #define IMG_BUG_RIGHT 196 #define IMG_BUG_UP 197 #define IMG_BUG_LEFT 198 #define IMG_BUG_DOWN 199 #define IMG_BUG_MOVING_RIGHT 200 #define IMG_BUG_MOVING_UP 201 #define IMG_BUG_MOVING_LEFT 202 #define IMG_BUG_MOVING_DOWN 203 #define IMG_BUG_TURNING_FROM_RIGHT_UP 204 #define IMG_BUG_TURNING_FROM_UP_LEFT 205 #define IMG_BUG_TURNING_FROM_LEFT_DOWN 206 #define IMG_BUG_TURNING_FROM_DOWN_RIGHT 207 #define IMG_BUG_TURNING_FROM_RIGHT_DOWN 208 #define IMG_BUG_TURNING_FROM_UP_RIGHT 209 #define IMG_BUG_TURNING_FROM_LEFT_UP 210 #define IMG_BUG_TURNING_FROM_DOWN_LEFT 211 #define IMG_SPACESHIP 212 #define IMG_SPACESHIP_RIGHT 213 #define IMG_SPACESHIP_UP 214 #define IMG_SPACESHIP_LEFT 215 #define IMG_SPACESHIP_DOWN 216 #define IMG_SPACESHIP_MOVING_RIGHT 217 #define IMG_SPACESHIP_MOVING_UP 218 #define IMG_SPACESHIP_MOVING_LEFT 219 #define IMG_SPACESHIP_MOVING_DOWN 220 #define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP 221 #define IMG_SPACESHIP_TURNING_FROM_UP_LEFT 222 #define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN 223 #define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT 224 #define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN 225 #define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT 226 #define IMG_SPACESHIP_TURNING_FROM_LEFT_UP 227 #define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT 228 #define IMG_YAMYAM 229 #define IMG_YAMYAM_LEFT 230 #define IMG_YAMYAM_LEFT_EDITOR 231 #define IMG_YAMYAM_RIGHT 232 #define IMG_YAMYAM_RIGHT_EDITOR 233 #define IMG_YAMYAM_UP 234 #define IMG_YAMYAM_UP_EDITOR 235 #define IMG_YAMYAM_DOWN 236 #define IMG_YAMYAM_DOWN_EDITOR 237 #define IMG_YAMYAM_MOVING 238 #define IMG_ROBOT 239 #define IMG_ROBOT_MOVING 240 #define IMG_ROBOT_WHEEL 241 #define IMG_ROBOT_WHEEL_ACTIVE 242 #define IMG_MAGIC_WALL 243 #define IMG_MAGIC_WALL_ACTIVE 244 #define IMG_MAGIC_WALL_FILLING 245 #define IMG_MAGIC_WALL_FULL 246 #define IMG_MAGIC_WALL_EMPTYING 247 #define IMG_MAGIC_WALL_DEAD 248 #define IMG_DC_MAGIC_WALL 249 #define IMG_DC_MAGIC_WALL_ACTIVE 250 #define IMG_DC_MAGIC_WALL_FILLING 251 #define IMG_DC_MAGIC_WALL_FULL 252 #define IMG_DC_MAGIC_WALL_EMPTYING 253 #define IMG_DC_MAGIC_WALL_DEAD 254 #define IMG_QUICKSAND_EMPTY 255 #define IMG_QUICKSAND_FILLING 256 #define IMG_QUICKSAND_FULL 257 #define IMG_QUICKSAND_FULL_EDITOR 258 #define IMG_QUICKSAND_EMPTYING 259 #define IMG_QUICKSAND_FAST_EMPTY 260 #define IMG_QUICKSAND_FAST_FILLING 261 #define IMG_QUICKSAND_FAST_FULL 262 #define IMG_QUICKSAND_FAST_FULL_EDITOR 263 #define IMG_QUICKSAND_FAST_EMPTYING 264 #define IMG_ACID_POOL_TOPLEFT 265 #define IMG_ACID_POOL_TOPRIGHT 266 #define IMG_ACID_POOL_BOTTOMLEFT 267 #define IMG_ACID_POOL_BOTTOM 268 #define IMG_ACID_POOL_BOTTOMRIGHT 269 #define IMG_ACID 270 #define IMG_ACID_SPLASH_LEFT 271 #define IMG_ACID_SPLASH_RIGHT 272 #define IMG_AMOEBA_DROP 273 #define IMG_AMOEBA_GROWING 274 #define IMG_AMOEBA_SHRINKING 275 #define IMG_AMOEBA_WET 276 #define IMG_AMOEBA_WET_EDITOR 277 #define IMG_AMOEBA_DROPPING 278 #define IMG_AMOEBA_DRY 279 #define IMG_AMOEBA_FULL 280 #define IMG_AMOEBA_FULL_EDITOR 281 #define IMG_AMOEBA_DEAD 282 #define IMG_AMOEBA_DEAD_EDITOR 283 #define IMG_EM_KEY_1 284 #define IMG_EM_KEY_2 285 #define IMG_EM_KEY_3 286 #define IMG_EM_KEY_4 287 #define IMG_DC_KEY_WHITE 288 #define IMG_EM_GATE_1 289 #define IMG_EM_GATE_2 290 #define IMG_EM_GATE_3 291 #define IMG_EM_GATE_4 292 #define IMG_DC_GATE_WHITE 293 #define IMG_EM_GATE_1_GRAY 294 #define IMG_EM_GATE_1_GRAY_EDITOR 295 #define IMG_EM_GATE_1_GRAY_ACTIVE 296 #define IMG_EM_GATE_2_GRAY 297 #define IMG_EM_GATE_2_GRAY_EDITOR 298 #define IMG_EM_GATE_2_GRAY_ACTIVE 299 #define IMG_EM_GATE_3_GRAY 300 #define IMG_EM_GATE_3_GRAY_EDITOR 301 #define IMG_EM_GATE_3_GRAY_ACTIVE 302 #define IMG_EM_GATE_4_GRAY 303 #define IMG_EM_GATE_4_GRAY_EDITOR 304 #define IMG_EM_GATE_4_GRAY_ACTIVE 305 #define IMG_DC_GATE_WHITE_GRAY 306 #define IMG_DC_GATE_WHITE_GRAY_EDITOR 307 #define IMG_DC_GATE_WHITE_GRAY_ACTIVE 308 #define IMG_DC_GATE_FAKE_GRAY 309 #define IMG_EXIT_CLOSED 310 #define IMG_EXIT_OPENING 311 #define IMG_EXIT_OPEN 312 #define IMG_EXIT_CLOSING 313 #define IMG_STEEL_EXIT_CLOSED 314 #define IMG_STEEL_EXIT_OPENING 315 #define IMG_STEEL_EXIT_OPEN 316 #define IMG_STEEL_EXIT_CLOSING 317 #define IMG_EM_EXIT_CLOSED 318 #define IMG_EM_EXIT_OPENING 319 #define IMG_EM_EXIT_OPEN 320 #define IMG_EM_EXIT_CLOSING 321 #define IMG_EM_STEEL_EXIT_CLOSED 322 #define IMG_EM_STEEL_EXIT_OPENING 323 #define IMG_EM_STEEL_EXIT_OPEN 324 #define IMG_EM_STEEL_EXIT_CLOSING 325 #define IMG_BALLOON 326 #define IMG_BALLOON_MOVING 327 #define IMG_BALLOON_PUSHING 328 #define IMG_BALLOON_SWITCH_LEFT 329 #define IMG_BALLOON_SWITCH_RIGHT 330 #define IMG_BALLOON_SWITCH_UP 331 #define IMG_BALLOON_SWITCH_DOWN 332 #define IMG_BALLOON_SWITCH_ANY 333 #define IMG_BALLOON_SWITCH_NONE 334 #define IMG_SPRING 335 #define IMG_EMC_STEELWALL_1 336 #define IMG_EMC_STEELWALL_2 337 #define IMG_EMC_STEELWALL_3 338 #define IMG_EMC_STEELWALL_4 339 #define IMG_EMC_WALL_1 340 #define IMG_EMC_WALL_2 341 #define IMG_EMC_WALL_3 342 #define IMG_EMC_WALL_4 343 #define IMG_EMC_WALL_5 344 #define IMG_EMC_WALL_6 345 #define IMG_EMC_WALL_7 346 #define IMG_EMC_WALL_8 347 #define IMG_INVISIBLE_STEELWALL 348 #define IMG_INVISIBLE_STEELWALL_EDITOR 349 #define IMG_INVISIBLE_STEELWALL_ACTIVE 350 #define IMG_INVISIBLE_WALL 351 #define IMG_INVISIBLE_WALL_EDITOR 352 #define IMG_INVISIBLE_WALL_ACTIVE 353 #define IMG_INVISIBLE_SAND 354 #define IMG_INVISIBLE_SAND_EDITOR 355 #define IMG_INVISIBLE_SAND_ACTIVE 356 #define IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED 357 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT 358 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT 359 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP 360 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN 361 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED 362 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED 363 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED 364 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED 365 #define IMG_CONVEYOR_BELT_1_MIDDLE 366 #define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE 367 #define IMG_CONVEYOR_BELT_1_LEFT 368 #define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE 369 #define IMG_CONVEYOR_BELT_1_RIGHT 370 #define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE 371 #define IMG_CONVEYOR_BELT_1_SWITCH_LEFT 372 #define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE 373 #define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT 374 #define IMG_CONVEYOR_BELT_2_MIDDLE 375 #define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE 376 #define IMG_CONVEYOR_BELT_2_LEFT 377 #define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE 378 #define IMG_CONVEYOR_BELT_2_RIGHT 379 #define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE 380 #define IMG_CONVEYOR_BELT_2_SWITCH_LEFT 381 #define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE 382 #define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT 383 #define IMG_CONVEYOR_BELT_3_MIDDLE 384 #define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE 385 #define IMG_CONVEYOR_BELT_3_LEFT 386 #define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE 387 #define IMG_CONVEYOR_BELT_3_RIGHT 388 #define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE 389 #define IMG_CONVEYOR_BELT_3_SWITCH_LEFT 390 #define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE 391 #define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT 392 #define IMG_CONVEYOR_BELT_4_MIDDLE 393 #define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE 394 #define IMG_CONVEYOR_BELT_4_LEFT 395 #define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE 396 #define IMG_CONVEYOR_BELT_4_RIGHT 397 #define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE 398 #define IMG_CONVEYOR_BELT_4_SWITCH_LEFT 399 #define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE 400 #define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT 401 #define IMG_SWITCHGATE_SWITCH_UP 402 #define IMG_SWITCHGATE_SWITCH_DOWN 403 #define IMG_DC_SWITCHGATE_SWITCH_UP 404 #define IMG_DC_SWITCHGATE_SWITCH_DOWN 405 #define IMG_LIGHT_SWITCH 406 #define IMG_LIGHT_SWITCH_ACTIVE 407 #define IMG_TIMEGATE_SWITCH 408 #define IMG_TIMEGATE_SWITCH_ACTIVE 409 #define IMG_DC_TIMEGATE_SWITCH 410 #define IMG_DC_TIMEGATE_SWITCH_ACTIVE 411 #define IMG_ENVELOPE_1 412 #define IMG_ENVELOPE_1_COLLECTING 413 #define IMG_ENVELOPE_2 414 #define IMG_ENVELOPE_2_COLLECTING 415 #define IMG_ENVELOPE_3 416 #define IMG_ENVELOPE_3_COLLECTING 417 #define IMG_ENVELOPE_4 418 #define IMG_ENVELOPE_4_COLLECTING 419 #define IMG_SIGN_RADIOACTIVITY 420 #define IMG_SIGN_GIVE_WAY 421 #define IMG_SIGN_NO_ENTRY 422 #define IMG_SIGN_EMERGENCY_EXIT 423 #define IMG_SIGN_YIN_YANG 424 #define IMG_SIGN_EXCLAMATION 425 #define IMG_SIGN_STOP 426 #define IMG_SIGN_PARKING 427 #define IMG_SIGN_WHEELCHAIR 428 #define IMG_SIGN_ENTRY_FORBIDDEN 429 #define IMG_SPERMS 430 #define IMG_BULLET 431 #define IMG_HEART 432 #define IMG_CROSS 433 #define IMG_FRANKIE 434 #define IMG_SIGN_SPERMS 435 #define IMG_SIGN_BULLET 436 #define IMG_SIGN_HEART 437 #define IMG_SIGN_CROSS 438 #define IMG_SIGN_FRANKIE 439 #define IMG_LANDMINE 440 #define IMG_DC_LANDMINE 441 #define IMG_STEELWALL_SLIPPERY 442 #define IMG_EXTRA_TIME 443 #define IMG_SHIELD_NORMAL 444 #define IMG_SHIELD_NORMAL_ACTIVE 445 #define IMG_SHIELD_DEADLY 446 #define IMG_SHIELD_DEADLY_ACTIVE 447 #define IMG_SWITCHGATE_CLOSED 448 #define IMG_SWITCHGATE_OPENING 449 #define IMG_SWITCHGATE_OPEN 450 #define IMG_SWITCHGATE_CLOSING 451 #define IMG_TIMEGATE_CLOSED 452 #define IMG_TIMEGATE_OPENING 453 #define IMG_TIMEGATE_OPEN 454 #define IMG_TIMEGATE_CLOSING 455 #define IMG_PEARL 456 #define IMG_PEARL_BREAKING 457 #define IMG_CRYSTAL 458 #define IMG_WALL_PEARL 459 #define IMG_WALL_CRYSTAL 460 #define IMG_DC_STEELWALL_1_LEFT 461 #define IMG_DC_STEELWALL_1_RIGHT 462 #define IMG_DC_STEELWALL_1_TOP 463 #define IMG_DC_STEELWALL_1_BOTTOM 464 #define IMG_DC_STEELWALL_1_HORIZONTAL 465 #define IMG_DC_STEELWALL_1_VERTICAL 466 #define IMG_DC_STEELWALL_1_TOPLEFT 467 #define IMG_DC_STEELWALL_1_TOPRIGHT 468 #define IMG_DC_STEELWALL_1_BOTTOMLEFT 469 #define IMG_DC_STEELWALL_1_BOTTOMRIGHT 470 #define IMG_DC_STEELWALL_1_TOPLEFT_2 471 #define IMG_DC_STEELWALL_1_TOPRIGHT_2 472 #define IMG_DC_STEELWALL_1_BOTTOMLEFT_2 473 #define IMG_DC_STEELWALL_1_BOTTOMRIGHT_2 474 #define IMG_DC_STEELWALL_2_LEFT 475 #define IMG_DC_STEELWALL_2_RIGHT 476 #define IMG_DC_STEELWALL_2_TOP 477 #define IMG_DC_STEELWALL_2_BOTTOM 478 #define IMG_DC_STEELWALL_2_HORIZONTAL 479 #define IMG_DC_STEELWALL_2_VERTICAL 480 #define IMG_DC_STEELWALL_2_MIDDLE 481 #define IMG_DC_STEELWALL_2_SINGLE 482 #define IMG_TUBE_RIGHT_DOWN 483 #define IMG_TUBE_HORIZONTAL_DOWN 484 #define IMG_TUBE_LEFT_DOWN 485 #define IMG_TUBE_HORIZONTAL 486 #define IMG_TUBE_VERTICAL_RIGHT 487 #define IMG_TUBE_ANY 488 #define IMG_TUBE_VERTICAL_LEFT 489 #define IMG_TUBE_VERTICAL 490 #define IMG_TUBE_RIGHT_UP 491 #define IMG_TUBE_HORIZONTAL_UP 492 #define IMG_TUBE_LEFT_UP 493 #define IMG_TRAP 494 #define IMG_TRAP_ACTIVE 495 #define IMG_DX_SUPABOMB 496 #define IMG_KEY_1 497 #define IMG_KEY_1_EDITOR 498 #define IMG_KEY_2 499 #define IMG_KEY_2_EDITOR 500 #define IMG_KEY_3 501 #define IMG_KEY_3_EDITOR 502 #define IMG_KEY_4 503 #define IMG_KEY_4_EDITOR 504 #define IMG_GATE_1 505 #define IMG_GATE_2 506 #define IMG_GATE_3 507 #define IMG_GATE_4 508 #define IMG_GATE_1_GRAY 509 #define IMG_GATE_1_GRAY_EDITOR 510 #define IMG_GATE_1_GRAY_ACTIVE 511 #define IMG_GATE_2_GRAY 512 #define IMG_GATE_2_GRAY_EDITOR 513 #define IMG_GATE_2_GRAY_ACTIVE 514 #define IMG_GATE_3_GRAY 515 #define IMG_GATE_3_GRAY_EDITOR 516 #define IMG_GATE_3_GRAY_ACTIVE 517 #define IMG_GATE_4_GRAY 518 #define IMG_GATE_4_GRAY_EDITOR 519 #define IMG_GATE_4_GRAY_ACTIVE 520 #define IMG_GAME_OF_LIFE 521 #define IMG_BIOMAZE 522 #define IMG_PACMAN 523 #define IMG_PACMAN_RIGHT 524 #define IMG_PACMAN_UP 525 #define IMG_PACMAN_LEFT 526 #define IMG_PACMAN_DOWN 527 #define IMG_PACMAN_TURNING_FROM_RIGHT 528 #define IMG_PACMAN_TURNING_FROM_UP 529 #define IMG_PACMAN_TURNING_FROM_LEFT 530 #define IMG_PACMAN_TURNING_FROM_DOWN 531 #define IMG_LAMP 532 #define IMG_LAMP_EDITOR 533 #define IMG_LAMP_ACTIVE 534 #define IMG_TIME_ORB_FULL 535 #define IMG_TIME_ORB_EMPTY 536 #define IMG_EMERALD_YELLOW 537 #define IMG_EMERALD_YELLOW_MOVING 538 #define IMG_EMERALD_YELLOW_FALLING 539 #define IMG_EMERALD_RED 540 #define IMG_EMERALD_RED_MOVING 541 #define IMG_EMERALD_RED_FALLING 542 #define IMG_EMERALD_PURPLE 543 #define IMG_EMERALD_PURPLE_MOVING 544 #define IMG_EMERALD_PURPLE_FALLING 545 #define IMG_WALL_EMERALD_YELLOW 546 #define IMG_WALL_EMERALD_RED 547 #define IMG_WALL_EMERALD_PURPLE 548 #define IMG_WALL_BD_DIAMOND 549 #define IMG_EXPANDABLE_WALL 550 #define IMG_EXPANDABLE_WALL_HORIZONTAL 551 #define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR 552 #define IMG_EXPANDABLE_WALL_VERTICAL 553 #define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR 554 #define IMG_EXPANDABLE_WALL_ANY 555 #define IMG_EXPANDABLE_WALL_ANY_EDITOR 556 #define IMG_EXPANDABLE_STEELWALL_HORIZONTAL 557 #define IMG_EXPANDABLE_STEELWALL_HORIZONTAL_EDITOR 558 #define IMG_EXPANDABLE_STEELWALL_VERTICAL 559 #define IMG_EXPANDABLE_STEELWALL_VERTICAL_EDITOR 560 #define IMG_EXPANDABLE_STEELWALL_ANY 561 #define IMG_EXPANDABLE_STEELWALL_ANY_EDITOR 562 #define IMG_BD_EXPANDABLE_WALL 563 #define IMG_BD_EXPANDABLE_WALL_EDITOR 564 #define IMG_EXPANDABLE_WALL_GROWING_LEFT 565 #define IMG_EXPANDABLE_WALL_GROWING_RIGHT 566 #define IMG_EXPANDABLE_WALL_GROWING_UP 567 #define IMG_EXPANDABLE_WALL_GROWING_DOWN 568 #define IMG_EXPANDABLE_STEELWALL_GROWING_LEFT 569 #define IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT 570 #define IMG_EXPANDABLE_STEELWALL_GROWING_UP 571 #define IMG_EXPANDABLE_STEELWALL_GROWING_DOWN 572 #define IMG_BLACK_ORB 573 #define IMG_SPEED_PILL 574 #define IMG_DARK_YAMYAM 575 #define IMG_DYNABOMB 576 #define IMG_DYNABOMB_ACTIVE 577 #define IMG_DYNABOMB_PLAYER_1 578 #define IMG_DYNABOMB_PLAYER_1_ACTIVE 579 #define IMG_DYNABOMB_PLAYER_2 580 #define IMG_DYNABOMB_PLAYER_2_ACTIVE 581 #define IMG_DYNABOMB_PLAYER_3 582 #define IMG_DYNABOMB_PLAYER_3_ACTIVE 583 #define IMG_DYNABOMB_PLAYER_4 584 #define IMG_DYNABOMB_PLAYER_4_ACTIVE 585 #define IMG_DYNABOMB_INCREASE_NUMBER 586 #define IMG_DYNABOMB_INCREASE_SIZE 587 #define IMG_DYNABOMB_INCREASE_POWER 588 #define IMG_PIG 589 #define IMG_PIG_DOWN 590 #define IMG_PIG_UP 591 #define IMG_PIG_LEFT 592 #define IMG_PIG_RIGHT 593 #define IMG_PIG_MOVING_DOWN 594 #define IMG_PIG_MOVING_UP 595 #define IMG_PIG_MOVING_LEFT 596 #define IMG_PIG_MOVING_RIGHT 597 #define IMG_PIG_DIGGING_DOWN 598 #define IMG_PIG_DIGGING_UP 599 #define IMG_PIG_DIGGING_LEFT 600 #define IMG_PIG_DIGGING_RIGHT 601 #define IMG_DRAGON 602 #define IMG_DRAGON_DOWN 603 #define IMG_DRAGON_UP 604 #define IMG_DRAGON_LEFT 605 #define IMG_DRAGON_RIGHT 606 #define IMG_DRAGON_MOVING_DOWN 607 #define IMG_DRAGON_MOVING_UP 608 #define IMG_DRAGON_MOVING_LEFT 609 #define IMG_DRAGON_MOVING_RIGHT 610 #define IMG_DRAGON_ATTACKING_DOWN 611 #define IMG_DRAGON_ATTACKING_UP 612 #define IMG_DRAGON_ATTACKING_LEFT 613 #define IMG_DRAGON_ATTACKING_RIGHT 614 #define IMG_MOLE 615 #define IMG_MOLE_DOWN 616 #define IMG_MOLE_UP 617 #define IMG_MOLE_LEFT 618 #define IMG_MOLE_RIGHT 619 #define IMG_MOLE_MOVING_DOWN 620 #define IMG_MOLE_MOVING_UP 621 #define IMG_MOLE_MOVING_LEFT 622 #define IMG_MOLE_MOVING_RIGHT 623 #define IMG_MOLE_DIGGING_DOWN 624 #define IMG_MOLE_DIGGING_UP 625 #define IMG_MOLE_DIGGING_LEFT 626 #define IMG_MOLE_DIGGING_RIGHT 627 #define IMG_PENGUIN 628 #define IMG_PENGUIN_EDITOR 629 #define IMG_PENGUIN_DOWN 630 #define IMG_PENGUIN_UP 631 #define IMG_PENGUIN_LEFT 632 #define IMG_PENGUIN_RIGHT 633 #define IMG_PENGUIN_MOVING_DOWN 634 #define IMG_PENGUIN_MOVING_UP 635 #define IMG_PENGUIN_MOVING_LEFT 636 #define IMG_PENGUIN_MOVING_RIGHT 637 #define IMG_SATELLITE 638 #define IMG_FLAMES_1_LEFT 639 #define IMG_FLAMES_2_LEFT 640 #define IMG_FLAMES_3_LEFT 641 #define IMG_FLAMES_1_RIGHT 642 #define IMG_FLAMES_2_RIGHT 643 #define IMG_FLAMES_3_RIGHT 644 #define IMG_FLAMES_1_UP 645 #define IMG_FLAMES_2_UP 646 #define IMG_FLAMES_3_UP 647 #define IMG_FLAMES_1_DOWN 648 #define IMG_FLAMES_2_DOWN 649 #define IMG_FLAMES_3_DOWN 650 #define IMG_STONEBLOCK 651 #define IMG_PLAYER_1 652 #define IMG_PLAYER_1_EDITOR 653 #define IMG_PLAYER_1_DOWN 654 #define IMG_PLAYER_1_UP 655 #define IMG_PLAYER_1_LEFT 656 #define IMG_PLAYER_1_RIGHT 657 #define IMG_PLAYER_1_MOVING_DOWN 658 #define IMG_PLAYER_1_MOVING_UP 659 #define IMG_PLAYER_1_MOVING_LEFT 660 #define IMG_PLAYER_1_MOVING_RIGHT 661 #define IMG_PLAYER_1_DIGGING_DOWN 662 #define IMG_PLAYER_1_DIGGING_UP 663 #define IMG_PLAYER_1_DIGGING_LEFT 664 #define IMG_PLAYER_1_DIGGING_RIGHT 665 #define IMG_PLAYER_1_COLLECTING_DOWN 666 #define IMG_PLAYER_1_COLLECTING_UP 667 #define IMG_PLAYER_1_COLLECTING_LEFT 668 #define IMG_PLAYER_1_COLLECTING_RIGHT 669 #define IMG_PLAYER_1_PUSHING_DOWN 670 #define IMG_PLAYER_1_PUSHING_UP 671 #define IMG_PLAYER_1_PUSHING_LEFT 672 #define IMG_PLAYER_1_PUSHING_RIGHT 673 #define IMG_PLAYER_1_SNAPPING_DOWN 674 #define IMG_PLAYER_1_SNAPPING_UP 675 #define IMG_PLAYER_1_SNAPPING_LEFT 676 #define IMG_PLAYER_1_SNAPPING_RIGHT 677 #define IMG_PLAYER_2 678 #define IMG_PLAYER_2_EDITOR 679 #define IMG_PLAYER_2_DOWN 680 #define IMG_PLAYER_2_UP 681 #define IMG_PLAYER_2_LEFT 682 #define IMG_PLAYER_2_RIGHT 683 #define IMG_PLAYER_2_MOVING_DOWN 684 #define IMG_PLAYER_2_MOVING_UP 685 #define IMG_PLAYER_2_MOVING_LEFT 686 #define IMG_PLAYER_2_MOVING_RIGHT 687 #define IMG_PLAYER_2_DIGGING_DOWN 688 #define IMG_PLAYER_2_DIGGING_UP 689 #define IMG_PLAYER_2_DIGGING_LEFT 690 #define IMG_PLAYER_2_DIGGING_RIGHT 691 #define IMG_PLAYER_2_COLLECTING_DOWN 692 #define IMG_PLAYER_2_COLLECTING_UP 693 #define IMG_PLAYER_2_COLLECTING_LEFT 694 #define IMG_PLAYER_2_COLLECTING_RIGHT 695 #define IMG_PLAYER_2_PUSHING_DOWN 696 #define IMG_PLAYER_2_PUSHING_UP 697 #define IMG_PLAYER_2_PUSHING_LEFT 698 #define IMG_PLAYER_2_PUSHING_RIGHT 699 #define IMG_PLAYER_2_SNAPPING_DOWN 700 #define IMG_PLAYER_2_SNAPPING_UP 701 #define IMG_PLAYER_2_SNAPPING_LEFT 702 #define IMG_PLAYER_2_SNAPPING_RIGHT 703 #define IMG_PLAYER_3 704 #define IMG_PLAYER_3_EDITOR 705 #define IMG_PLAYER_3_DOWN 706 #define IMG_PLAYER_3_UP 707 #define IMG_PLAYER_3_LEFT 708 #define IMG_PLAYER_3_RIGHT 709 #define IMG_PLAYER_3_MOVING_DOWN 710 #define IMG_PLAYER_3_MOVING_UP 711 #define IMG_PLAYER_3_MOVING_LEFT 712 #define IMG_PLAYER_3_MOVING_RIGHT 713 #define IMG_PLAYER_3_DIGGING_DOWN 714 #define IMG_PLAYER_3_DIGGING_UP 715 #define IMG_PLAYER_3_DIGGING_LEFT 716 #define IMG_PLAYER_3_DIGGING_RIGHT 717 #define IMG_PLAYER_3_COLLECTING_DOWN 718 #define IMG_PLAYER_3_COLLECTING_UP 719 #define IMG_PLAYER_3_COLLECTING_LEFT 720 #define IMG_PLAYER_3_COLLECTING_RIGHT 721 #define IMG_PLAYER_3_PUSHING_DOWN 722 #define IMG_PLAYER_3_PUSHING_UP 723 #define IMG_PLAYER_3_PUSHING_LEFT 724 #define IMG_PLAYER_3_PUSHING_RIGHT 725 #define IMG_PLAYER_3_SNAPPING_DOWN 726 #define IMG_PLAYER_3_SNAPPING_UP 727 #define IMG_PLAYER_3_SNAPPING_LEFT 728 #define IMG_PLAYER_3_SNAPPING_RIGHT 729 #define IMG_PLAYER_4 730 #define IMG_PLAYER_4_EDITOR 731 #define IMG_PLAYER_4_DOWN 732 #define IMG_PLAYER_4_UP 733 #define IMG_PLAYER_4_LEFT 734 #define IMG_PLAYER_4_RIGHT 735 #define IMG_PLAYER_4_MOVING_DOWN 736 #define IMG_PLAYER_4_MOVING_UP 737 #define IMG_PLAYER_4_MOVING_LEFT 738 #define IMG_PLAYER_4_MOVING_RIGHT 739 #define IMG_PLAYER_4_DIGGING_DOWN 740 #define IMG_PLAYER_4_DIGGING_UP 741 #define IMG_PLAYER_4_DIGGING_LEFT 742 #define IMG_PLAYER_4_DIGGING_RIGHT 743 #define IMG_PLAYER_4_COLLECTING_DOWN 744 #define IMG_PLAYER_4_COLLECTING_UP 745 #define IMG_PLAYER_4_COLLECTING_LEFT 746 #define IMG_PLAYER_4_COLLECTING_RIGHT 747 #define IMG_PLAYER_4_PUSHING_DOWN 748 #define IMG_PLAYER_4_PUSHING_UP 749 #define IMG_PLAYER_4_PUSHING_LEFT 750 #define IMG_PLAYER_4_PUSHING_RIGHT 751 #define IMG_PLAYER_4_SNAPPING_DOWN 752 #define IMG_PLAYER_4_SNAPPING_UP 753 #define IMG_PLAYER_4_SNAPPING_LEFT 754 #define IMG_PLAYER_4_SNAPPING_RIGHT 755 #define IMG_DEFAULT_EXPLODING 756 #define IMG_TWINKLE_BLUE 757 #define IMG_TWINKLE_WHITE 758 #define IMG_STEELWALL_TOPLEFT 759 #define IMG_STEELWALL_TOPRIGHT 760 #define IMG_STEELWALL_BOTTOMLEFT 761 #define IMG_STEELWALL_BOTTOMRIGHT 762 #define IMG_STEELWALL_HORIZONTAL 763 #define IMG_STEELWALL_VERTICAL 764 #define IMG_STEELWALL_TOPLEFT_EDITOR 765 #define IMG_STEELWALL_TOPRIGHT_EDITOR 766 #define IMG_STEELWALL_BOTTOMLEFT_EDITOR 767 #define IMG_STEELWALL_BOTTOMRIGHT_EDITOR 768 #define IMG_STEELWALL_HORIZONTAL_EDITOR 769 #define IMG_STEELWALL_VERTICAL_EDITOR 770 #define IMG_INVISIBLE_STEELWALL_TOPLEFT 771 #define IMG_INVISIBLE_STEELWALL_TOPRIGHT 772 #define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT 773 #define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT 774 #define IMG_INVISIBLE_STEELWALL_HORIZONTAL 775 #define IMG_INVISIBLE_STEELWALL_VERTICAL 776 #define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR 777 #define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR 778 #define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR 779 #define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR 780 #define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR 781 #define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR 782 #define IMG_ARROW_LEFT 783 #define IMG_ARROW_RIGHT 784 #define IMG_ARROW_UP 785 #define IMG_ARROW_DOWN 786 #define IMG_UNKNOWN 787 #define IMG_TRIGGER_ELEMENT 788 #define IMG_TRIGGER_PLAYER 789 #define IMG_TRIGGER_CE_VALUE 790 #define IMG_TRIGGER_CE_SCORE 791 #define IMG_CURRENT_CE_VALUE 792 #define IMG_CURRENT_CE_SCORE 793 #define IMG_PREV_CE_1 794 #define IMG_PREV_CE_2 795 #define IMG_PREV_CE_3 796 #define IMG_PREV_CE_4 797 #define IMG_PREV_CE_5 798 #define IMG_PREV_CE_6 799 #define IMG_PREV_CE_7 800 #define IMG_PREV_CE_8 801 #define IMG_NEXT_CE_1 802 #define IMG_NEXT_CE_2 803 #define IMG_NEXT_CE_3 804 #define IMG_NEXT_CE_4 805 #define IMG_NEXT_CE_5 806 #define IMG_NEXT_CE_6 807 #define IMG_NEXT_CE_7 808 #define IMG_NEXT_CE_8 809 #define IMG_SELF 810 #define IMG_ANY_ELEMENT 811 #define IMG_EMC_KEY_5 812 #define IMG_EMC_KEY_6 813 #define IMG_EMC_KEY_7 814 #define IMG_EMC_KEY_8 815 #define IMG_EMC_GATE_5 816 #define IMG_EMC_GATE_6 817 #define IMG_EMC_GATE_7 818 #define IMG_EMC_GATE_8 819 #define IMG_EMC_GATE_5_GRAY 820 #define IMG_EMC_GATE_5_GRAY_EDITOR 821 #define IMG_EMC_GATE_5_GRAY_ACTIVE 822 #define IMG_EMC_GATE_6_GRAY 823 #define IMG_EMC_GATE_6_GRAY_EDITOR 824 #define IMG_EMC_GATE_6_GRAY_ACTIVE 825 #define IMG_EMC_GATE_7_GRAY 826 #define IMG_EMC_GATE_7_GRAY_EDITOR 827 #define IMG_EMC_GATE_7_GRAY_ACTIVE 828 #define IMG_EMC_GATE_8_GRAY 829 #define IMG_EMC_GATE_8_GRAY_EDITOR 830 #define IMG_EMC_GATE_8_GRAY_ACTIVE 831 #define IMG_EMC_ANDROID 832 #define IMG_EMC_ANDROID_SHRINKING_UPLEFT 833 #define IMG_EMC_ANDROID_GROWING_DOWNRIGHT 834 #define IMG_EMC_ANDROID_SHRINKING_DOWNLEFT 835 #define IMG_EMC_ANDROID_GROWING_UPRIGHT 836 #define IMG_EMC_ANDROID_SHRINKING_UPRIGHT 837 #define IMG_EMC_ANDROID_GROWING_DOWNLEFT 838 #define IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT 839 #define IMG_EMC_ANDROID_GROWING_UPLEFT 840 #define IMG_EMC_GRASS 841 #define IMG_EMC_GRASS_CRUMBLED 842 #define IMG_EMC_GRASS_DIGGING_LEFT 843 #define IMG_EMC_GRASS_DIGGING_RIGHT 844 #define IMG_EMC_GRASS_DIGGING_UP 845 #define IMG_EMC_GRASS_DIGGING_DOWN 846 #define IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED 847 #define IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED 848 #define IMG_EMC_GRASS_DIGGING_UP_CRUMBLED 849 #define IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED 850 #define IMG_EMC_MAGIC_BALL 851 #define IMG_EMC_MAGIC_BALL_ACTIVE 852 #define IMG_EMC_MAGIC_BALL_DROPPING 853 #define IMG_EMC_MAGIC_BALL_SWITCH 854 #define IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE 855 #define IMG_EMC_SPRING_BUMPER 856 #define IMG_EMC_SPRING_BUMPER_ACTIVE 857 #define IMG_EMC_PLANT 858 #define IMG_EMC_PLANT_CRUMBLED 859 #define IMG_EMC_LENSES 860 #define IMG_EMC_MAGNIFIER 861 #define IMG_EMC_WALL_9 862 #define IMG_EMC_WALL_10 863 #define IMG_EMC_WALL_11 864 #define IMG_EMC_WALL_12 865 #define IMG_EMC_WALL_13 866 #define IMG_EMC_WALL_14 867 #define IMG_EMC_WALL_15 868 #define IMG_EMC_WALL_16 869 #define IMG_EMC_WALL_SLIPPERY_1 870 #define IMG_EMC_WALL_SLIPPERY_2 871 #define IMG_EMC_WALL_SLIPPERY_3 872 #define IMG_EMC_WALL_SLIPPERY_4 873 #define IMG_EMC_FAKE_GRASS 874 #define IMG_EMC_FAKE_GRASS_CRUMBLED 875 #define IMG_EMC_FAKE_GRASS_ACTIVE 876 #define IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED 877 #define IMG_EMC_FAKE_GRASS_EDITOR 878 #define IMG_EMC_FAKE_ACID 879 #define IMG_EMC_DRIPPER 880 #define IMG_EMC_DRIPPER_EDITOR 881 #define IMG_EMC_DRIPPER_ACTIVE 882 #define IMG_GRAPHIC_1 883 #define IMG_GRAPHIC_2 884 #define IMG_GRAPHIC_3 885 #define IMG_GRAPHIC_4 886 #define IMG_GRAPHIC_5 887 #define IMG_GRAPHIC_6 888 #define IMG_GRAPHIC_7 889 #define IMG_GRAPHIC_8 890 #define IMG_CHAR_SPACE 891 #define IMG_CHAR_SPACE_EDITOR 892 #define IMG_CHAR_EXCLAM 893 #define IMG_CHAR_QUOTEDBL 894 #define IMG_CHAR_NUMBERSIGN 895 #define IMG_CHAR_DOLLAR 896 #define IMG_CHAR_PERCENT 897 #define IMG_CHAR_AMPERSAND 898 #define IMG_CHAR_APOSTROPHE 899 #define IMG_CHAR_PARENLEFT 900 #define IMG_CHAR_PARENRIGHT 901 #define IMG_CHAR_ASTERISK 902 #define IMG_CHAR_PLUS 903 #define IMG_CHAR_COMMA 904 #define IMG_CHAR_MINUS 905 #define IMG_CHAR_PERIOD 906 #define IMG_CHAR_SLASH 907 #define IMG_CHAR_0 908 #define IMG_CHAR_1 909 #define IMG_CHAR_2 910 #define IMG_CHAR_3 911 #define IMG_CHAR_4 912 #define IMG_CHAR_5 913 #define IMG_CHAR_6 914 #define IMG_CHAR_7 915 #define IMG_CHAR_8 916 #define IMG_CHAR_9 917 #define IMG_CHAR_COLON 918 #define IMG_CHAR_SEMICOLON 919 #define IMG_CHAR_LESS 920 #define IMG_CHAR_EQUAL 921 #define IMG_CHAR_GREATER 922 #define IMG_CHAR_QUESTION 923 #define IMG_CHAR_AT 924 #define IMG_CHAR_A 925 #define IMG_CHAR_B 926 #define IMG_CHAR_C 927 #define IMG_CHAR_D 928 #define IMG_CHAR_E 929 #define IMG_CHAR_F 930 #define IMG_CHAR_G 931 #define IMG_CHAR_H 932 #define IMG_CHAR_I 933 #define IMG_CHAR_J 934 #define IMG_CHAR_K 935 #define IMG_CHAR_L 936 #define IMG_CHAR_M 937 #define IMG_CHAR_N 938 #define IMG_CHAR_O 939 #define IMG_CHAR_P 940 #define IMG_CHAR_Q 941 #define IMG_CHAR_R 942 #define IMG_CHAR_S 943 #define IMG_CHAR_T 944 #define IMG_CHAR_U 945 #define IMG_CHAR_V 946 #define IMG_CHAR_W 947 #define IMG_CHAR_X 948 #define IMG_CHAR_Y 949 #define IMG_CHAR_Z 950 #define IMG_CHAR_BRACKETLEFT 951 #define IMG_CHAR_BACKSLASH 952 #define IMG_CHAR_BRACKETRIGHT 953 #define IMG_CHAR_ASCIICIRCUM 954 #define IMG_CHAR_UNDERSCORE 955 #define IMG_CHAR_COPYRIGHT 956 #define IMG_CHAR_AUMLAUT 957 #define IMG_CHAR_OUMLAUT 958 #define IMG_CHAR_UUMLAUT 959 #define IMG_CHAR_DEGREE 960 #define IMG_CHAR_TRADEMARK 961 #define IMG_CHAR_CURSOR 962 #define IMG_CHAR_BUTTON 963 #define IMG_CHAR_UP 964 #define IMG_CHAR_DOWN 965 #define IMG_STEEL_CHAR_SPACE 966 #define IMG_STEEL_CHAR_SPACE_EDITOR 967 #define IMG_STEEL_CHAR_EXCLAM 968 #define IMG_STEEL_CHAR_QUOTEDBL 969 #define IMG_STEEL_CHAR_NUMBERSIGN 970 #define IMG_STEEL_CHAR_DOLLAR 971 #define IMG_STEEL_CHAR_PERCENT 972 #define IMG_STEEL_CHAR_AMPERSAND 973 #define IMG_STEEL_CHAR_APOSTROPHE 974 #define IMG_STEEL_CHAR_PARENLEFT 975 #define IMG_STEEL_CHAR_PARENRIGHT 976 #define IMG_STEEL_CHAR_ASTERISK 977 #define IMG_STEEL_CHAR_PLUS 978 #define IMG_STEEL_CHAR_COMMA 979 #define IMG_STEEL_CHAR_MINUS 980 #define IMG_STEEL_CHAR_PERIOD 981 #define IMG_STEEL_CHAR_SLASH 982 #define IMG_STEEL_CHAR_0 983 #define IMG_STEEL_CHAR_1 984 #define IMG_STEEL_CHAR_2 985 #define IMG_STEEL_CHAR_3 986 #define IMG_STEEL_CHAR_4 987 #define IMG_STEEL_CHAR_5 988 #define IMG_STEEL_CHAR_6 989 #define IMG_STEEL_CHAR_7 990 #define IMG_STEEL_CHAR_8 991 #define IMG_STEEL_CHAR_9 992 #define IMG_STEEL_CHAR_COLON 993 #define IMG_STEEL_CHAR_SEMICOLON 994 #define IMG_STEEL_CHAR_LESS 995 #define IMG_STEEL_CHAR_EQUAL 996 #define IMG_STEEL_CHAR_GREATER 997 #define IMG_STEEL_CHAR_QUESTION 998 #define IMG_STEEL_CHAR_AT 999 #define IMG_STEEL_CHAR_A 1000 #define IMG_STEEL_CHAR_B 1001 #define IMG_STEEL_CHAR_C 1002 #define IMG_STEEL_CHAR_D 1003 #define IMG_STEEL_CHAR_E 1004 #define IMG_STEEL_CHAR_F 1005 #define IMG_STEEL_CHAR_G 1006 #define IMG_STEEL_CHAR_H 1007 #define IMG_STEEL_CHAR_I 1008 #define IMG_STEEL_CHAR_J 1009 #define IMG_STEEL_CHAR_K 1010 #define IMG_STEEL_CHAR_L 1011 #define IMG_STEEL_CHAR_M 1012 #define IMG_STEEL_CHAR_N 1013 #define IMG_STEEL_CHAR_O 1014 #define IMG_STEEL_CHAR_P 1015 #define IMG_STEEL_CHAR_Q 1016 #define IMG_STEEL_CHAR_R 1017 #define IMG_STEEL_CHAR_S 1018 #define IMG_STEEL_CHAR_T 1019 #define IMG_STEEL_CHAR_U 1020 #define IMG_STEEL_CHAR_V 1021 #define IMG_STEEL_CHAR_W 1022 #define IMG_STEEL_CHAR_X 1023 #define IMG_STEEL_CHAR_Y 1024 #define IMG_STEEL_CHAR_Z 1025 #define IMG_STEEL_CHAR_BRACKETLEFT 1026 #define IMG_STEEL_CHAR_BACKSLASH 1027 #define IMG_STEEL_CHAR_BRACKETRIGHT 1028 #define IMG_STEEL_CHAR_ASCIICIRCUM 1029 #define IMG_STEEL_CHAR_UNDERSCORE 1030 #define IMG_STEEL_CHAR_COPYRIGHT 1031 #define IMG_STEEL_CHAR_AUMLAUT 1032 #define IMG_STEEL_CHAR_OUMLAUT 1033 #define IMG_STEEL_CHAR_UUMLAUT 1034 #define IMG_STEEL_CHAR_DEGREE 1035 #define IMG_STEEL_CHAR_TRADEMARK 1036 #define IMG_STEEL_CHAR_CURSOR 1037 #define IMG_STEEL_CHAR_BUTTON 1038 #define IMG_STEEL_CHAR_UP 1039 #define IMG_STEEL_CHAR_DOWN 1040 #define IMG_CUSTOM_1 1041 #define IMG_CUSTOM_1_EDITOR 1042 #define IMG_CUSTOM_2 1043 #define IMG_CUSTOM_2_EDITOR 1044 #define IMG_CUSTOM_3 1045 #define IMG_CUSTOM_3_EDITOR 1046 #define IMG_CUSTOM_4 1047 #define IMG_CUSTOM_4_EDITOR 1048 #define IMG_CUSTOM_5 1049 #define IMG_CUSTOM_5_EDITOR 1050 #define IMG_CUSTOM_6 1051 #define IMG_CUSTOM_6_EDITOR 1052 #define IMG_CUSTOM_7 1053 #define IMG_CUSTOM_7_EDITOR 1054 #define IMG_CUSTOM_8 1055 #define IMG_CUSTOM_8_EDITOR 1056 #define IMG_CUSTOM_9 1057 #define IMG_CUSTOM_9_EDITOR 1058 #define IMG_CUSTOM_10 1059 #define IMG_CUSTOM_10_EDITOR 1060 #define IMG_CUSTOM_11 1061 #define IMG_CUSTOM_11_EDITOR 1062 #define IMG_CUSTOM_12 1063 #define IMG_CUSTOM_12_EDITOR 1064 #define IMG_CUSTOM_13 1065 #define IMG_CUSTOM_13_EDITOR 1066 #define IMG_CUSTOM_14 1067 #define IMG_CUSTOM_14_EDITOR 1068 #define IMG_CUSTOM_15 1069 #define IMG_CUSTOM_15_EDITOR 1070 #define IMG_CUSTOM_16 1071 #define IMG_CUSTOM_16_EDITOR 1072 #define IMG_CUSTOM_17 1073 #define IMG_CUSTOM_17_EDITOR 1074 #define IMG_CUSTOM_18 1075 #define IMG_CUSTOM_18_EDITOR 1076 #define IMG_CUSTOM_19 1077 #define IMG_CUSTOM_19_EDITOR 1078 #define IMG_CUSTOM_20 1079 #define IMG_CUSTOM_20_EDITOR 1080 #define IMG_CUSTOM_21 1081 #define IMG_CUSTOM_21_EDITOR 1082 #define IMG_CUSTOM_22 1083 #define IMG_CUSTOM_22_EDITOR 1084 #define IMG_CUSTOM_23 1085 #define IMG_CUSTOM_23_EDITOR 1086 #define IMG_CUSTOM_24 1087 #define IMG_CUSTOM_24_EDITOR 1088 #define IMG_CUSTOM_25 1089 #define IMG_CUSTOM_25_EDITOR 1090 #define IMG_CUSTOM_26 1091 #define IMG_CUSTOM_26_EDITOR 1092 #define IMG_CUSTOM_27 1093 #define IMG_CUSTOM_27_EDITOR 1094 #define IMG_CUSTOM_28 1095 #define IMG_CUSTOM_28_EDITOR 1096 #define IMG_CUSTOM_29 1097 #define IMG_CUSTOM_29_EDITOR 1098 #define IMG_CUSTOM_30 1099 #define IMG_CUSTOM_30_EDITOR 1100 #define IMG_CUSTOM_31 1101 #define IMG_CUSTOM_31_EDITOR 1102 #define IMG_CUSTOM_32 1103 #define IMG_CUSTOM_32_EDITOR 1104 #define IMG_CUSTOM_33 1105 #define IMG_CUSTOM_33_EDITOR 1106 #define IMG_CUSTOM_34 1107 #define IMG_CUSTOM_34_EDITOR 1108 #define IMG_CUSTOM_35 1109 #define IMG_CUSTOM_35_EDITOR 1110 #define IMG_CUSTOM_36 1111 #define IMG_CUSTOM_36_EDITOR 1112 #define IMG_CUSTOM_37 1113 #define IMG_CUSTOM_37_EDITOR 1114 #define IMG_CUSTOM_38 1115 #define IMG_CUSTOM_38_EDITOR 1116 #define IMG_CUSTOM_39 1117 #define IMG_CUSTOM_39_EDITOR 1118 #define IMG_CUSTOM_40 1119 #define IMG_CUSTOM_40_EDITOR 1120 #define IMG_CUSTOM_41 1121 #define IMG_CUSTOM_41_EDITOR 1122 #define IMG_CUSTOM_42 1123 #define IMG_CUSTOM_42_EDITOR 1124 #define IMG_CUSTOM_43 1125 #define IMG_CUSTOM_43_EDITOR 1126 #define IMG_CUSTOM_44 1127 #define IMG_CUSTOM_44_EDITOR 1128 #define IMG_CUSTOM_45 1129 #define IMG_CUSTOM_45_EDITOR 1130 #define IMG_CUSTOM_46 1131 #define IMG_CUSTOM_46_EDITOR 1132 #define IMG_CUSTOM_47 1133 #define IMG_CUSTOM_47_EDITOR 1134 #define IMG_CUSTOM_48 1135 #define IMG_CUSTOM_48_EDITOR 1136 #define IMG_CUSTOM_49 1137 #define IMG_CUSTOM_49_EDITOR 1138 #define IMG_CUSTOM_50 1139 #define IMG_CUSTOM_50_EDITOR 1140 #define IMG_CUSTOM_51 1141 #define IMG_CUSTOM_51_EDITOR 1142 #define IMG_CUSTOM_52 1143 #define IMG_CUSTOM_52_EDITOR 1144 #define IMG_CUSTOM_53 1145 #define IMG_CUSTOM_53_EDITOR 1146 #define IMG_CUSTOM_54 1147 #define IMG_CUSTOM_54_EDITOR 1148 #define IMG_CUSTOM_55 1149 #define IMG_CUSTOM_55_EDITOR 1150 #define IMG_CUSTOM_56 1151 #define IMG_CUSTOM_56_EDITOR 1152 #define IMG_CUSTOM_57 1153 #define IMG_CUSTOM_57_EDITOR 1154 #define IMG_CUSTOM_58 1155 #define IMG_CUSTOM_58_EDITOR 1156 #define IMG_CUSTOM_59 1157 #define IMG_CUSTOM_59_EDITOR 1158 #define IMG_CUSTOM_60 1159 #define IMG_CUSTOM_60_EDITOR 1160 #define IMG_CUSTOM_61 1161 #define IMG_CUSTOM_61_EDITOR 1162 #define IMG_CUSTOM_62 1163 #define IMG_CUSTOM_62_EDITOR 1164 #define IMG_CUSTOM_63 1165 #define IMG_CUSTOM_63_EDITOR 1166 #define IMG_CUSTOM_64 1167 #define IMG_CUSTOM_64_EDITOR 1168 #define IMG_CUSTOM_65 1169 #define IMG_CUSTOM_65_EDITOR 1170 #define IMG_CUSTOM_66 1171 #define IMG_CUSTOM_66_EDITOR 1172 #define IMG_CUSTOM_67 1173 #define IMG_CUSTOM_67_EDITOR 1174 #define IMG_CUSTOM_68 1175 #define IMG_CUSTOM_68_EDITOR 1176 #define IMG_CUSTOM_69 1177 #define IMG_CUSTOM_69_EDITOR 1178 #define IMG_CUSTOM_70 1179 #define IMG_CUSTOM_70_EDITOR 1180 #define IMG_CUSTOM_71 1181 #define IMG_CUSTOM_71_EDITOR 1182 #define IMG_CUSTOM_72 1183 #define IMG_CUSTOM_72_EDITOR 1184 #define IMG_CUSTOM_73 1185 #define IMG_CUSTOM_73_EDITOR 1186 #define IMG_CUSTOM_74 1187 #define IMG_CUSTOM_74_EDITOR 1188 #define IMG_CUSTOM_75 1189 #define IMG_CUSTOM_75_EDITOR 1190 #define IMG_CUSTOM_76 1191 #define IMG_CUSTOM_76_EDITOR 1192 #define IMG_CUSTOM_77 1193 #define IMG_CUSTOM_77_EDITOR 1194 #define IMG_CUSTOM_78 1195 #define IMG_CUSTOM_78_EDITOR 1196 #define IMG_CUSTOM_79 1197 #define IMG_CUSTOM_79_EDITOR 1198 #define IMG_CUSTOM_80 1199 #define IMG_CUSTOM_80_EDITOR 1200 #define IMG_CUSTOM_81 1201 #define IMG_CUSTOM_81_EDITOR 1202 #define IMG_CUSTOM_82 1203 #define IMG_CUSTOM_82_EDITOR 1204 #define IMG_CUSTOM_83 1205 #define IMG_CUSTOM_83_EDITOR 1206 #define IMG_CUSTOM_84 1207 #define IMG_CUSTOM_84_EDITOR 1208 #define IMG_CUSTOM_85 1209 #define IMG_CUSTOM_85_EDITOR 1210 #define IMG_CUSTOM_86 1211 #define IMG_CUSTOM_86_EDITOR 1212 #define IMG_CUSTOM_87 1213 #define IMG_CUSTOM_87_EDITOR 1214 #define IMG_CUSTOM_88 1215 #define IMG_CUSTOM_88_EDITOR 1216 #define IMG_CUSTOM_89 1217 #define IMG_CUSTOM_89_EDITOR 1218 #define IMG_CUSTOM_90 1219 #define IMG_CUSTOM_90_EDITOR 1220 #define IMG_CUSTOM_91 1221 #define IMG_CUSTOM_91_EDITOR 1222 #define IMG_CUSTOM_92 1223 #define IMG_CUSTOM_92_EDITOR 1224 #define IMG_CUSTOM_93 1225 #define IMG_CUSTOM_93_EDITOR 1226 #define IMG_CUSTOM_94 1227 #define IMG_CUSTOM_94_EDITOR 1228 #define IMG_CUSTOM_95 1229 #define IMG_CUSTOM_95_EDITOR 1230 #define IMG_CUSTOM_96 1231 #define IMG_CUSTOM_96_EDITOR 1232 #define IMG_CUSTOM_97 1233 #define IMG_CUSTOM_97_EDITOR 1234 #define IMG_CUSTOM_98 1235 #define IMG_CUSTOM_98_EDITOR 1236 #define IMG_CUSTOM_99 1237 #define IMG_CUSTOM_99_EDITOR 1238 #define IMG_CUSTOM_100 1239 #define IMG_CUSTOM_100_EDITOR 1240 #define IMG_CUSTOM_101 1241 #define IMG_CUSTOM_101_EDITOR 1242 #define IMG_CUSTOM_102 1243 #define IMG_CUSTOM_102_EDITOR 1244 #define IMG_CUSTOM_103 1245 #define IMG_CUSTOM_103_EDITOR 1246 #define IMG_CUSTOM_104 1247 #define IMG_CUSTOM_104_EDITOR 1248 #define IMG_CUSTOM_105 1249 #define IMG_CUSTOM_105_EDITOR 1250 #define IMG_CUSTOM_106 1251 #define IMG_CUSTOM_106_EDITOR 1252 #define IMG_CUSTOM_107 1253 #define IMG_CUSTOM_107_EDITOR 1254 #define IMG_CUSTOM_108 1255 #define IMG_CUSTOM_108_EDITOR 1256 #define IMG_CUSTOM_109 1257 #define IMG_CUSTOM_109_EDITOR 1258 #define IMG_CUSTOM_110 1259 #define IMG_CUSTOM_110_EDITOR 1260 #define IMG_CUSTOM_111 1261 #define IMG_CUSTOM_111_EDITOR 1262 #define IMG_CUSTOM_112 1263 #define IMG_CUSTOM_112_EDITOR 1264 #define IMG_CUSTOM_113 1265 #define IMG_CUSTOM_113_EDITOR 1266 #define IMG_CUSTOM_114 1267 #define IMG_CUSTOM_114_EDITOR 1268 #define IMG_CUSTOM_115 1269 #define IMG_CUSTOM_115_EDITOR 1270 #define IMG_CUSTOM_116 1271 #define IMG_CUSTOM_116_EDITOR 1272 #define IMG_CUSTOM_117 1273 #define IMG_CUSTOM_117_EDITOR 1274 #define IMG_CUSTOM_118 1275 #define IMG_CUSTOM_118_EDITOR 1276 #define IMG_CUSTOM_119 1277 #define IMG_CUSTOM_119_EDITOR 1278 #define IMG_CUSTOM_120 1279 #define IMG_CUSTOM_120_EDITOR 1280 #define IMG_CUSTOM_121 1281 #define IMG_CUSTOM_121_EDITOR 1282 #define IMG_CUSTOM_122 1283 #define IMG_CUSTOM_122_EDITOR 1284 #define IMG_CUSTOM_123 1285 #define IMG_CUSTOM_123_EDITOR 1286 #define IMG_CUSTOM_124 1287 #define IMG_CUSTOM_124_EDITOR 1288 #define IMG_CUSTOM_125 1289 #define IMG_CUSTOM_125_EDITOR 1290 #define IMG_CUSTOM_126 1291 #define IMG_CUSTOM_126_EDITOR 1292 #define IMG_CUSTOM_127 1293 #define IMG_CUSTOM_127_EDITOR 1294 #define IMG_CUSTOM_128 1295 #define IMG_CUSTOM_128_EDITOR 1296 #define IMG_CUSTOM_129 1297 #define IMG_CUSTOM_129_EDITOR 1298 #define IMG_CUSTOM_130 1299 #define IMG_CUSTOM_130_EDITOR 1300 #define IMG_CUSTOM_131 1301 #define IMG_CUSTOM_131_EDITOR 1302 #define IMG_CUSTOM_132 1303 #define IMG_CUSTOM_132_EDITOR 1304 #define IMG_CUSTOM_133 1305 #define IMG_CUSTOM_133_EDITOR 1306 #define IMG_CUSTOM_134 1307 #define IMG_CUSTOM_134_EDITOR 1308 #define IMG_CUSTOM_135 1309 #define IMG_CUSTOM_135_EDITOR 1310 #define IMG_CUSTOM_136 1311 #define IMG_CUSTOM_136_EDITOR 1312 #define IMG_CUSTOM_137 1313 #define IMG_CUSTOM_137_EDITOR 1314 #define IMG_CUSTOM_138 1315 #define IMG_CUSTOM_138_EDITOR 1316 #define IMG_CUSTOM_139 1317 #define IMG_CUSTOM_139_EDITOR 1318 #define IMG_CUSTOM_140 1319 #define IMG_CUSTOM_140_EDITOR 1320 #define IMG_CUSTOM_141 1321 #define IMG_CUSTOM_141_EDITOR 1322 #define IMG_CUSTOM_142 1323 #define IMG_CUSTOM_142_EDITOR 1324 #define IMG_CUSTOM_143 1325 #define IMG_CUSTOM_143_EDITOR 1326 #define IMG_CUSTOM_144 1327 #define IMG_CUSTOM_144_EDITOR 1328 #define IMG_CUSTOM_145 1329 #define IMG_CUSTOM_145_EDITOR 1330 #define IMG_CUSTOM_146 1331 #define IMG_CUSTOM_146_EDITOR 1332 #define IMG_CUSTOM_147 1333 #define IMG_CUSTOM_147_EDITOR 1334 #define IMG_CUSTOM_148 1335 #define IMG_CUSTOM_148_EDITOR 1336 #define IMG_CUSTOM_149 1337 #define IMG_CUSTOM_149_EDITOR 1338 #define IMG_CUSTOM_150 1339 #define IMG_CUSTOM_150_EDITOR 1340 #define IMG_CUSTOM_151 1341 #define IMG_CUSTOM_151_EDITOR 1342 #define IMG_CUSTOM_152 1343 #define IMG_CUSTOM_152_EDITOR 1344 #define IMG_CUSTOM_153 1345 #define IMG_CUSTOM_153_EDITOR 1346 #define IMG_CUSTOM_154 1347 #define IMG_CUSTOM_154_EDITOR 1348 #define IMG_CUSTOM_155 1349 #define IMG_CUSTOM_155_EDITOR 1350 #define IMG_CUSTOM_156 1351 #define IMG_CUSTOM_156_EDITOR 1352 #define IMG_CUSTOM_157 1353 #define IMG_CUSTOM_157_EDITOR 1354 #define IMG_CUSTOM_158 1355 #define IMG_CUSTOM_158_EDITOR 1356 #define IMG_CUSTOM_159 1357 #define IMG_CUSTOM_159_EDITOR 1358 #define IMG_CUSTOM_160 1359 #define IMG_CUSTOM_160_EDITOR 1360 #define IMG_CUSTOM_161 1361 #define IMG_CUSTOM_161_EDITOR 1362 #define IMG_CUSTOM_162 1363 #define IMG_CUSTOM_162_EDITOR 1364 #define IMG_CUSTOM_163 1365 #define IMG_CUSTOM_163_EDITOR 1366 #define IMG_CUSTOM_164 1367 #define IMG_CUSTOM_164_EDITOR 1368 #define IMG_CUSTOM_165 1369 #define IMG_CUSTOM_165_EDITOR 1370 #define IMG_CUSTOM_166 1371 #define IMG_CUSTOM_166_EDITOR 1372 #define IMG_CUSTOM_167 1373 #define IMG_CUSTOM_167_EDITOR 1374 #define IMG_CUSTOM_168 1375 #define IMG_CUSTOM_168_EDITOR 1376 #define IMG_CUSTOM_169 1377 #define IMG_CUSTOM_169_EDITOR 1378 #define IMG_CUSTOM_170 1379 #define IMG_CUSTOM_170_EDITOR 1380 #define IMG_CUSTOM_171 1381 #define IMG_CUSTOM_171_EDITOR 1382 #define IMG_CUSTOM_172 1383 #define IMG_CUSTOM_172_EDITOR 1384 #define IMG_CUSTOM_173 1385 #define IMG_CUSTOM_173_EDITOR 1386 #define IMG_CUSTOM_174 1387 #define IMG_CUSTOM_174_EDITOR 1388 #define IMG_CUSTOM_175 1389 #define IMG_CUSTOM_175_EDITOR 1390 #define IMG_CUSTOM_176 1391 #define IMG_CUSTOM_176_EDITOR 1392 #define IMG_CUSTOM_177 1393 #define IMG_CUSTOM_177_EDITOR 1394 #define IMG_CUSTOM_178 1395 #define IMG_CUSTOM_178_EDITOR 1396 #define IMG_CUSTOM_179 1397 #define IMG_CUSTOM_179_EDITOR 1398 #define IMG_CUSTOM_180 1399 #define IMG_CUSTOM_180_EDITOR 1400 #define IMG_CUSTOM_181 1401 #define IMG_CUSTOM_181_EDITOR 1402 #define IMG_CUSTOM_182 1403 #define IMG_CUSTOM_182_EDITOR 1404 #define IMG_CUSTOM_183 1405 #define IMG_CUSTOM_183_EDITOR 1406 #define IMG_CUSTOM_184 1407 #define IMG_CUSTOM_184_EDITOR 1408 #define IMG_CUSTOM_185 1409 #define IMG_CUSTOM_185_EDITOR 1410 #define IMG_CUSTOM_186 1411 #define IMG_CUSTOM_186_EDITOR 1412 #define IMG_CUSTOM_187 1413 #define IMG_CUSTOM_187_EDITOR 1414 #define IMG_CUSTOM_188 1415 #define IMG_CUSTOM_188_EDITOR 1416 #define IMG_CUSTOM_189 1417 #define IMG_CUSTOM_189_EDITOR 1418 #define IMG_CUSTOM_190 1419 #define IMG_CUSTOM_190_EDITOR 1420 #define IMG_CUSTOM_191 1421 #define IMG_CUSTOM_191_EDITOR 1422 #define IMG_CUSTOM_192 1423 #define IMG_CUSTOM_192_EDITOR 1424 #define IMG_CUSTOM_193 1425 #define IMG_CUSTOM_193_EDITOR 1426 #define IMG_CUSTOM_194 1427 #define IMG_CUSTOM_194_EDITOR 1428 #define IMG_CUSTOM_195 1429 #define IMG_CUSTOM_195_EDITOR 1430 #define IMG_CUSTOM_196 1431 #define IMG_CUSTOM_196_EDITOR 1432 #define IMG_CUSTOM_197 1433 #define IMG_CUSTOM_197_EDITOR 1434 #define IMG_CUSTOM_198 1435 #define IMG_CUSTOM_198_EDITOR 1436 #define IMG_CUSTOM_199 1437 #define IMG_CUSTOM_199_EDITOR 1438 #define IMG_CUSTOM_200 1439 #define IMG_CUSTOM_200_EDITOR 1440 #define IMG_CUSTOM_201 1441 #define IMG_CUSTOM_201_EDITOR 1442 #define IMG_CUSTOM_202 1443 #define IMG_CUSTOM_202_EDITOR 1444 #define IMG_CUSTOM_203 1445 #define IMG_CUSTOM_203_EDITOR 1446 #define IMG_CUSTOM_204 1447 #define IMG_CUSTOM_204_EDITOR 1448 #define IMG_CUSTOM_205 1449 #define IMG_CUSTOM_205_EDITOR 1450 #define IMG_CUSTOM_206 1451 #define IMG_CUSTOM_206_EDITOR 1452 #define IMG_CUSTOM_207 1453 #define IMG_CUSTOM_207_EDITOR 1454 #define IMG_CUSTOM_208 1455 #define IMG_CUSTOM_208_EDITOR 1456 #define IMG_CUSTOM_209 1457 #define IMG_CUSTOM_209_EDITOR 1458 #define IMG_CUSTOM_210 1459 #define IMG_CUSTOM_210_EDITOR 1460 #define IMG_CUSTOM_211 1461 #define IMG_CUSTOM_211_EDITOR 1462 #define IMG_CUSTOM_212 1463 #define IMG_CUSTOM_212_EDITOR 1464 #define IMG_CUSTOM_213 1465 #define IMG_CUSTOM_213_EDITOR 1466 #define IMG_CUSTOM_214 1467 #define IMG_CUSTOM_214_EDITOR 1468 #define IMG_CUSTOM_215 1469 #define IMG_CUSTOM_215_EDITOR 1470 #define IMG_CUSTOM_216 1471 #define IMG_CUSTOM_216_EDITOR 1472 #define IMG_CUSTOM_217 1473 #define IMG_CUSTOM_217_EDITOR 1474 #define IMG_CUSTOM_218 1475 #define IMG_CUSTOM_218_EDITOR 1476 #define IMG_CUSTOM_219 1477 #define IMG_CUSTOM_219_EDITOR 1478 #define IMG_CUSTOM_220 1479 #define IMG_CUSTOM_220_EDITOR 1480 #define IMG_CUSTOM_221 1481 #define IMG_CUSTOM_221_EDITOR 1482 #define IMG_CUSTOM_222 1483 #define IMG_CUSTOM_222_EDITOR 1484 #define IMG_CUSTOM_223 1485 #define IMG_CUSTOM_223_EDITOR 1486 #define IMG_CUSTOM_224 1487 #define IMG_CUSTOM_224_EDITOR 1488 #define IMG_CUSTOM_225 1489 #define IMG_CUSTOM_225_EDITOR 1490 #define IMG_CUSTOM_226 1491 #define IMG_CUSTOM_226_EDITOR 1492 #define IMG_CUSTOM_227 1493 #define IMG_CUSTOM_227_EDITOR 1494 #define IMG_CUSTOM_228 1495 #define IMG_CUSTOM_228_EDITOR 1496 #define IMG_CUSTOM_229 1497 #define IMG_CUSTOM_229_EDITOR 1498 #define IMG_CUSTOM_230 1499 #define IMG_CUSTOM_230_EDITOR 1500 #define IMG_CUSTOM_231 1501 #define IMG_CUSTOM_231_EDITOR 1502 #define IMG_CUSTOM_232 1503 #define IMG_CUSTOM_232_EDITOR 1504 #define IMG_CUSTOM_233 1505 #define IMG_CUSTOM_233_EDITOR 1506 #define IMG_CUSTOM_234 1507 #define IMG_CUSTOM_234_EDITOR 1508 #define IMG_CUSTOM_235 1509 #define IMG_CUSTOM_235_EDITOR 1510 #define IMG_CUSTOM_236 1511 #define IMG_CUSTOM_236_EDITOR 1512 #define IMG_CUSTOM_237 1513 #define IMG_CUSTOM_237_EDITOR 1514 #define IMG_CUSTOM_238 1515 #define IMG_CUSTOM_238_EDITOR 1516 #define IMG_CUSTOM_239 1517 #define IMG_CUSTOM_239_EDITOR 1518 #define IMG_CUSTOM_240 1519 #define IMG_CUSTOM_240_EDITOR 1520 #define IMG_CUSTOM_241 1521 #define IMG_CUSTOM_241_EDITOR 1522 #define IMG_CUSTOM_242 1523 #define IMG_CUSTOM_242_EDITOR 1524 #define IMG_CUSTOM_243 1525 #define IMG_CUSTOM_243_EDITOR 1526 #define IMG_CUSTOM_244 1527 #define IMG_CUSTOM_244_EDITOR 1528 #define IMG_CUSTOM_245 1529 #define IMG_CUSTOM_245_EDITOR 1530 #define IMG_CUSTOM_246 1531 #define IMG_CUSTOM_246_EDITOR 1532 #define IMG_CUSTOM_247 1533 #define IMG_CUSTOM_247_EDITOR 1534 #define IMG_CUSTOM_248 1535 #define IMG_CUSTOM_248_EDITOR 1536 #define IMG_CUSTOM_249 1537 #define IMG_CUSTOM_249_EDITOR 1538 #define IMG_CUSTOM_250 1539 #define IMG_CUSTOM_250_EDITOR 1540 #define IMG_CUSTOM_251 1541 #define IMG_CUSTOM_251_EDITOR 1542 #define IMG_CUSTOM_252 1543 #define IMG_CUSTOM_252_EDITOR 1544 #define IMG_CUSTOM_253 1545 #define IMG_CUSTOM_253_EDITOR 1546 #define IMG_CUSTOM_254 1547 #define IMG_CUSTOM_254_EDITOR 1548 #define IMG_CUSTOM_255 1549 #define IMG_CUSTOM_255_EDITOR 1550 #define IMG_CUSTOM_256 1551 #define IMG_CUSTOM_256_EDITOR 1552 #define IMG_GROUP_1 1553 #define IMG_GROUP_1_EDITOR 1554 #define IMG_GROUP_2 1555 #define IMG_GROUP_2_EDITOR 1556 #define IMG_GROUP_3 1557 #define IMG_GROUP_3_EDITOR 1558 #define IMG_GROUP_4 1559 #define IMG_GROUP_4_EDITOR 1560 #define IMG_GROUP_5 1561 #define IMG_GROUP_5_EDITOR 1562 #define IMG_GROUP_6 1563 #define IMG_GROUP_6_EDITOR 1564 #define IMG_GROUP_7 1565 #define IMG_GROUP_7_EDITOR 1566 #define IMG_GROUP_8 1567 #define IMG_GROUP_8_EDITOR 1568 #define IMG_GROUP_9 1569 #define IMG_GROUP_9_EDITOR 1570 #define IMG_GROUP_10 1571 #define IMG_GROUP_10_EDITOR 1572 #define IMG_GROUP_11 1573 #define IMG_GROUP_11_EDITOR 1574 #define IMG_GROUP_12 1575 #define IMG_GROUP_12_EDITOR 1576 #define IMG_GROUP_13 1577 #define IMG_GROUP_13_EDITOR 1578 #define IMG_GROUP_14 1579 #define IMG_GROUP_14_EDITOR 1580 #define IMG_GROUP_15 1581 #define IMG_GROUP_15_EDITOR 1582 #define IMG_GROUP_16 1583 #define IMG_GROUP_16_EDITOR 1584 #define IMG_GROUP_17 1585 #define IMG_GROUP_17_EDITOR 1586 #define IMG_GROUP_18 1587 #define IMG_GROUP_18_EDITOR 1588 #define IMG_GROUP_19 1589 #define IMG_GROUP_19_EDITOR 1590 #define IMG_GROUP_20 1591 #define IMG_GROUP_20_EDITOR 1592 #define IMG_GROUP_21 1593 #define IMG_GROUP_21_EDITOR 1594 #define IMG_GROUP_22 1595 #define IMG_GROUP_22_EDITOR 1596 #define IMG_GROUP_23 1597 #define IMG_GROUP_23_EDITOR 1598 #define IMG_GROUP_24 1599 #define IMG_GROUP_24_EDITOR 1600 #define IMG_GROUP_25 1601 #define IMG_GROUP_25_EDITOR 1602 #define IMG_GROUP_26 1603 #define IMG_GROUP_26_EDITOR 1604 #define IMG_GROUP_27 1605 #define IMG_GROUP_27_EDITOR 1606 #define IMG_GROUP_28 1607 #define IMG_GROUP_28_EDITOR 1608 #define IMG_GROUP_29 1609 #define IMG_GROUP_29_EDITOR 1610 #define IMG_GROUP_30 1611 #define IMG_GROUP_30_EDITOR 1612 #define IMG_GROUP_31 1613 #define IMG_GROUP_31_EDITOR 1614 #define IMG_GROUP_32 1615 #define IMG_GROUP_32_EDITOR 1616 #define IMG_EMC_OBJECT 1617 #define IMG_EMC_SPRITE 1618 #define IMG_SP_FRAME_HORIZONTAL 1619 #define IMG_SP_FRAME_VERTICAL 1620 #define IMG_SP_FRAME_CORNER 1621 #define IMG_TOON_1 1622 #define IMG_TOON_2 1623 #define IMG_TOON_3 1624 #define IMG_TOON_4 1625 #define IMG_TOON_5 1626 #define IMG_TOON_6 1627 #define IMG_TOON_7 1628 #define IMG_TOON_8 1629 #define IMG_TOON_9 1630 #define IMG_TOON_10 1631 #define IMG_TOON_11 1632 #define IMG_TOON_12 1633 #define IMG_TOON_13 1634 #define IMG_TOON_14 1635 #define IMG_TOON_15 1636 #define IMG_TOON_16 1637 #define IMG_TOON_17 1638 #define IMG_TOON_18 1639 #define IMG_TOON_19 1640 #define IMG_TOON_20 1641 #define IMG_MENU_CALIBRATE_RED 1642 #define IMG_MENU_CALIBRATE_BLUE 1643 #define IMG_MENU_CALIBRATE_YELLOW 1644 #define IMG_MENU_BUTTON 1645 #define IMG_MENU_BUTTON_ACTIVE 1646 #define IMG_MENU_BUTTON_LEFT 1647 #define IMG_MENU_BUTTON_LEFT_ACTIVE 1648 #define IMG_MENU_BUTTON_RIGHT 1649 #define IMG_MENU_BUTTON_RIGHT_ACTIVE 1650 #define IMG_MENU_BUTTON_UP 1651 #define IMG_MENU_BUTTON_UP_ACTIVE 1652 #define IMG_MENU_BUTTON_DOWN 1653 #define IMG_MENU_BUTTON_DOWN_ACTIVE 1654 #define IMG_MENU_BUTTON_ENTER_MENU 1655 #define IMG_MENU_BUTTON_ENTER_MENU_ACTIVE 1656 #define IMG_MENU_BUTTON_LEAVE_MENU 1657 #define IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE 1658 #define IMG_MENU_BUTTON_NEXT_LEVEL 1659 #define IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE 1660 #define IMG_MENU_BUTTON_PREV_LEVEL 1661 #define IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE 1662 #define IMG_MENU_BUTTON_NAME 1663 #define IMG_MENU_BUTTON_NAME_ACTIVE 1664 #define IMG_MENU_BUTTON_LEVELS 1665 #define IMG_MENU_BUTTON_LEVELS_ACTIVE 1666 #define IMG_MENU_BUTTON_SCORES 1667 #define IMG_MENU_BUTTON_SCORES_ACTIVE 1668 #define IMG_MENU_BUTTON_EDITOR 1669 #define IMG_MENU_BUTTON_EDITOR_ACTIVE 1670 #define IMG_MENU_BUTTON_INFO 1671 #define IMG_MENU_BUTTON_INFO_ACTIVE 1672 #define IMG_MENU_BUTTON_GAME 1673 #define IMG_MENU_BUTTON_GAME_ACTIVE 1674 #define IMG_MENU_BUTTON_SETUP 1675 #define IMG_MENU_BUTTON_SETUP_ACTIVE 1676 #define IMG_MENU_BUTTON_QUIT 1677 #define IMG_MENU_BUTTON_QUIT_ACTIVE 1678 #define IMG_MENU_SCROLLBAR 1679 #define IMG_MENU_SCROLLBAR_ACTIVE 1680 #define IMG_FONT_INITIAL_1 1681 #define IMG_FONT_INITIAL_2 1682 #define IMG_FONT_INITIAL_3 1683 #define IMG_FONT_INITIAL_4 1684 #define IMG_FONT_TITLE_1 1685 #define IMG_FONT_TITLE_2 1686 #define IMG_FONT_TITLE_2_SETUP 1687 #define IMG_FONT_MENU_1 1688 #define IMG_FONT_MENU_1_ACTIVE 1689 #define IMG_FONT_MENU_2 1690 #define IMG_FONT_MENU_2_ACTIVE 1691 #define IMG_FONT_TEXT_1 1692 #define IMG_FONT_TEXT_1_MAIN 1693 #define IMG_FONT_TEXT_1_LEVELS 1694 #define IMG_FONT_TEXT_1_SETUP 1695 #define IMG_FONT_TEXT_1_PREVIEW 1696 #define IMG_FONT_TEXT_1_SCORES 1697 #define IMG_FONT_TEXT_1_ACTIVE_SCORES 1698 #define IMG_FONT_TEXT_1_PANEL 1699 #define IMG_FONT_TEXT_1_DOOR 1700 #define IMG_FONT_TEXT_2 1701 #define IMG_FONT_TEXT_2_MAIN 1702 #define IMG_FONT_TEXT_2_LEVELS 1703 #define IMG_FONT_TEXT_2_SETUP 1704 #define IMG_FONT_TEXT_2_PREVIEW 1705 #define IMG_FONT_TEXT_2_SCORES 1706 #define IMG_FONT_TEXT_2_ACTIVE_SCORES 1707 #define IMG_FONT_TEXT_3 1708 #define IMG_FONT_TEXT_3_LEVELS 1709 #define IMG_FONT_TEXT_3_SETUP 1710 #define IMG_FONT_TEXT_3_PREVIEW 1711 #define IMG_FONT_TEXT_3_SCORES 1712 #define IMG_FONT_TEXT_3_ACTIVE_SCORES 1713 #define IMG_FONT_TEXT_4 1714 #define IMG_FONT_TEXT_4_MAIN 1715 #define IMG_FONT_TEXT_4_LEVELS 1716 #define IMG_FONT_TEXT_4_SETUP 1717 #define IMG_FONT_TEXT_4_SCORES 1718 #define IMG_FONT_TEXT_4_ACTIVE_SCORES 1719 #define IMG_FONT_ENVELOPE_1 1720 #define IMG_FONT_ENVELOPE_2 1721 #define IMG_FONT_ENVELOPE_3 1722 #define IMG_FONT_ENVELOPE_4 1723 #define IMG_FONT_INPUT_1 1724 #define IMG_FONT_INPUT_1_MAIN 1725 #define IMG_FONT_INPUT_1_ACTIVE 1726 #define IMG_FONT_INPUT_1_ACTIVE_MAIN 1727 #define IMG_FONT_INPUT_1_ACTIVE_SETUP 1728 #define IMG_FONT_INPUT_2 1729 #define IMG_FONT_INPUT_2_ACTIVE 1730 #define IMG_FONT_OPTION_OFF 1731 #define IMG_FONT_OPTION_ON 1732 #define IMG_FONT_VALUE_1 1733 #define IMG_FONT_VALUE_2 1734 #define IMG_FONT_VALUE_OLD 1735 #define IMG_FONT_LEVEL_NUMBER 1736 #define IMG_FONT_LEVEL_NUMBER_ACTIVE 1737 #define IMG_FONT_TAPE_RECORDER 1738 #define IMG_FONT_GAME_INFO 1739 #define IMG_FONT_INFO_ELEMENTS 1740 #define IMG_FONT_INFO_LEVELSET 1741 #define IMG_GLOBAL_BORDER 1742 #define IMG_GLOBAL_DOOR 1743 #define IMG_GLOBAL_BUSY 1744 #define IMG_EDITOR_ELEMENT_BORDER 1745 #define IMG_EDITOR_ELEMENT_BORDER_INPUT 1746 #define IMG_EDITOR_CASCADE_LIST 1747 #define IMG_EDITOR_CASCADE_LIST_ACTIVE 1748 #define IMG_BACKGROUND 1749 #define IMG_BACKGROUND_TITLE_INITIAL 1750 #define IMG_BACKGROUND_TITLE 1751 #define IMG_BACKGROUND_MAIN 1752 #define IMG_BACKGROUND_LEVELS 1753 #define IMG_BACKGROUND_SCORES 1754 #define IMG_BACKGROUND_EDITOR 1755 #define IMG_BACKGROUND_INFO 1756 #define IMG_BACKGROUND_INFO_ELEMENTS 1757 #define IMG_BACKGROUND_INFO_MUSIC 1758 #define IMG_BACKGROUND_INFO_CREDITS 1759 #define IMG_BACKGROUND_INFO_PROGRAM 1760 #define IMG_BACKGROUND_INFO_VERSION 1761 #define IMG_BACKGROUND_INFO_LEVELSET 1762 #define IMG_BACKGROUND_SETUP 1763 #define IMG_BACKGROUND_PLAYING 1764 #define IMG_BACKGROUND_DOOR 1765 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_1 1766 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_2 1767 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_3 1768 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_4 1769 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_5 1770 #define IMG_BACKGROUND_TITLESCREEN_1 1771 #define IMG_BACKGROUND_TITLESCREEN_2 1772 #define IMG_BACKGROUND_TITLESCREEN_3 1773 #define IMG_BACKGROUND_TITLESCREEN_4 1774 #define IMG_BACKGROUND_TITLESCREEN_5 1775 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 1776 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2 1777 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3 1778 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4 1779 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5 1780 #define IMG_BACKGROUND_TITLEMESSAGE_1 1781 #define IMG_BACKGROUND_TITLEMESSAGE_2 1782 #define IMG_BACKGROUND_TITLEMESSAGE_3 1783 #define IMG_BACKGROUND_TITLEMESSAGE_4 1784 #define IMG_BACKGROUND_TITLEMESSAGE_5 1785 #define IMG_BACKGROUND_ENVELOPE_1 1786 #define IMG_BACKGROUND_ENVELOPE_2 1787 #define IMG_BACKGROUND_ENVELOPE_3 1788 #define IMG_BACKGROUND_ENVELOPE_4 1789 #define IMG_TITLESCREEN_INITIAL_1 1790 #define IMG_TITLESCREEN_INITIAL_2 1791 #define IMG_TITLESCREEN_INITIAL_3 1792 #define IMG_TITLESCREEN_INITIAL_4 1793 #define IMG_TITLESCREEN_INITIAL_5 1794 #define IMG_TITLESCREEN_1 1795 #define IMG_TITLESCREEN_2 1796 #define IMG_TITLESCREEN_3 1797 #define IMG_TITLESCREEN_4 1798 #define IMG_TITLESCREEN_5 1799 #define NUM_IMAGE_FILES 1800 #endif /* CONF_GFX_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_grp.h0000644000175000017500000000442411375255512017375 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_grp.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GRP_H #define CONF_GRP_H /* values for elements configuration (group elements) */ #define EL_GROUP_1 (EL_GROUP_START + 0) #define EL_GROUP_2 (EL_GROUP_START + 1) #define EL_GROUP_3 (EL_GROUP_START + 2) #define EL_GROUP_4 (EL_GROUP_START + 3) #define EL_GROUP_5 (EL_GROUP_START + 4) #define EL_GROUP_6 (EL_GROUP_START + 5) #define EL_GROUP_7 (EL_GROUP_START + 6) #define EL_GROUP_8 (EL_GROUP_START + 7) #define EL_GROUP_9 (EL_GROUP_START + 8) #define EL_GROUP_10 (EL_GROUP_START + 9) #define EL_GROUP_11 (EL_GROUP_START + 10) #define EL_GROUP_12 (EL_GROUP_START + 11) #define EL_GROUP_13 (EL_GROUP_START + 12) #define EL_GROUP_14 (EL_GROUP_START + 13) #define EL_GROUP_15 (EL_GROUP_START + 14) #define EL_GROUP_16 (EL_GROUP_START + 15) #define EL_GROUP_17 (EL_GROUP_START + 16) #define EL_GROUP_18 (EL_GROUP_START + 17) #define EL_GROUP_19 (EL_GROUP_START + 18) #define EL_GROUP_20 (EL_GROUP_START + 19) #define EL_GROUP_21 (EL_GROUP_START + 20) #define EL_GROUP_22 (EL_GROUP_START + 21) #define EL_GROUP_23 (EL_GROUP_START + 22) #define EL_GROUP_24 (EL_GROUP_START + 23) #define EL_GROUP_25 (EL_GROUP_START + 24) #define EL_GROUP_26 (EL_GROUP_START + 25) #define EL_GROUP_27 (EL_GROUP_START + 26) #define EL_GROUP_28 (EL_GROUP_START + 27) #define EL_GROUP_29 (EL_GROUP_START + 28) #define EL_GROUP_30 (EL_GROUP_START + 29) #define EL_GROUP_31 (EL_GROUP_START + 30) #define EL_GROUP_32 (EL_GROUP_START + 31) #endif /* CONF_GRP_C */ rocksndiamonds-3.3.0.1+dfsg1/src/init.h0000644000175000017500000000343711357175263016552 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * init.h * ***********************************************************/ #ifndef INIT_H #define INIT_H #include "main.h" #define setMoveIntoAcidProperty(l, e, v) \ (setBitfieldProperty(&(l)->can_move_into_acid_bits, \ EP_CAN_MOVE_INTO_ACID, e, v)) #define getMoveIntoAcidProperty(l, e) \ (getBitfieldProperty(&(l)->can_move_into_acid_bits, \ EP_CAN_MOVE_INTO_ACID, e)) #define setDontCollideWithProperty(l, e, v) \ (setBitfieldProperty(&(l)->dont_collide_with_bits, \ EP_DONT_COLLIDE_WITH, e, v)) #define getDontCollideWithProperty(l, e) \ (getBitfieldProperty(&(l)->dont_collide_with_bits, \ EP_DONT_COLLIDE_WITH, e)) void setBitfieldProperty(int *, int, int, boolean); boolean getBitfieldProperty(int *, int, int); void ResolveGroupElement(int); void InitElementPropertiesStatic(void); void InitElementPropertiesEngine(int); void InitElementPropertiesAfterLoading(int); void InitElementPropertiesGfxElement(); void ReloadCustomArtwork(int); void RedrawBackground(); void KeyboardAutoRepeatOffUnlessAutoplay(); void InitGfxBuffers(); void InitGadgets(); void OpenAll(void); void CloseAllAndExit(int); #endif rocksndiamonds-3.3.0.1+dfsg1/src/editor.c0000644000175000017500000132046211364305507017063 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * editor.c * ***********************************************************/ #include #include "libgame/libgame.h" #include "editor.h" #include "screens.h" #include "tools.h" #include "files.h" #include "game.h" #include "init.h" #include "tape.h" #define INFOTEXT_UNKNOWN_ELEMENT "unknown" /* ----------------------------------------------------------------------------- screen and artwork graphic pixel position definitions ----------------------------------------------------------------------------- */ /* positions in the level editor */ #define ED_WIN_MB_LEFT_XPOS 6 #define ED_WIN_MB_LEFT_YPOS 258 #define ED_WIN_MB_MIDDLE_XPOS 42 #define ED_WIN_MB_MIDDLE_YPOS ED_WIN_MB_LEFT_YPOS #define ED_WIN_MB_RIGHT_XPOS 78 #define ED_WIN_MB_RIGHT_YPOS ED_WIN_MB_LEFT_YPOS /* values for the control window */ #define ED_CTRL_NO_BUTTONS_GFX_XPOS 6 #define ED_CTRL_NO_BUTTONS_GFX_YPOS 286 #define ED_CTRL1_BUTTONS_GFX_YPOS 236 #define ED_CTRL2_BUTTONS_GFX_YPOS 236 #define ED_CTRL3_BUTTONS_GFX_YPOS 324 #define ED_CTRL4_BUTTONS_GFX_XPOS 44 #define ED_CTRL4_BUTTONS_GFX_YPOS 214 #define ED_CTRL1_BUTTONS_ALT_GFX_YPOS 142 #define ED_CTRL3_BUTTONS_ALT_GFX_YPOS 302 #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_BUTTON_XSIZE 30 #define ED_CTRL2_BUTTON_YSIZE 20 #define ED_CTRL2_BUTTONS_XPOS 5 #define ED_CTRL2_BUTTONS_YPOS 99 #define ED_CTRL3_BUTTON_XSIZE 22 #define ED_CTRL3_BUTTON_YSIZE 22 #define ED_CTRL3_BUTTONS_XPOS 6 #define ED_CTRL3_BUTTONS_YPOS 6 #define ED_CTRL4_BUTTON_XSIZE 22 #define ED_CTRL4_BUTTON_YSIZE 22 #define ED_CTRL4_BUTTONS_XPOS 6 #define ED_CTRL4_BUTTONS_YPOS 6 #define ED_CTRL1_BUTTONS_HORIZ 4 #define ED_CTRL1_BUTTONS_VERT 4 #define ED_CTRL2_BUTTONS_HORIZ 3 #define ED_CTRL2_BUTTONS_VERT 2 #define ED_CTRL3_BUTTONS_HORIZ 3 #define ED_CTRL3_BUTTONS_VERT 1 #define ED_CTRL4_BUTTONS_HORIZ 2 #define ED_CTRL4_BUTTONS_VERT 1 #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_CTRL3_BUTTONS (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT) #define ED_NUM_CTRL4_BUTTONS (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT) #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS) #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS) #define ED_NUM_CTRL_BUTTONS (ED_NUM_CTRL1_BUTTONS + \ ED_NUM_CTRL2_BUTTONS + \ ED_NUM_CTRL3_BUTTONS + \ ED_NUM_CTRL4_BUTTONS) /* values for the element list */ #define ED_ELEMENTLIST_XPOS 5 #define ED_ELEMENTLIST_YPOS 30 #define ED_ELEMENTLIST_XSIZE 20 #define ED_ELEMENTLIST_YSIZE 20 #define ED_ELEMENTLIST_BUTTONS_HORIZ 4 #define ED_ELEMENTLIST_BUTTONS_VERT 11 #define ED_NUM_ELEMENTLIST_BUTTONS (ED_ELEMENTLIST_BUTTONS_HORIZ * \ ED_ELEMENTLIST_BUTTONS_VERT) /* standard distances */ #define ED_BORDER_SIZE 3 #define ED_BORDER_TEXT_XSIZE 5 #define ED_BORDER_AREA_YSIZE 1 #define ED_GADGET_DISTANCE 2 #define ED_GADGET_TEXT_DISTANCE (2 * ED_GADGET_DISTANCE) #define ED_DRAWINGAREA_TEXT_DISTANCE (ED_GADGET_TEXT_DISTANCE + \ MINI_TILEX / 2) /* values for the settings windows */ #define ED_LEVEL_SETTINGS_XSTART (3 * MINI_TILEX / 2) #define ED_LEVEL_SETTINGS_YSTART (7 * MINI_TILEY) #define ED_ELEMENT_SETTINGS_XSTART (3 * MINI_TILEX / 2) #define ED_ELEMENT_SETTINGS_YSTART (10 * MINI_TILEY) #define ED_XOFFSET_CHECKBOX (ED_CHECKBUTTON_XSIZE + \ 2 * ED_GADGET_DISTANCE) #define ED_SETTINGS_XOFFSET ED_XOFFSET_CHECKBOX #define ED_SETTINGS_YOFFSET (3 * MINI_TILEY / 2) #define ED_SETTINGS_TAB_XOFFSET 124 #define ED_LEVEL_SETTINGS_XPOS(n) (ED_LEVEL_SETTINGS_XSTART + \ (n) * ED_SETTINGS_XOFFSET) #define ED_LEVEL_SETTINGS_YPOS(n) (ED_LEVEL_SETTINGS_YSTART + \ (n) * ED_SETTINGS_YOFFSET) #define ED_ELEMENT_SETTINGS_XPOS(n) (ED_ELEMENT_SETTINGS_XSTART + \ (n) * ED_SETTINGS_XOFFSET) #define ED_ELEMENT_SETTINGS_YPOS(n) (ED_ELEMENT_SETTINGS_YSTART + \ (n) * ED_SETTINGS_YOFFSET) #define ED_LEVEL_SETTINGS_TABS_XPOS(n) (ED_LEVEL_SETTINGS_XPOS(0) + \ (n) * ED_SETTINGS_TAB_XOFFSET) #define ED_LEVEL_SETTINGS_TABS_YPOS(n) (ED_LEVEL_SETTINGS_YSTART - \ 3 * MINI_TILEY) #define ED_ELEMENT_SETTINGS_TABS_XPOS(n) (ED_ELEMENT_SETTINGS_XPOS(0) + \ (n) * ED_SETTINGS_TAB_XOFFSET) #define ED_ELEMENT_SETTINGS_TABS_YPOS(n) (ED_ELEMENT_SETTINGS_YSTART - \ 2 * MINI_TILEY) #define ED_SETTINGS1_YPOS MINI_TILEY #define ED_SETTINGS2_XPOS MINI_TILEX #define ED_SETTINGS2_YPOS (ED_SETTINGS1_YPOS + 12 * TILEY - 2) /* values for counter gadgets */ #define ED_COUNTER_YSTART (ED_SETTINGS1_YPOS + 2 * TILEY) #define ED_COUNTER_YDISTANCE (3 * MINI_TILEY) #define ED_COUNTER_YPOS(n) (ED_COUNTER_YSTART + \ (n) * ED_COUNTER_YDISTANCE) #define ED_COUNTER2_YPOS(n) (ED_COUNTER_YSTART + \ (n) * ED_COUNTER_YDISTANCE - 2) /* values for element content drawing areas */ #define ED_AREA_1X1_SETTINGS_XPOS(n) (ED_ELEMENT_SETTINGS_XPOS(n)) #define ED_AREA_1X1_SETTINGS_YPOS(n) (ED_ELEMENT_SETTINGS_YPOS(n) + \ ED_GADGET_DISTANCE) #define ED_AREA_3X3_SETTINGS_XPOS(n) (ED_ELEMENT_SETTINGS_XPOS(n)) #define ED_AREA_3X3_SETTINGS_YPOS(n) (ED_ELEMENT_SETTINGS_YPOS(n) + \ ED_GADGET_DISTANCE - MINI_TILEY) /* yamyam content */ #define ED_AREA_YAMYAM_CONTENT_XPOS(n) (2 * MINI_TILEX + \ 5 * ((n) % 4) * MINI_TILEX) #define ED_AREA_YAMYAM_CONTENT_YPOS(n) (11 * ED_SETTINGS_YOFFSET + \ 6 * ((n) / 4) * MINI_TILEY) /* magic ball content */ #define ED_AREA_MAGIC_BALL_CONTENT_XPOS(n) (2 * MINI_TILEX + \ 5 * ((n) % 4) * MINI_TILEX) #define ED_AREA_MAGIC_BALL_CONTENT_YPOS(n) (12 * ED_SETTINGS_YOFFSET + \ 6 * ((n) / 4) * MINI_TILEY) /* values for scrolling gadgets for drawing area */ #define ED_SCROLLBUTTON_XPOS 24 #define ED_SCROLLBUTTON_YPOS 0 #define ED_SCROLLBAR_XPOS 24 #define ED_SCROLLBAR_YPOS 64 #define ED_SCROLLBUTTON_XSIZE 16 #define ED_SCROLLBUTTON_YSIZE 16 #define ED_SCROLL_UP_XPOS (SXSIZE - ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_UP_YPOS (0) #define ED_SCROLL_DOWN_XPOS ED_SCROLL_UP_XPOS #define ED_SCROLL_DOWN_YPOS (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_LEFT_XPOS (0) #define ED_SCROLL_LEFT_YPOS (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_RIGHT_XPOS (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_RIGHT_YPOS ED_SCROLL_LEFT_YPOS #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + \ ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_HORIZONTAL_YPOS ED_SCROLL_LEFT_YPOS #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE #define ED_SCROLL_VERTICAL_XPOS ED_SCROLL_UP_XPOS #define ED_SCROLL_VERTICAL_YPOS (ED_SCROLL_UP_YPOS + \ ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_VERTICAL_XSIZE ED_SCROLLBUTTON_XSIZE #define ED_SCROLL_VERTICAL_YSIZE (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE) /* values for scrolling gadgets for element list */ #define ED_SCROLLBUTTON2_XPOS 50 #define ED_SCROLLBUTTON2_YPOS 0 #define ED_SCROLLBAR2_XPOS 50 #define ED_SCROLLBAR2_YPOS 20 #define ED_SCROLLBUTTON2_XSIZE 10 #define ED_SCROLLBUTTON2_YSIZE 10 #define ED_SCROLL2_UP_XPOS 85 #define ED_SCROLL2_UP_YPOS 30 #define ED_SCROLL2_DOWN_XPOS ED_SCROLL2_UP_XPOS #define ED_SCROLL2_DOWN_YPOS (ED_SCROLL2_UP_YPOS + \ ED_ELEMENTLIST_BUTTONS_VERT * \ ED_ELEMENTLIST_YSIZE - \ ED_SCROLLBUTTON2_YSIZE) #define ED_SCROLL2_VERTICAL_XPOS ED_SCROLL2_UP_XPOS #define ED_SCROLL2_VERTICAL_YPOS (ED_SCROLL2_UP_YPOS + \ ED_SCROLLBUTTON2_YSIZE) #define ED_SCROLL2_VERTICAL_XSIZE ED_SCROLLBUTTON2_XSIZE #define ED_SCROLL2_VERTICAL_YSIZE (ED_ELEMENTLIST_BUTTONS_VERT * \ ED_ELEMENTLIST_YSIZE - \ 2 * ED_SCROLLBUTTON2_YSIZE) /* values for checkbutton gadgets */ #define ED_CHECKBUTTON_XSIZE ED_BUTTON_COUNT_XSIZE #define ED_CHECKBUTTON_YSIZE ED_BUTTON_COUNT_YSIZE #define ED_CHECKBUTTON_UNCHECKED_XPOS ED_BUTTON_MINUS_XPOS #define ED_CHECKBUTTON_CHECKED_XPOS ED_BUTTON_PLUS_XPOS #define ED_CHECKBUTTON_YPOS (ED_BUTTON_MINUS_YPOS + 22) #define ED_RADIOBUTTON_YPOS (ED_BUTTON_MINUS_YPOS + 44) #define ED_STICKYBUTTON_YPOS (ED_BUTTON_MINUS_YPOS + 66) /* values for some special graphic buttons */ #define ED_COPY_CHANGE_PAGE_XPOS 25 #define ED_COPY_CHANGE_PAGE_YPOS 50 #define ED_PASTE_CHANGE_PAGE_XPOS 25 #define ED_PASTE_CHANGE_PAGE_YPOS 70 /* some values for text input, selectbox and counter gadgets */ #define ED_BUTTON_COUNT_YPOS 60 #define ED_BUTTON_COUNT_XSIZE 20 #define ED_BUTTON_COUNT_YSIZE 20 #define ED_WIN_COUNT_XPOS (2 + ED_BUTTON_COUNT_XSIZE + 2) #define ED_WIN_COUNT_YPOS ED_BUTTON_COUNT_YPOS #define ED_WIN_COUNT_XSIZE 52 #define ED_WIN_COUNT_YSIZE ED_BUTTON_COUNT_YSIZE #define ED_WIN_COUNT2_XPOS 27 #define ED_WIN_COUNT2_YPOS 3 #define ED_WIN_COUNT2_XSIZE 46 #define ED_WIN_COUNT2_YSIZE ED_BUTTON_COUNT_YSIZE #define ED_BUTTON_MINUS_XPOS 2 #define ED_BUTTON_MINUS_YPOS ED_BUTTON_COUNT_YPOS #define ED_BUTTON_MINUS_XSIZE ED_BUTTON_COUNT_XSIZE #define ED_BUTTON_MINUS_YSIZE ED_BUTTON_COUNT_YSIZE #define ED_BUTTON_PLUS_XPOS (ED_WIN_COUNT_XPOS + \ ED_WIN_COUNT_XSIZE + 2) #define ED_BUTTON_PLUS_YPOS ED_BUTTON_COUNT_YPOS #define ED_BUTTON_PLUS_XSIZE ED_BUTTON_COUNT_XSIZE #define ED_BUTTON_PLUS_YSIZE ED_BUTTON_COUNT_YSIZE #define ED_SELECTBOX_XPOS ED_WIN_COUNT_XPOS #define ED_SELECTBOX_YPOS (ED_WIN_COUNT_YPOS + \ 2 + ED_WIN_COUNT_YSIZE) #define ED_SELECTBOX_XSIZE ED_WIN_COUNT_XSIZE #define ED_SELECTBOX_YSIZE ED_WIN_COUNT_YSIZE #define ED_SELECTBOX_BUTTON_XSIZE 14 #define ED_TEXTBUTTON_XPOS ED_WIN_COUNT_XPOS #define ED_TEXTBUTTON_YPOS (ED_WIN_COUNT_YPOS + \ 4 * (2 + ED_WIN_COUNT_YSIZE)) #define ED_TEXTBUTTON_INACTIVE_YPOS ED_TEXTBUTTON_YPOS #define ED_TEXTBUTTON_TAB_XPOS ED_WIN_COUNT_XPOS #define ED_TEXTBUTTON_TAB_YPOS (ED_WIN_COUNT_YPOS + \ 2 * (2 + ED_WIN_COUNT_YSIZE)) #define ED_TEXTBUTTON_TAB_INACTIVE_YPOS (ED_WIN_COUNT_YPOS + \ 3 * (2 + ED_WIN_COUNT_YSIZE)) #define ED_TEXTBUTTON_XSIZE ED_WIN_COUNT_XSIZE #define ED_TEXTBUTTON_YSIZE ED_WIN_COUNT_YSIZE /* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */ #define INFOTEXT_XPOS SX #define INFOTEXT_YPOS (SY + SYSIZE - MINI_TILEX + 2) #define INFOTEXT_XSIZE SXSIZE #define INFOTEXT_YSIZE MINI_TILEX /* ----------------------------------------------------------------------------- editor gadget definitions ----------------------------------------------------------------------------- */ /* drawing toolbox buttons */ #define GADGET_ID_NONE -1 #define GADGET_ID_TOOLBOX_FIRST 0 #define GADGET_ID_SINGLE_ITEMS (GADGET_ID_TOOLBOX_FIRST + 0) #define GADGET_ID_CONNECTED_ITEMS (GADGET_ID_TOOLBOX_FIRST + 1) #define GADGET_ID_LINE (GADGET_ID_TOOLBOX_FIRST + 2) #define GADGET_ID_ARC (GADGET_ID_TOOLBOX_FIRST + 3) #define GADGET_ID_RECTANGLE (GADGET_ID_TOOLBOX_FIRST + 4) #define GADGET_ID_FILLED_BOX (GADGET_ID_TOOLBOX_FIRST + 5) #define GADGET_ID_WRAP_UP (GADGET_ID_TOOLBOX_FIRST + 6) #define GADGET_ID_TEXT (GADGET_ID_TOOLBOX_FIRST + 7) #define GADGET_ID_FLOOD_FILL (GADGET_ID_TOOLBOX_FIRST + 8) #define GADGET_ID_WRAP_LEFT (GADGET_ID_TOOLBOX_FIRST + 9) #define GADGET_ID_PROPERTIES (GADGET_ID_TOOLBOX_FIRST + 10) #define GADGET_ID_WRAP_RIGHT (GADGET_ID_TOOLBOX_FIRST + 11) #define GADGET_ID_RANDOM_PLACEMENT (GADGET_ID_TOOLBOX_FIRST + 12) #define GADGET_ID_GRAB_BRUSH (GADGET_ID_TOOLBOX_FIRST + 13) #define GADGET_ID_WRAP_DOWN (GADGET_ID_TOOLBOX_FIRST + 14) #define GADGET_ID_PICK_ELEMENT (GADGET_ID_TOOLBOX_FIRST + 15) #define GADGET_ID_UNDO (GADGET_ID_TOOLBOX_FIRST + 16) #define GADGET_ID_INFO (GADGET_ID_TOOLBOX_FIRST + 17) #define GADGET_ID_SAVE (GADGET_ID_TOOLBOX_FIRST + 18) #define GADGET_ID_CLEAR (GADGET_ID_TOOLBOX_FIRST + 19) #define GADGET_ID_TEST (GADGET_ID_TOOLBOX_FIRST + 20) #define GADGET_ID_EXIT (GADGET_ID_TOOLBOX_FIRST + 21) #define GADGET_ID_CUSTOM_COPY_FROM (GADGET_ID_TOOLBOX_FIRST + 22) #define GADGET_ID_CUSTOM_COPY_TO (GADGET_ID_TOOLBOX_FIRST + 23) #define GADGET_ID_CUSTOM_EXCHANGE (GADGET_ID_TOOLBOX_FIRST + 24) #define GADGET_ID_CUSTOM_COPY (GADGET_ID_TOOLBOX_FIRST + 25) #define GADGET_ID_CUSTOM_PASTE (GADGET_ID_TOOLBOX_FIRST + 26) /* counter gadget identifiers */ #define GADGET_ID_COUNTER_FIRST (GADGET_ID_TOOLBOX_FIRST + 27) #define GADGET_ID_SELECT_LEVEL_DOWN (GADGET_ID_COUNTER_FIRST + 0) #define GADGET_ID_SELECT_LEVEL_TEXT (GADGET_ID_COUNTER_FIRST + 1) #define GADGET_ID_SELECT_LEVEL_UP (GADGET_ID_COUNTER_FIRST + 2) #define GADGET_ID_LEVEL_XSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 3) #define GADGET_ID_LEVEL_XSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 4) #define GADGET_ID_LEVEL_XSIZE_UP (GADGET_ID_COUNTER_FIRST + 5) #define GADGET_ID_LEVEL_YSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 6) #define GADGET_ID_LEVEL_YSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 7) #define GADGET_ID_LEVEL_YSIZE_UP (GADGET_ID_COUNTER_FIRST + 8) #define GADGET_ID_LEVEL_RANDOM_DOWN (GADGET_ID_COUNTER_FIRST + 9) #define GADGET_ID_LEVEL_RANDOM_TEXT (GADGET_ID_COUNTER_FIRST + 10) #define GADGET_ID_LEVEL_RANDOM_UP (GADGET_ID_COUNTER_FIRST + 11) #define GADGET_ID_LEVEL_GEMSLIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 12) #define GADGET_ID_LEVEL_GEMSLIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 13) #define GADGET_ID_LEVEL_GEMSLIMIT_UP (GADGET_ID_COUNTER_FIRST + 14) #define GADGET_ID_LEVEL_TIMELIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 15) #define GADGET_ID_LEVEL_TIMELIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 16) #define GADGET_ID_LEVEL_TIMELIMIT_UP (GADGET_ID_COUNTER_FIRST + 17) #define GADGET_ID_LEVEL_TIMESCORE_DOWN (GADGET_ID_COUNTER_FIRST + 18) #define GADGET_ID_LEVEL_TIMESCORE_TEXT (GADGET_ID_COUNTER_FIRST + 19) #define GADGET_ID_LEVEL_TIMESCORE_UP (GADGET_ID_COUNTER_FIRST + 20) #define GADGET_ID_LEVEL_RANDOM_SEED_DOWN (GADGET_ID_COUNTER_FIRST + 21) #define GADGET_ID_LEVEL_RANDOM_SEED_TEXT (GADGET_ID_COUNTER_FIRST + 22) #define GADGET_ID_LEVEL_RANDOM_SEED_UP (GADGET_ID_COUNTER_FIRST + 23) #define GADGET_ID_ELEMENT_VALUE1_DOWN (GADGET_ID_COUNTER_FIRST + 24) #define GADGET_ID_ELEMENT_VALUE1_TEXT (GADGET_ID_COUNTER_FIRST + 25) #define GADGET_ID_ELEMENT_VALUE1_UP (GADGET_ID_COUNTER_FIRST + 26) #define GADGET_ID_ELEMENT_VALUE2_DOWN (GADGET_ID_COUNTER_FIRST + 27) #define GADGET_ID_ELEMENT_VALUE2_TEXT (GADGET_ID_COUNTER_FIRST + 28) #define GADGET_ID_ELEMENT_VALUE2_UP (GADGET_ID_COUNTER_FIRST + 29) #define GADGET_ID_ELEMENT_VALUE3_DOWN (GADGET_ID_COUNTER_FIRST + 30) #define GADGET_ID_ELEMENT_VALUE3_TEXT (GADGET_ID_COUNTER_FIRST + 31) #define GADGET_ID_ELEMENT_VALUE3_UP (GADGET_ID_COUNTER_FIRST + 32) #define GADGET_ID_ELEMENT_VALUE4_DOWN (GADGET_ID_COUNTER_FIRST + 33) #define GADGET_ID_ELEMENT_VALUE4_TEXT (GADGET_ID_COUNTER_FIRST + 34) #define GADGET_ID_ELEMENT_VALUE4_UP (GADGET_ID_COUNTER_FIRST + 35) #define GADGET_ID_YAMYAM_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 36) #define GADGET_ID_YAMYAM_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 37) #define GADGET_ID_YAMYAM_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 38) #define GADGET_ID_BALL_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 39) #define GADGET_ID_BALL_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 40) #define GADGET_ID_BALL_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 41) #define GADGET_ID_ANDROID_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 42) #define GADGET_ID_ANDROID_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 43) #define GADGET_ID_ANDROID_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 44) #define GADGET_ID_ENVELOPE_XSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 45) #define GADGET_ID_ENVELOPE_XSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 46) #define GADGET_ID_ENVELOPE_XSIZE_UP (GADGET_ID_COUNTER_FIRST + 47) #define GADGET_ID_ENVELOPE_YSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 48) #define GADGET_ID_ENVELOPE_YSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 49) #define GADGET_ID_ENVELOPE_YSIZE_UP (GADGET_ID_COUNTER_FIRST + 50) #define GADGET_ID_INVENTORY_SIZE_DOWN (GADGET_ID_COUNTER_FIRST + 51) #define GADGET_ID_INVENTORY_SIZE_TEXT (GADGET_ID_COUNTER_FIRST + 52) #define GADGET_ID_INVENTORY_SIZE_UP (GADGET_ID_COUNTER_FIRST + 53) #define GADGET_ID_CUSTOM_SCORE_DOWN (GADGET_ID_COUNTER_FIRST + 54) #define GADGET_ID_CUSTOM_SCORE_TEXT (GADGET_ID_COUNTER_FIRST + 55) #define GADGET_ID_CUSTOM_SCORE_UP (GADGET_ID_COUNTER_FIRST + 56) #define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 57) #define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 58) #define GADGET_ID_CUSTOM_GEMCOUNT_UP (GADGET_ID_COUNTER_FIRST + 59) #define GADGET_ID_CUSTOM_VALUE_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 60) #define GADGET_ID_CUSTOM_VALUE_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 61) #define GADGET_ID_CUSTOM_VALUE_FIX_UP (GADGET_ID_COUNTER_FIRST + 62) #define GADGET_ID_CUSTOM_VALUE_RND_DOWN (GADGET_ID_COUNTER_FIRST + 63) #define GADGET_ID_CUSTOM_VALUE_RND_TEXT (GADGET_ID_COUNTER_FIRST + 64) #define GADGET_ID_CUSTOM_VALUE_RND_UP (GADGET_ID_COUNTER_FIRST + 65) #define GADGET_ID_PUSH_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 66) #define GADGET_ID_PUSH_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 67) #define GADGET_ID_PUSH_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 68) #define GADGET_ID_PUSH_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 69) #define GADGET_ID_PUSH_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 70) #define GADGET_ID_PUSH_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 71) #define GADGET_ID_DROP_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 72) #define GADGET_ID_DROP_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 73) #define GADGET_ID_DROP_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 74) #define GADGET_ID_DROP_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 75) #define GADGET_ID_DROP_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 76) #define GADGET_ID_DROP_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 77) #define GADGET_ID_MOVE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 78) #define GADGET_ID_MOVE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 79) #define GADGET_ID_MOVE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 80) #define GADGET_ID_MOVE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 81) #define GADGET_ID_MOVE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 82) #define GADGET_ID_MOVE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 83) #define GADGET_ID_EXPLOSION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 84) #define GADGET_ID_EXPLOSION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 85) #define GADGET_ID_EXPLOSION_DELAY_UP (GADGET_ID_COUNTER_FIRST + 86) #define GADGET_ID_IGNITION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 87) #define GADGET_ID_IGNITION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 88) #define GADGET_ID_IGNITION_DELAY_UP (GADGET_ID_COUNTER_FIRST + 89) #define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 90) #define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 91) #define GADGET_ID_CHANGE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 92) #define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 93) #define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 94) #define GADGET_ID_CHANGE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 95) #define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 96) #define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 97) #define GADGET_ID_CHANGE_CONT_RND_UP (GADGET_ID_COUNTER_FIRST + 98) #define GADGET_ID_GROUP_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 99) #define GADGET_ID_GROUP_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 100) #define GADGET_ID_GROUP_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 101) /* drawing area identifiers */ #define GADGET_ID_DRAWING_AREA_FIRST (GADGET_ID_COUNTER_FIRST + 102) #define GADGET_ID_DRAWING_LEVEL (GADGET_ID_DRAWING_AREA_FIRST + 0) #define GADGET_ID_YAMYAM_CONTENT_0 (GADGET_ID_DRAWING_AREA_FIRST + 1) #define GADGET_ID_YAMYAM_CONTENT_1 (GADGET_ID_DRAWING_AREA_FIRST + 2) #define GADGET_ID_YAMYAM_CONTENT_2 (GADGET_ID_DRAWING_AREA_FIRST + 3) #define GADGET_ID_YAMYAM_CONTENT_3 (GADGET_ID_DRAWING_AREA_FIRST + 4) #define GADGET_ID_YAMYAM_CONTENT_4 (GADGET_ID_DRAWING_AREA_FIRST + 5) #define GADGET_ID_YAMYAM_CONTENT_5 (GADGET_ID_DRAWING_AREA_FIRST + 6) #define GADGET_ID_YAMYAM_CONTENT_6 (GADGET_ID_DRAWING_AREA_FIRST + 7) #define GADGET_ID_YAMYAM_CONTENT_7 (GADGET_ID_DRAWING_AREA_FIRST + 8) #define GADGET_ID_MAGIC_BALL_CONTENT_0 (GADGET_ID_DRAWING_AREA_FIRST + 9) #define GADGET_ID_MAGIC_BALL_CONTENT_1 (GADGET_ID_DRAWING_AREA_FIRST + 10) #define GADGET_ID_MAGIC_BALL_CONTENT_2 (GADGET_ID_DRAWING_AREA_FIRST + 11) #define GADGET_ID_MAGIC_BALL_CONTENT_3 (GADGET_ID_DRAWING_AREA_FIRST + 12) #define GADGET_ID_MAGIC_BALL_CONTENT_4 (GADGET_ID_DRAWING_AREA_FIRST + 13) #define GADGET_ID_MAGIC_BALL_CONTENT_5 (GADGET_ID_DRAWING_AREA_FIRST + 14) #define GADGET_ID_MAGIC_BALL_CONTENT_6 (GADGET_ID_DRAWING_AREA_FIRST + 15) #define GADGET_ID_MAGIC_BALL_CONTENT_7 (GADGET_ID_DRAWING_AREA_FIRST + 16) #define GADGET_ID_ANDROID_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 17) #define GADGET_ID_AMOEBA_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 18) #define GADGET_ID_START_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 19) #define GADGET_ID_ARTWORK_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 20) #define GADGET_ID_EXPLOSION_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 21) #define GADGET_ID_INVENTORY_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 22) #define GADGET_ID_CUSTOM_GRAPHIC (GADGET_ID_DRAWING_AREA_FIRST + 23) #define GADGET_ID_CUSTOM_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 24) #define GADGET_ID_CUSTOM_MOVE_ENTER (GADGET_ID_DRAWING_AREA_FIRST + 25) #define GADGET_ID_CUSTOM_MOVE_LEAVE (GADGET_ID_DRAWING_AREA_FIRST + 26) #define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 27) #define GADGET_ID_CUSTOM_CHANGE_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 28) #define GADGET_ID_CUSTOM_CHANGE_TRIGGER (GADGET_ID_DRAWING_AREA_FIRST + 29) #define GADGET_ID_CUSTOM_CHANGE_ACTION (GADGET_ID_DRAWING_AREA_FIRST + 30) #define GADGET_ID_GROUP_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 31) #define GADGET_ID_RANDOM_BACKGROUND (GADGET_ID_DRAWING_AREA_FIRST + 32) /* text input identifiers */ #define GADGET_ID_TEXT_INPUT_FIRST (GADGET_ID_DRAWING_AREA_FIRST + 33) #define GADGET_ID_LEVEL_NAME (GADGET_ID_TEXT_INPUT_FIRST + 0) #define GADGET_ID_LEVEL_AUTHOR (GADGET_ID_TEXT_INPUT_FIRST + 1) #define GADGET_ID_ELEMENT_NAME (GADGET_ID_TEXT_INPUT_FIRST + 2) /* text area identifiers */ #define GADGET_ID_TEXT_AREA_FIRST (GADGET_ID_TEXT_INPUT_FIRST + 3) #define GADGET_ID_ENVELOPE_INFO (GADGET_ID_TEXT_AREA_FIRST + 0) /* selectbox identifiers */ #define GADGET_ID_SELECTBOX_FIRST (GADGET_ID_TEXT_AREA_FIRST + 1) #define GADGET_ID_TIME_OR_STEPS (GADGET_ID_SELECTBOX_FIRST + 0) #define GADGET_ID_GAME_ENGINE_TYPE (GADGET_ID_SELECTBOX_FIRST + 1) #define GADGET_ID_WIND_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 2) #define GADGET_ID_PLAYER_SPEED (GADGET_ID_SELECTBOX_FIRST + 3) #define GADGET_ID_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 4) #define GADGET_ID_CUSTOM_EXPLOSION_TYPE (GADGET_ID_SELECTBOX_FIRST + 5) #define GADGET_ID_CUSTOM_DEADLINESS (GADGET_ID_SELECTBOX_FIRST + 6) #define GADGET_ID_CUSTOM_MOVE_PATTERN (GADGET_ID_SELECTBOX_FIRST + 7) #define GADGET_ID_CUSTOM_MOVE_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 8) #define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 9) #define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 10) #define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 11) #define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 12) #define GADGET_ID_CUSTOM_ACCESS_TYPE (GADGET_ID_SELECTBOX_FIRST + 13) #define GADGET_ID_CUSTOM_ACCESS_LAYER (GADGET_ID_SELECTBOX_FIRST + 14) #define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 15) #define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 16) #define GADGET_ID_CHANGE_TIME_UNITS (GADGET_ID_SELECTBOX_FIRST + 17) #define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 18) #define GADGET_ID_CHANGE_OTHER_ACTION (GADGET_ID_SELECTBOX_FIRST + 19) #define GADGET_ID_CHANGE_SIDE (GADGET_ID_SELECTBOX_FIRST + 20) #define GADGET_ID_CHANGE_PLAYER (GADGET_ID_SELECTBOX_FIRST + 21) #define GADGET_ID_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 22) #define GADGET_ID_CHANGE_REPLACE_WHEN (GADGET_ID_SELECTBOX_FIRST + 23) #define GADGET_ID_ACTION_TYPE (GADGET_ID_SELECTBOX_FIRST + 24) #define GADGET_ID_ACTION_MODE (GADGET_ID_SELECTBOX_FIRST + 25) #define GADGET_ID_ACTION_ARG (GADGET_ID_SELECTBOX_FIRST + 26) #define GADGET_ID_SELECT_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 27) #define GADGET_ID_GROUP_CHOICE_MODE (GADGET_ID_SELECTBOX_FIRST + 28) /* textbutton identifiers */ #define GADGET_ID_TEXTBUTTON_FIRST (GADGET_ID_SELECTBOX_FIRST + 29) #define GADGET_ID_LEVELINFO_LEVEL (GADGET_ID_TEXTBUTTON_FIRST + 0) #define GADGET_ID_LEVELINFO_EDITOR (GADGET_ID_TEXTBUTTON_FIRST + 1) #define GADGET_ID_PROPERTIES_INFO (GADGET_ID_TEXTBUTTON_FIRST + 2) #define GADGET_ID_PROPERTIES_CONFIG (GADGET_ID_TEXTBUTTON_FIRST + 3) #define GADGET_ID_PROPERTIES_CONFIG_1 (GADGET_ID_TEXTBUTTON_FIRST + 4) #define GADGET_ID_PROPERTIES_CONFIG_2 (GADGET_ID_TEXTBUTTON_FIRST + 5) #define GADGET_ID_PROPERTIES_CHANGE (GADGET_ID_TEXTBUTTON_FIRST + 6) #define GADGET_ID_SAVE_AS_TEMPLATE (GADGET_ID_TEXTBUTTON_FIRST + 7) #define GADGET_ID_ADD_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 8) #define GADGET_ID_DEL_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 9) /* graphicbutton identifiers */ #define GADGET_ID_GRAPHICBUTTON_FIRST (GADGET_ID_TEXTBUTTON_FIRST + 10) #define GADGET_ID_PREV_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 0) #define GADGET_ID_NEXT_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 1) #define GADGET_ID_COPY_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 2) #define GADGET_ID_PASTE_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 3) /* gadgets for scrolling of drawing area */ #define GADGET_ID_SCROLLING_FIRST (GADGET_ID_GRAPHICBUTTON_FIRST + 4) #define GADGET_ID_SCROLL_UP (GADGET_ID_SCROLLING_FIRST + 0) #define GADGET_ID_SCROLL_DOWN (GADGET_ID_SCROLLING_FIRST + 1) #define GADGET_ID_SCROLL_LEFT (GADGET_ID_SCROLLING_FIRST + 2) #define GADGET_ID_SCROLL_RIGHT (GADGET_ID_SCROLLING_FIRST + 3) #define GADGET_ID_SCROLL_HORIZONTAL (GADGET_ID_SCROLLING_FIRST + 4) #define GADGET_ID_SCROLL_VERTICAL (GADGET_ID_SCROLLING_FIRST + 5) /* gadgets for scrolling element list */ #define GADGET_ID_SCROLLING_LIST_FIRST (GADGET_ID_SCROLLING_FIRST + 6) #define GADGET_ID_SCROLL_LIST_UP (GADGET_ID_SCROLLING_LIST_FIRST + 0) #define GADGET_ID_SCROLL_LIST_DOWN (GADGET_ID_SCROLLING_LIST_FIRST + 1) #define GADGET_ID_SCROLL_LIST_VERTICAL (GADGET_ID_SCROLLING_LIST_FIRST + 2) /* checkbuttons/radiobuttons for level/element properties */ #define GADGET_ID_CHECKBUTTON_FIRST (GADGET_ID_SCROLLING_LIST_FIRST + 3) #define GADGET_ID_RANDOM_PERCENTAGE (GADGET_ID_CHECKBUTTON_FIRST + 0) #define GADGET_ID_RANDOM_QUANTITY (GADGET_ID_CHECKBUTTON_FIRST + 1) #define GADGET_ID_RANDOM_RESTRICTED (GADGET_ID_CHECKBUTTON_FIRST + 2) #define GADGET_ID_STICK_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 3) #define GADGET_ID_EM_SLIPPERY_GEMS (GADGET_ID_CHECKBUTTON_FIRST + 4) #define GADGET_ID_EM_EXPLODES_BY_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 5) #define GADGET_ID_USE_SPRING_BUG (GADGET_ID_CHECKBUTTON_FIRST + 6) #define GADGET_ID_USE_TIME_ORB_BUG (GADGET_ID_CHECKBUTTON_FIRST + 7) #define GADGET_ID_RANDOM_BALL_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 8) #define GADGET_ID_INITIAL_BALL_STATE (GADGET_ID_CHECKBUTTON_FIRST + 9) #define GADGET_ID_GROW_INTO_DIGGABLE (GADGET_ID_CHECKBUTTON_FIRST + 10) #define GADGET_ID_AUTO_EXIT_SOKOBAN (GADGET_ID_CHECKBUTTON_FIRST + 11) #define GADGET_ID_CONTINUOUS_SNAPPING (GADGET_ID_CHECKBUTTON_FIRST + 12) #define GADGET_ID_BLOCK_SNAP_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 13) #define GADGET_ID_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 14) #define GADGET_ID_SP_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 15) #define GADGET_ID_INSTANT_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 16) #define GADGET_ID_SHIFTED_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 17) #define GADGET_ID_USE_START_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 18) #define GADGET_ID_USE_ARTWORK_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 19) #define GADGET_ID_USE_EXPLOSION_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 20) #define GADGET_ID_INITIAL_GRAVITY (GADGET_ID_CHECKBUTTON_FIRST + 21) #define GADGET_ID_USE_INITIAL_INVENTORY (GADGET_ID_CHECKBUTTON_FIRST + 22) #define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 23) #define GADGET_ID_CAN_FALL_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 24) #define GADGET_ID_CAN_MOVE_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 25) #define GADGET_ID_DONT_COLLIDE_WITH (GADGET_ID_CHECKBUTTON_FIRST + 26) #define GADGET_ID_ENVELOPE_AUTOWRAP (GADGET_ID_CHECKBUTTON_FIRST + 27) #define GADGET_ID_ENVELOPE_CENTERED (GADGET_ID_CHECKBUTTON_FIRST + 28) #define GADGET_ID_CUSTOM_INDESTRUCTIBLE (GADGET_ID_CHECKBUTTON_FIRST + 29) #define GADGET_ID_CUSTOM_CAN_EXPLODE (GADGET_ID_CHECKBUTTON_FIRST + 30) #define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 31) #define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 32) #define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 33) #define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 34) #define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 35) #define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 36) #define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 37) #define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 38) #define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 39) #define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 40) #define GADGET_ID_CUSTOM_GRAV_REACHABLE (GADGET_ID_CHECKBUTTON_FIRST + 41) #define GADGET_ID_CUSTOM_USE_LAST_VALUE (GADGET_ID_CHECKBUTTON_FIRST + 42) #define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 43) #define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 44) #define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 45) #define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 46) #define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 47) #define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 48) #define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 49) #define GADGET_ID_CHANGE_HAS_ACTION (GADGET_ID_CHECKBUTTON_FIRST + 50) #define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 51) #define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 52) #define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 53) /* gadgets for buttons in element list */ #define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 54) #define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \ ED_NUM_ELEMENTLIST_BUTTONS - 1) #define NUM_EDITOR_GADGETS (GADGET_ID_ELEMENTLIST_LAST + 1) /* radio button numbers */ #define RADIO_NR_NONE 0 #define RADIO_NR_DRAWING_TOOLBOX 1 #define RADIO_NR_RANDOM_ELEMENTS 2 /* values for counter gadgets */ #define ED_COUNTER_ID_SELECT_LEVEL 0 #define ED_COUNTER_ID_LEVEL_XSIZE 1 #define ED_COUNTER_ID_LEVEL_YSIZE 2 #define ED_COUNTER_ID_LEVEL_GEMSLIMIT 3 #define ED_COUNTER_ID_LEVEL_TIMELIMIT 4 #define ED_COUNTER_ID_LEVEL_TIMESCORE 5 #define ED_COUNTER_ID_LEVEL_RANDOM_SEED 6 #define ED_COUNTER_ID_LEVEL_RANDOM 7 #define ED_COUNTER_ID_ELEMENT_VALUE1 8 #define ED_COUNTER_ID_ELEMENT_VALUE2 9 #define ED_COUNTER_ID_ELEMENT_VALUE3 10 #define ED_COUNTER_ID_ELEMENT_VALUE4 11 #define ED_COUNTER_ID_YAMYAM_CONTENT 12 #define ED_COUNTER_ID_BALL_CONTENT 13 #define ED_COUNTER_ID_ANDROID_CONTENT 14 #define ED_COUNTER_ID_ENVELOPE_XSIZE 15 #define ED_COUNTER_ID_ENVELOPE_YSIZE 16 #define ED_COUNTER_ID_INVENTORY_SIZE 17 #define ED_COUNTER_ID_CUSTOM_SCORE 18 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT 19 #define ED_COUNTER_ID_CUSTOM_VALUE_FIX 20 #define ED_COUNTER_ID_CUSTOM_VALUE_RND 21 #define ED_COUNTER_ID_PUSH_DELAY_FIX 22 #define ED_COUNTER_ID_PUSH_DELAY_RND 23 #define ED_COUNTER_ID_DROP_DELAY_FIX 24 #define ED_COUNTER_ID_DROP_DELAY_RND 25 #define ED_COUNTER_ID_MOVE_DELAY_FIX 26 #define ED_COUNTER_ID_MOVE_DELAY_RND 27 #define ED_COUNTER_ID_EXPLOSION_DELAY 28 #define ED_COUNTER_ID_IGNITION_DELAY 29 #define ED_COUNTER_ID_GROUP_CONTENT 30 #define ED_COUNTER_ID_CHANGE_DELAY_FIX 31 #define ED_COUNTER_ID_CHANGE_DELAY_RND 32 #define ED_COUNTER_ID_CHANGE_CONT_RND 33 #define ED_NUM_COUNTERBUTTONS 34 #define ED_COUNTER_ID_LEVEL_FIRST ED_COUNTER_ID_LEVEL_XSIZE #define ED_COUNTER_ID_LEVEL_LAST ED_COUNTER_ID_LEVEL_RANDOM_SEED #define ED_COUNTER_ID_EDITOR_FIRST ED_COUNTER_ID_LEVEL_RANDOM #define ED_COUNTER_ID_EDITOR_LAST ED_COUNTER_ID_LEVEL_RANDOM #define ED_COUNTER_ID_CUSTOM1_FIRST ED_COUNTER_ID_CUSTOM_SCORE #define ED_COUNTER_ID_CUSTOM1_LAST ED_COUNTER_ID_DROP_DELAY_RND #define ED_COUNTER_ID_CUSTOM2_FIRST ED_COUNTER_ID_MOVE_DELAY_FIX #define ED_COUNTER_ID_CUSTOM2_LAST ED_COUNTER_ID_IGNITION_DELAY #define ED_COUNTER_ID_CUSTOM_FIRST ED_COUNTER_ID_CUSTOM1_FIRST #define ED_COUNTER_ID_CUSTOM_LAST ED_COUNTER_ID_CUSTOM2_LAST #define ED_COUNTER_ID_CHANGE_FIRST ED_COUNTER_ID_CHANGE_DELAY_FIX #define ED_COUNTER_ID_CHANGE_LAST ED_COUNTER_ID_CHANGE_CONT_RND /* values for scrollbutton gadgets */ #define ED_SCROLLBUTTON_ID_AREA_UP 0 #define ED_SCROLLBUTTON_ID_AREA_DOWN 1 #define ED_SCROLLBUTTON_ID_AREA_LEFT 2 #define ED_SCROLLBUTTON_ID_AREA_RIGHT 3 #define ED_SCROLLBUTTON_ID_LIST_UP 4 #define ED_SCROLLBUTTON_ID_LIST_DOWN 5 #define ED_NUM_SCROLLBUTTONS 6 #define ED_SCROLLBUTTON_ID_AREA_FIRST ED_SCROLLBUTTON_ID_AREA_UP #define ED_SCROLLBUTTON_ID_AREA_LAST ED_SCROLLBUTTON_ID_AREA_RIGHT /* values for scrollbar gadgets */ #define ED_SCROLLBAR_ID_AREA_HORIZONTAL 0 #define ED_SCROLLBAR_ID_AREA_VERTICAL 1 #define ED_SCROLLBAR_ID_LIST_VERTICAL 2 #define ED_NUM_SCROLLBARS 3 #define ED_SCROLLBAR_ID_AREA_FIRST ED_SCROLLBAR_ID_AREA_HORIZONTAL #define ED_SCROLLBAR_ID_AREA_LAST ED_SCROLLBAR_ID_AREA_VERTICAL /* values for text input gadgets */ #define ED_TEXTINPUT_ID_LEVEL_NAME 0 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR 1 #define ED_TEXTINPUT_ID_ELEMENT_NAME 2 #define ED_NUM_TEXTINPUT 3 #define ED_TEXTINPUT_ID_LEVEL_FIRST ED_TEXTINPUT_ID_LEVEL_NAME #define ED_TEXTINPUT_ID_LEVEL_LAST ED_TEXTINPUT_ID_LEVEL_AUTHOR /* values for text area gadgets */ #define ED_TEXTAREA_ID_ENVELOPE_INFO 0 #define ED_NUM_TEXTAREAS 1 #define ED_TEXTAREA_ID_LEVEL_FIRST ED_TEXTAREA_ID_ENVELOPE #define ED_TEXTAREA_ID_LEVEL_LAST ED_TEXTAREA_ID_ENVELOPE /* values for selectbox gadgets */ #define ED_SELECTBOX_ID_TIME_OR_STEPS 0 #define ED_SELECTBOX_ID_GAME_ENGINE_TYPE 1 #define ED_SELECTBOX_ID_WIND_DIRECTION 2 #define ED_SELECTBOX_ID_PLAYER_SPEED 3 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE 4 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER 5 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED 6 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION 7 #define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION 8 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN 9 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION 10 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE 11 #define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE 12 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS 13 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE 14 #define ED_SELECTBOX_ID_CUSTOM_DEADLINESS 15 #define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE 16 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS 17 #define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION 18 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION 19 #define ED_SELECTBOX_ID_CHANGE_SIDE 20 #define ED_SELECTBOX_ID_CHANGE_PLAYER 21 #define ED_SELECTBOX_ID_CHANGE_PAGE 22 #define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN 23 #define ED_SELECTBOX_ID_ACTION_TYPE 24 #define ED_SELECTBOX_ID_ACTION_MODE 25 #define ED_SELECTBOX_ID_ACTION_ARG 26 #define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE 27 #define ED_SELECTBOX_ID_GROUP_CHOICE_MODE 28 #define ED_NUM_SELECTBOX 29 #define ED_SELECTBOX_ID_LEVEL_FIRST ED_SELECTBOX_ID_TIME_OR_STEPS #define ED_SELECTBOX_ID_LEVEL_LAST ED_SELECTBOX_ID_WIND_DIRECTION #define ED_SELECTBOX_ID_CUSTOM1_FIRST ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE #define ED_SELECTBOX_ID_CUSTOM1_LAST ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION #define ED_SELECTBOX_ID_CUSTOM2_FIRST ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN #define ED_SELECTBOX_ID_CUSTOM2_LAST ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE #define ED_SELECTBOX_ID_CUSTOM_FIRST ED_SELECTBOX_ID_CUSTOM1_FIRST #define ED_SELECTBOX_ID_CUSTOM_LAST ED_SELECTBOX_ID_CUSTOM2_LAST #define ED_SELECTBOX_ID_CHANGE_FIRST ED_SELECTBOX_ID_CHANGE_TIME_UNITS #define ED_SELECTBOX_ID_CHANGE_LAST ED_SELECTBOX_ID_SELECT_CHANGE_PAGE /* values for textbutton gadgets */ #define ED_TEXTBUTTON_ID_LEVELINFO_LEVEL 0 #define ED_TEXTBUTTON_ID_LEVELINFO_EDITOR 1 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO 2 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG 3 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1 4 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2 5 #define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE 6 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE 7 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE 8 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE 9 #define ED_NUM_TEXTBUTTONS 10 #define ED_TEXTBUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL #define ED_TEXTBUTTON_ID_LEVELINFO_LAST ED_TEXTBUTTON_ID_LEVELINFO_EDITOR #define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO #define ED_TEXTBUTTON_ID_PROPERTIES_LAST ED_TEXTBUTTON_ID_PROPERTIES_CHANGE #define ED_TEXTBUTTON_ID_CHANGE_FIRST ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE #define ED_TEXTBUTTON_ID_CHANGE_LAST ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE /* values for graphicbutton gadgets */ #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE 0 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE 1 #define ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE 2 #define ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE 3 #define ED_NUM_GRAPHICBUTTONS 4 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE #define ED_GRAPHICBUTTON_ID_CHANGE_LAST ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE /* values for checkbutton gadgets */ #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED 0 #define ED_CHECKBUTTON_ID_STICK_ELEMENT 1 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS 2 #define ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE 3 #define ED_CHECKBUTTON_ID_USE_SPRING_BUG 4 #define ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG 5 #define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT 6 #define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE 7 #define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE 8 #define ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN 9 #define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING 10 #define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD 11 #define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD 12 #define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD 13 #define ED_CHECKBUTTON_ID_INSTANT_RELOCATION 14 #define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION 15 #define ED_CHECKBUTTON_ID_USE_START_ELEMENT 16 #define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT 17 #define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT 18 #define ED_CHECKBUTTON_ID_INITIAL_GRAVITY 19 #define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY 20 #define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 21 #define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID 22 #define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID 23 #define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH 24 #define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP 25 #define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED 26 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 27 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 28 #define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 29 #define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE 30 #define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE 31 #define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 32 #define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE 33 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 34 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 35 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 36 #define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 37 #define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 38 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE 39 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 40 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 41 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 42 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 43 #define ED_CHECKBUTTON_ID_CHANGE_DELAY 44 #define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 45 #define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 46 #define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 47 #define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 48 #define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 49 #define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 50 #define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION 51 #define ED_NUM_CHECKBUTTONS 52 #define ED_CHECKBUTTON_ID_EDITOR_FIRST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED #define ED_CHECKBUTTON_ID_EDITOR_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC #define ED_CHECKBUTTON_ID_CUSTOM1_LAST ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE #define ED_CHECKBUTTON_ID_CUSTOM2_LAST ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT #define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM1_FIRST #define ED_CHECKBUTTON_ID_CUSTOM_LAST ED_CHECKBUTTON_ID_CUSTOM2_LAST #define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE #define ED_CHECKBUTTON_ID_CHANGE_LAST ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION /* values for radiobutton gadgets */ #define ED_RADIOBUTTON_ID_PERCENTAGE 0 #define ED_RADIOBUTTON_ID_QUANTITY 1 #define ED_NUM_RADIOBUTTONS 2 #define ED_RADIOBUTTON_ID_EDITOR_FIRST ED_RADIOBUTTON_ID_PERCENTAGE #define ED_RADIOBUTTON_ID_EDITOR_LAST ED_RADIOBUTTON_ID_QUANTITY /* values for drawing area gadgets */ #define ED_DRAWING_ID_DRAWING_LEVEL 0 #define ED_DRAWING_ID_YAMYAM_CONTENT_0 1 #define ED_DRAWING_ID_YAMYAM_CONTENT_1 2 #define ED_DRAWING_ID_YAMYAM_CONTENT_2 3 #define ED_DRAWING_ID_YAMYAM_CONTENT_3 4 #define ED_DRAWING_ID_YAMYAM_CONTENT_4 5 #define ED_DRAWING_ID_YAMYAM_CONTENT_5 6 #define ED_DRAWING_ID_YAMYAM_CONTENT_6 7 #define ED_DRAWING_ID_YAMYAM_CONTENT_7 8 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 9 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_1 10 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_2 11 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_3 12 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_4 13 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_5 14 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_6 15 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_7 16 #define ED_DRAWING_ID_ANDROID_CONTENT 17 #define ED_DRAWING_ID_AMOEBA_CONTENT 18 #define ED_DRAWING_ID_START_ELEMENT 19 #define ED_DRAWING_ID_ARTWORK_ELEMENT 20 #define ED_DRAWING_ID_EXPLOSION_ELEMENT 21 #define ED_DRAWING_ID_INVENTORY_CONTENT 22 #define ED_DRAWING_ID_CUSTOM_GRAPHIC 23 #define ED_DRAWING_ID_CUSTOM_CONTENT 24 #define ED_DRAWING_ID_CUSTOM_MOVE_ENTER 25 #define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE 26 #define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET 27 #define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT 28 #define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER 29 #define ED_DRAWING_ID_CUSTOM_CHANGE_ACTION 30 #define ED_DRAWING_ID_GROUP_CONTENT 31 #define ED_DRAWING_ID_RANDOM_BACKGROUND 32 #define ED_NUM_DRAWING_AREAS 33 /* ----------------------------------------------------------------------------- some internally used definitions ----------------------------------------------------------------------------- */ /* values for CopyLevelToUndoBuffer() */ #define UNDO_IMMEDIATE 0 #define UNDO_ACCUMULATE 1 /* values for scrollbars */ #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 /* sub-screens in the global settings section */ #define ED_MODE_LEVELINFO_LEVEL ED_TEXTBUTTON_ID_LEVELINFO_LEVEL #define ED_MODE_LEVELINFO_EDITOR ED_TEXTBUTTON_ID_LEVELINFO_EDITOR /* sub-screens in the element properties section */ #define ED_MODE_PROPERTIES_INFO ED_TEXTBUTTON_ID_PROPERTIES_INFO #define ED_MODE_PROPERTIES_CONFIG ED_TEXTBUTTON_ID_PROPERTIES_CONFIG #define ED_MODE_PROPERTIES_CONFIG_1 ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1 #define ED_MODE_PROPERTIES_CONFIG_2 ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2 #define ED_MODE_PROPERTIES_CHANGE ED_TEXTBUTTON_ID_PROPERTIES_CHANGE /* how many steps can be cancelled */ #define NUM_UNDO_STEPS (10 + 1) /* values for elements with score for certain actions */ #define MIN_SCORE 0 #define MAX_SCORE 999 /* values for elements with count for collecting */ #define MIN_COLLECT_COUNT 0 #define MAX_COLLECT_COUNT 999 /* values for random placement */ #define RANDOM_USE_PERCENTAGE 0 #define RANDOM_USE_QUANTITY 1 /* maximal size of level editor drawing area */ #define MAX_ED_FIELDX (2 * SCR_FIELDX) #define MAX_ED_FIELDY (2 * SCR_FIELDY - 1) /* ----------------------------------------------------------------------------- some internally used data structure definitions ----------------------------------------------------------------------------- */ static struct { char shortcut; char *text; } control_info[ED_NUM_CTRL_BUTTONS] = { /* note: some additional characters are already reserved for "cheat mode" shortcuts (":XYZ" style) -- for details, see "events.c" */ { 's', "draw single items" }, { 'd', "draw connected items" }, { 'l', "draw lines" }, { 'a', "draw arcs" }, { 'r', "draw outline rectangles" }, { 'R', "draw filled rectangles" }, { '\0', "wrap (rotate) level up" }, { 't', "enter text elements" }, { 'f', "flood fill" }, { '\0', "wrap (rotate) level left" }, { '?', "properties of drawing element" }, { '\0', "wrap (rotate) level right" }, { '\0', "random element placement" }, { 'b', "grab brush" }, { '\0', "wrap (rotate) level down" }, { ',', "pick drawing element" }, { 'U', "undo last operation" }, { 'I', "properties of level" }, { 'S', "save level" }, { 'C', "clear level" }, { 'T', "test level" }, { 'E', "exit level editor" }, { '\0', "copy settings from other element" }, { '\0', "copy settings to other element" }, { '\0', "exchange element with other element" }, { '\0', "copy settings from this element" }, { '\0', "paste settings to this element" }, }; static int random_placement_value = 10; static int random_placement_method = RANDOM_USE_QUANTITY; static int random_placement_background_element = EL_SAND; static boolean random_placement_background_restricted = FALSE; static boolean stick_element_properties_window = FALSE; static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES]; static boolean custom_element_change_events[NUM_CHANGE_EVENTS]; static struct ElementChangeInfo custom_element_change; static struct ElementGroupInfo group_element_info; static struct ElementInfo custom_element; static struct { int x, y; int min_value, max_value; int gadget_id_down, gadget_id_up; int gadget_id_text; int gadget_id_align; int *value; char *text_above, *text_left, *text_right; } counterbutton_info[ED_NUM_COUNTERBUTTONS] = { /* ---------- current level number --------------------------------------- */ { #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else DX + 5 - SX, DY + 3 - SY, #endif 1, 100, GADGET_ID_SELECT_LEVEL_DOWN, GADGET_ID_SELECT_LEVEL_UP, GADGET_ID_SELECT_LEVEL_TEXT, GADGET_ID_NONE, &level_nr, NULL, NULL, NULL }, /* ---------- level and editor settings ---------------------------------- */ { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(4), MIN_LEV_FIELDX, MAX_LEV_FIELDX, GADGET_ID_LEVEL_XSIZE_DOWN, GADGET_ID_LEVEL_XSIZE_UP, GADGET_ID_LEVEL_XSIZE_TEXT, GADGET_ID_NONE, &level.fieldx, "playfield size:", NULL, "width", }, { -1, ED_LEVEL_SETTINGS_YPOS(4), MIN_LEV_FIELDY, MAX_LEV_FIELDY, GADGET_ID_LEVEL_YSIZE_DOWN, GADGET_ID_LEVEL_YSIZE_UP, GADGET_ID_LEVEL_YSIZE_TEXT, GADGET_ID_LEVEL_XSIZE_UP, &level.fieldy, NULL, " ", "height", }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(5), 0, 999, GADGET_ID_LEVEL_GEMSLIMIT_DOWN, GADGET_ID_LEVEL_GEMSLIMIT_UP, GADGET_ID_LEVEL_GEMSLIMIT_TEXT, GADGET_ID_NONE, &level.gems_needed, NULL, "number of gems to collect:", NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(7), 0, 9999, GADGET_ID_LEVEL_TIMELIMIT_DOWN, GADGET_ID_LEVEL_TIMELIMIT_UP, GADGET_ID_LEVEL_TIMELIMIT_TEXT, GADGET_ID_NONE, &level.time, "time or step limit to solve level:", NULL, NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(9), 0, 999, GADGET_ID_LEVEL_TIMESCORE_DOWN, GADGET_ID_LEVEL_TIMESCORE_UP, GADGET_ID_LEVEL_TIMESCORE_TEXT, GADGET_ID_NONE, &level.score[SC_TIME_BONUS], "score for each second/step left:", NULL, NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(12), 0, 9999, GADGET_ID_LEVEL_RANDOM_SEED_DOWN, GADGET_ID_LEVEL_RANDOM_SEED_UP, GADGET_ID_LEVEL_RANDOM_SEED_TEXT, GADGET_ID_NONE, &level.random_seed, NULL, "random seed:", "(0 => random)" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(0), 1, 100, GADGET_ID_LEVEL_RANDOM_DOWN, GADGET_ID_LEVEL_RANDOM_UP, GADGET_ID_LEVEL_RANDOM_TEXT, GADGET_ID_NONE, &random_placement_value, "random element placement:", NULL, "in" }, /* ---------- element settings: configure (various elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE1_DOWN, GADGET_ID_ELEMENT_VALUE1_UP, GADGET_ID_ELEMENT_VALUE1_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE2_DOWN, GADGET_ID_ELEMENT_VALUE2_UP, GADGET_ID_ELEMENT_VALUE2_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE3_DOWN, GADGET_ID_ELEMENT_VALUE3_UP, GADGET_ID_ELEMENT_VALUE3_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE4_DOWN, GADGET_ID_ELEMENT_VALUE4_UP, GADGET_ID_ELEMENT_VALUE4_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), MIN_ELEMENT_CONTENTS, MAX_ELEMENT_CONTENTS, GADGET_ID_YAMYAM_CONTENT_DOWN, GADGET_ID_YAMYAM_CONTENT_UP, GADGET_ID_YAMYAM_CONTENT_TEXT, GADGET_ID_NONE, &level.num_yamyam_contents, NULL, NULL, "number of content areas" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), MIN_ELEMENT_CONTENTS, MAX_ELEMENT_CONTENTS, GADGET_ID_BALL_CONTENT_DOWN, GADGET_ID_BALL_CONTENT_UP, GADGET_ID_BALL_CONTENT_TEXT, GADGET_ID_NONE, &level.num_ball_contents, NULL, NULL, "number of content areas" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), MIN_ANDROID_ELEMENTS, MAX_ANDROID_ELEMENTS, GADGET_ID_ANDROID_CONTENT_DOWN, GADGET_ID_ANDROID_CONTENT_UP, GADGET_ID_ANDROID_CONTENT_TEXT, GADGET_ID_NONE, &level.num_android_clone_elements, NULL, NULL, "number of clonable elements" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), MIN_ENVELOPE_XSIZE, MAX_ENVELOPE_XSIZE, GADGET_ID_ENVELOPE_XSIZE_DOWN, GADGET_ID_ENVELOPE_XSIZE_UP, GADGET_ID_ENVELOPE_XSIZE_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, "width", }, { -1, ED_ELEMENT_SETTINGS_YPOS(0), MIN_ENVELOPE_YSIZE, MAX_ENVELOPE_YSIZE, GADGET_ID_ENVELOPE_YSIZE_DOWN, GADGET_ID_ENVELOPE_YSIZE_UP, GADGET_ID_ENVELOPE_YSIZE_TEXT, GADGET_ID_ENVELOPE_XSIZE_UP, NULL, /* will be set when used */ NULL, " ", "height", }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), MIN_INITIAL_INVENTORY_SIZE, MAX_INITIAL_INVENTORY_SIZE, GADGET_ID_INVENTORY_SIZE_DOWN, GADGET_ID_INVENTORY_SIZE_UP, GADGET_ID_INVENTORY_SIZE_TEXT, GADGET_ID_NONE, &level.initial_inventory_size[0], NULL, NULL, "number of inventory elements" }, /* ---------- element settings: configure 1 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(6), MIN_SCORE, MAX_SCORE, GADGET_ID_CUSTOM_SCORE_DOWN, GADGET_ID_CUSTOM_SCORE_UP, GADGET_ID_CUSTOM_SCORE_TEXT, GADGET_ID_NONE, &custom_element.collect_score_initial, NULL, "CE score", " " }, { -1, ED_ELEMENT_SETTINGS_YPOS(6), MIN_COLLECT_COUNT, MAX_COLLECT_COUNT, GADGET_ID_CUSTOM_GEMCOUNT_DOWN, GADGET_ID_CUSTOM_GEMCOUNT_UP, GADGET_ID_CUSTOM_GEMCOUNT_TEXT, GADGET_ID_CUSTOM_SCORE_UP, &custom_element.collect_count_initial, NULL, "CE count", NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(12), 0, 9999, GADGET_ID_CUSTOM_VALUE_FIX_DOWN, GADGET_ID_CUSTOM_VALUE_FIX_UP, GADGET_ID_CUSTOM_VALUE_FIX_TEXT, GADGET_ID_NONE, &custom_element.ce_value_fixed_initial, NULL, "CE value", NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(12), 0, 9999, GADGET_ID_CUSTOM_VALUE_RND_DOWN, GADGET_ID_CUSTOM_VALUE_RND_UP, GADGET_ID_CUSTOM_VALUE_RND_TEXT, GADGET_ID_CUSTOM_VALUE_FIX_UP, &custom_element.ce_value_random_initial, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(7), 0, 999, GADGET_ID_PUSH_DELAY_FIX_DOWN, GADGET_ID_PUSH_DELAY_FIX_UP, GADGET_ID_PUSH_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.push_delay_fixed, NULL, "push delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), 0, 999, GADGET_ID_PUSH_DELAY_RND_DOWN, GADGET_ID_PUSH_DELAY_RND_UP, GADGET_ID_PUSH_DELAY_RND_TEXT, GADGET_ID_PUSH_DELAY_FIX_UP, &custom_element.push_delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8), 0, 999, GADGET_ID_DROP_DELAY_FIX_DOWN, GADGET_ID_DROP_DELAY_FIX_UP, GADGET_ID_DROP_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.drop_delay_fixed, NULL, "drop delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(8), 0, 999, GADGET_ID_DROP_DELAY_RND_DOWN, GADGET_ID_DROP_DELAY_RND_UP, GADGET_ID_DROP_DELAY_RND_TEXT, GADGET_ID_DROP_DELAY_FIX_UP, &custom_element.drop_delay_random, NULL, "+random", NULL }, /* ---------- element settings: configure 2 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), 0, 999, GADGET_ID_MOVE_DELAY_FIX_DOWN, GADGET_ID_MOVE_DELAY_FIX_UP, GADGET_ID_MOVE_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.move_delay_fixed, NULL, "move delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(5), 0, 999, GADGET_ID_MOVE_DELAY_RND_DOWN, GADGET_ID_MOVE_DELAY_RND_UP, GADGET_ID_MOVE_DELAY_RND_TEXT, GADGET_ID_MOVE_DELAY_FIX_UP, &custom_element.move_delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(12), 0, 999, GADGET_ID_EXPLOSION_DELAY_DOWN, GADGET_ID_EXPLOSION_DELAY_UP, GADGET_ID_EXPLOSION_DELAY_TEXT, GADGET_ID_NONE, &custom_element.explosion_delay, NULL, "explosion delay", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13), 0, 999, GADGET_ID_IGNITION_DELAY_DOWN, GADGET_ID_IGNITION_DELAY_UP, GADGET_ID_IGNITION_DELAY_TEXT, GADGET_ID_NONE, &custom_element.ignition_delay, NULL, "ignition delay", "(by fire)" }, /* ---------- element settings: configure (group elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(5), MIN_ELEMENTS_IN_GROUP, MAX_ELEMENTS_IN_GROUP, GADGET_ID_GROUP_CONTENT_DOWN, GADGET_ID_GROUP_CONTENT_UP, GADGET_ID_GROUP_CONTENT_TEXT, GADGET_ID_NONE, &group_element_info.num_elements, NULL, NULL, "number of elements in group" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(2), 0, 999, GADGET_ID_CHANGE_DELAY_FIX_DOWN, GADGET_ID_CHANGE_DELAY_FIX_UP, GADGET_ID_CHANGE_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element_change.delay_fixed, NULL, "CE delay", NULL, }, { -1, ED_ELEMENT_SETTINGS_YPOS(2), 0, 999, GADGET_ID_CHANGE_DELAY_RND_DOWN, GADGET_ID_CHANGE_DELAY_RND_UP, GADGET_ID_CHANGE_DELAY_RND_TEXT, GADGET_ID_CHANGE_DELAY_FIX_UP, &custom_element_change.delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(3), ED_ELEMENT_SETTINGS_YPOS(12), 0, 100, GADGET_ID_CHANGE_CONT_RND_DOWN, GADGET_ID_CHANGE_CONT_RND_UP, GADGET_ID_CHANGE_CONT_RND_TEXT, GADGET_ID_NONE, &custom_element_change.random_percentage, NULL, "use random replace:", "%" }, }; static struct { int x, y; int gadget_id; int size; char *value; char *text_above, *infotext; } textinput_info[ED_NUM_TEXTINPUT] = { { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_LEVEL_NAME, MAX_LEVEL_NAME_LEN, level.name, "Title:", "Title" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(2), GADGET_ID_LEVEL_AUTHOR, MAX_LEVEL_AUTHOR_LEN, level.author, "Author:", "Author" }, { 5 * MINI_TILEX - 2, 5 * MINI_TILEY - ED_BORDER_SIZE + 1, GADGET_ID_ELEMENT_NAME, MAX_ELEMENT_NAME_LEN - 2, /* currently 2 chars less editable */ custom_element.description, NULL, "Element name" } }; static struct { int x, y; int gadget_id; int xsize, ysize; char *value; char *text_above, *infotext; } textarea_info[ED_NUM_TEXTAREAS] = { { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_ENVELOPE_INFO, MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE, NULL, "Envelope Content:", "Envelope Content" } }; static struct ValueTextInfo options_time_or_steps[] = { { 0, "seconds" }, { 1, "steps" }, { -1, NULL } }; static struct ValueTextInfo options_game_engine_type[] = { { GAME_ENGINE_TYPE_RND, "Rocks'n'Diamonds" }, { GAME_ENGINE_TYPE_EM, "Emerald Mine" }, { GAME_ENGINE_TYPE_SP, "Supaplex" }, { -1, NULL } }; static struct ValueTextInfo options_wind_direction[] = { { MV_START_NONE, "none" }, { MV_START_LEFT, "left" }, { MV_START_RIGHT, "right" }, { MV_START_UP, "up" }, { MV_START_DOWN, "down" }, { -1, NULL } }; static struct ValueTextInfo options_player_speed[] = { { 0, "frozen" }, { 1, "very slow" }, { 2, "slow" }, { 4, "normal" }, { 8, "fast" }, { 16, "very fast" }, { 32, "ultrafast" }, { -1, NULL } }; static struct ValueTextInfo options_access_type[] = { { EP_WALKABLE, "walkable" }, { EP_PASSABLE, "passable" }, { -1, NULL } }; static struct ValueTextInfo options_access_layer[] = { { EP_ACCESSIBLE_OVER, "over" }, { EP_ACCESSIBLE_INSIDE, "inside" }, { EP_ACCESSIBLE_UNDER, "under" }, { -1, NULL } }; static struct ValueTextInfo options_access_protected[] = { { 0, "unprotected" }, { 1, "protected" }, { -1, NULL } }; static struct ValueTextInfo options_access_direction[] = { { MV_NO_DIRECTION, "no direction" }, { MV_LEFT, "left" }, { MV_RIGHT, "right" }, { MV_UP, "up" }, { MV_DOWN, "down" }, { MV_LEFT | MV_UP, "left + up" }, { MV_LEFT | MV_DOWN, "left + down" }, { MV_RIGHT | MV_UP, "right + up" }, { MV_RIGHT | MV_DOWN, "right + down" }, { MV_HORIZONTAL, "horizontal" }, { MV_VERTICAL, "vertical" }, { MV_HORIZONTAL | MV_UP, "horizontal + up" }, { MV_HORIZONTAL | MV_DOWN, "horizontal + down" }, { MV_VERTICAL | MV_LEFT, "vertical + left" }, { MV_VERTICAL | MV_RIGHT, "vertical + right" }, { MV_ALL_DIRECTIONS, "all directions" }, { -1, NULL } }; static struct ValueTextInfo options_walk_to_action[] = { { EP_DIGGABLE, "diggable" }, { EP_COLLECTIBLE_ONLY, "collectible" }, { EP_DROPPABLE, "collectible & droppable" }, { EP_THROWABLE, "collectible & throwable" }, { EP_PUSHABLE, "pushable" }, { -1, NULL } }; static struct ValueTextInfo options_move_pattern[] = { { MV_LEFT, "left" }, { MV_RIGHT, "right" }, { MV_UP, "up" }, { MV_DOWN, "down" }, { MV_HORIZONTAL, "horizontal" }, { MV_VERTICAL, "vertical" }, { MV_ALL_DIRECTIONS, "all directions" }, { MV_WIND_DIRECTION, "wind direction" }, { MV_TOWARDS_PLAYER, "towards player" }, { MV_AWAY_FROM_PLAYER, "away from player" }, { MV_ALONG_LEFT_SIDE, "along left side" }, { MV_ALONG_RIGHT_SIDE, "along right side" }, { MV_TURNING_LEFT, "turning left" }, { MV_TURNING_RIGHT, "turning right" }, { MV_TURNING_LEFT_RIGHT, "turning left, right" }, { MV_TURNING_RIGHT_LEFT, "turning right, left" }, { MV_TURNING_RANDOM, "turning random" }, { MV_MAZE_RUNNER, "maze runner style" }, { MV_MAZE_HUNTER, "maze hunter style" }, { MV_WHEN_PUSHED, "when pushed" }, { MV_WHEN_DROPPED, "when dropped/thrown" }, { -1, NULL } }; static struct ValueTextInfo options_move_direction[] = { { MV_START_AUTOMATIC, "automatic" }, { MV_START_LEFT, "left" }, { MV_START_RIGHT, "right" }, { MV_START_UP, "up" }, { MV_START_DOWN, "down" }, { MV_START_RANDOM, "random" }, { MV_START_PREVIOUS, "previous" }, { -1, NULL } }; static struct ValueTextInfo options_move_stepsize[] = { { 0, "not moving" }, { 1, "very slow" }, { 2, "slow" }, { 4, "normal" }, { 8, "fast" }, { 16, "very fast" }, { 32, "even faster" }, { -1, NULL } }; static struct ValueTextInfo options_move_leave_type[] = { { LEAVE_TYPE_UNLIMITED, "leave behind" }, { LEAVE_TYPE_LIMITED, "change it to" }, { -1, NULL } }; static struct ValueTextInfo options_smash_targets[] = { { EP_CAN_SMASH_PLAYER, "player" }, #if 0 { EP_CAN_SMASH_ENEMIES, "enemies" }, #endif { EP_CAN_SMASH_EVERYTHING, "everything" }, { -1, NULL } }; static struct ValueTextInfo options_slippery_type[] = { { SLIPPERY_ANY_RANDOM, "random" }, { SLIPPERY_ANY_LEFT_RIGHT, "left, right" }, { SLIPPERY_ANY_RIGHT_LEFT, "right, left" }, { SLIPPERY_ONLY_LEFT, "only left" }, { SLIPPERY_ONLY_RIGHT, "only right" }, { -1, NULL } }; static struct ValueTextInfo options_deadliness[] = { { EP_DONT_RUN_INTO, "running into" }, { EP_DONT_COLLIDE_WITH, "colliding with" }, { EP_DONT_GET_HIT_BY, "getting hit by" }, { EP_DONT_TOUCH, "touching" }, { -1, NULL } }; static struct ValueTextInfo options_explosion_type[] = { { EXPLODES_3X3, "3x3" }, { EXPLODES_CROSS, "3+3" }, { EXPLODES_1X1, "1x1" }, { -1, NULL } }; static struct ValueTextInfo options_time_units[] = { { 1, "frames" }, { FRAMES_PER_SECOND, "seconds" }, { -1, NULL } }; static struct ValueTextInfo options_change_direct_action[] = { { CE_TOUCHED_BY_PLAYER, "touched by player" }, { CE_PRESSED_BY_PLAYER, "pressed by player" }, { CE_SWITCHED_BY_PLAYER, "switched by player" }, { CE_SNAPPED_BY_PLAYER, "snapped by player" }, { CE_PUSHED_BY_PLAYER, "pushed by player" }, { CE_ENTERED_BY_PLAYER, "entered by player" }, { CE_LEFT_BY_PLAYER, "left by player" }, { CE_DROPPED_BY_PLAYER, "dropped/thrown by player" }, { CE_SWITCHED, "switched" }, { CE_HITTING_SOMETHING, "hitting something" }, { CE_HIT_BY_SOMETHING, "hit by something" }, #if 0 { CE_BLOCKED, "blocked" }, #endif { CE_IMPACT, "impact (on something)" }, { CE_SMASHED, "smashed (from above)" }, #if 0 { CE_VALUE_CHANGES, "CE value changes" }, { CE_SCORE_CHANGES, "CE score changes" }, #endif { CE_VALUE_GETS_ZERO, "CE value gets 0" }, { CE_SCORE_GETS_ZERO, "CE score gets 0" }, { -1, NULL } }; static struct ValueTextInfo options_change_other_action[] = { { CE_PLAYER_TOUCHES_X, "player touches" }, { CE_PLAYER_PRESSES_X, "player presses" }, { CE_PLAYER_SWITCHES_X, "player switches" }, { CE_PLAYER_SNAPS_X, "player snaps" }, { CE_PLAYER_PUSHES_X, "player pushes" }, { CE_PLAYER_ENTERS_X, "player enters" }, { CE_PLAYER_LEAVES_X, "player leaves" }, { CE_PLAYER_DIGS_X, "player digs" }, { CE_PLAYER_COLLECTS_X, "player collects" }, { CE_PLAYER_DROPS_X, "player drops/throws" }, { CE_TOUCHING_X, "touching" }, { CE_HITTING_X, "hitting" }, { CE_DIGGING_X, "digging" }, { CE_HIT_BY_X, "hit by" }, { CE_SWITCH_OF_X, "switch of" }, { CE_CHANGE_OF_X, "change by page of" }, { CE_EXPLOSION_OF_X, "explosion of" }, { CE_MOVE_OF_X, "move of" }, { CE_CREATION_OF_X, "creation of" }, { CE_VALUE_CHANGES_OF_X, "CE value changes of" }, { CE_SCORE_CHANGES_OF_X, "CE score changes of" }, { CE_VALUE_GETS_ZERO_OF_X, "CE value gets 0 of" }, { CE_SCORE_GETS_ZERO_OF_X, "CE score gets 0 of" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_side[] = { { CH_SIDE_LEFT, "left" }, { CH_SIDE_RIGHT, "right" }, { CH_SIDE_TOP, "top" }, { CH_SIDE_BOTTOM, "bottom" }, { CH_SIDE_LEFT_RIGHT, "left/right" }, { CH_SIDE_TOP_BOTTOM, "top/bottom" }, { CH_SIDE_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_player[] = { { CH_PLAYER_1, "1" }, { CH_PLAYER_2, "2" }, { CH_PLAYER_3, "3" }, { CH_PLAYER_4, "4" }, { CH_PLAYER_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_page[] = { { (1 << 0), "1" }, { (1 << 1), "2" }, { (1 << 2), "3" }, { (1 << 3), "4" }, { (1 << 4), "5" }, { (1 << 5), "6" }, { (1 << 6), "7" }, { (1 << 7), "8" }, { (1 << 8), "9" }, { (1 << 9), "10" }, { (1 << 10), "11" }, { (1 << 11), "12" }, { (1 << 12), "13" }, { (1 << 13), "14" }, { (1 << 14), "15" }, { (1 << 15), "16" }, { (1 << 16), "17" }, { (1 << 17), "18" }, { (1 << 18), "19" }, { (1 << 19), "20" }, { (1 << 20), "21" }, { (1 << 21), "22" }, { (1 << 22), "23" }, { (1 << 23), "24" }, { (1 << 24), "25" }, { (1 << 25), "26" }, { (1 << 26), "27" }, { (1 << 27), "28" }, { (1 << 28), "29" }, { (1 << 29), "30" }, { (1 << 30), "31" }, { (1 << 31), "32" }, { CH_PAGE_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_replace_when[] = { { CP_WHEN_EMPTY, "empty" }, { CP_WHEN_WALKABLE, "walkable" }, { CP_WHEN_DIGGABLE, "diggable" }, { CP_WHEN_COLLECTIBLE, "collectible" }, { CP_WHEN_REMOVABLE, "removable" }, { CP_WHEN_DESTRUCTIBLE, "destructible" }, { -1, NULL } }; static struct ValueTextInfo options_action_type[] = { { CA_NO_ACTION, "no action" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_LEVEL_ACTIONS, "[level]" }, { CA_RESTART_LEVEL, "restart level" }, { CA_SHOW_ENVELOPE, "show envelope" }, { CA_SET_LEVEL_TIME, "set time" }, { CA_SET_LEVEL_SCORE, "set score" }, { CA_SET_LEVEL_GEMS, "set gems" }, { CA_SET_LEVEL_WIND, "set wind dir." }, { CA_SET_LEVEL_RANDOM_SEED, "set rand. seed" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_PLAYER_ACTIONS, "[player]" }, { CA_MOVE_PLAYER, "move player" }, { CA_EXIT_PLAYER, "exit player" }, { CA_KILL_PLAYER, "kill player" }, { CA_SET_PLAYER_KEYS, "set keys" }, { CA_SET_PLAYER_SPEED, "set speed" }, { CA_SET_PLAYER_SHIELD, "set shield" }, { CA_SET_PLAYER_GRAVITY, "set gravity" }, { CA_SET_PLAYER_ARTWORK, "set artwork" }, { CA_SET_PLAYER_INVENTORY, "set inventory" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_CE_ACTIONS, "[CE]" }, { CA_SET_CE_VALUE, "set CE value" }, { CA_SET_CE_SCORE, "set CE score" }, { CA_SET_CE_ARTWORK, "set CE artwork" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_ENGINE_ACTIONS, "[engine]" }, { CA_SET_ENGINE_SCAN_MODE, "set scan mode" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_none[] = { { CA_MODE_UNDEFINED, " " }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_assign[] = { { CA_MODE_SET, "=" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_add_remove[] = { { CA_MODE_ADD, "+" }, { CA_MODE_SUBTRACT, "-" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_calculate[] = { { CA_MODE_SET, "=" }, { CA_MODE_ADD, "+" }, { CA_MODE_SUBTRACT, "-" }, { CA_MODE_MULTIPLY, "*" }, { CA_MODE_DIVIDE, "/" }, { CA_MODE_MODULO, "%" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_none[] = { { CA_ARG_UNDEFINED, " " }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_player[] = { { CA_ARG_PLAYER_HEADLINE, "[player]" }, { CA_ARG_PLAYER_1, "1" }, { CA_ARG_PLAYER_2, "2" }, { CA_ARG_PLAYER_3, "3" }, { CA_ARG_PLAYER_4, "4" }, { CA_ARG_PLAYER_ANY, "any" }, { CA_ARG_PLAYER_TRIGGER, "trigger" }, { CA_ARG_PLAYER_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_number[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_0, "0" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_10, "10" }, { CA_ARG_100, "100" }, { CA_ARG_1000, "1000" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_MIN, "min" }, { CA_ARG_NUMBER_MAX, "max" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_RESET, "reset" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_CE_VALUE, "CE value" }, { CA_ARG_NUMBER_CE_SCORE, "CE score" }, { CA_ARG_NUMBER_CE_DELAY, "CE delay" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_LEVEL_TIME, "time" }, { CA_ARG_NUMBER_LEVEL_GEMS, "gems" }, { CA_ARG_NUMBER_LEVEL_SCORE, "score" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]" }, { CA_ARG_ELEMENT_CV_TARGET, "target" }, { CA_ARG_ELEMENT_CV_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CV_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]" }, { CA_ARG_ELEMENT_CS_TARGET, "target" }, { CA_ARG_ELEMENT_CS_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CS_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_value[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_0, "0" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_10, "10" }, { CA_ARG_100, "100" }, { CA_ARG_1000, "1000" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_MIN, "min" }, { CA_ARG_NUMBER_MAX, "max" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_RESET, "reset" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_CE_VALUE, "CE value" }, { CA_ARG_NUMBER_CE_SCORE, "CE score" }, { CA_ARG_NUMBER_CE_DELAY, "CE delay" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_LEVEL_TIME, "time" }, { CA_ARG_NUMBER_LEVEL_GEMS, "gems" }, { CA_ARG_NUMBER_LEVEL_SCORE, "score" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]" }, { CA_ARG_ELEMENT_CV_TARGET, "target" }, { CA_ARG_ELEMENT_CV_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CV_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]" }, { CA_ARG_ELEMENT_CS_TARGET, "target" }, { CA_ARG_ELEMENT_CS_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CS_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_NR_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_NR_TARGET, "target" }, { CA_ARG_ELEMENT_NR_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_NR_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_envelope[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_key[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_6, "6" }, { CA_ARG_7, "7" }, { CA_ARG_8, "8" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_speed[] = { { CA_ARG_SPEED_HEADLINE, "[speed]" }, { CA_ARG_SPEED_NOT_MOVING, "frozen" }, { CA_ARG_SPEED_VERY_SLOW, "very slow" }, { CA_ARG_SPEED_SLOW, "slow" }, { CA_ARG_SPEED_NORMAL, "normal" }, { CA_ARG_SPEED_FAST, "fast" }, { CA_ARG_SPEED_VERY_FAST, "very fast" }, { CA_ARG_SPEED_EVEN_FASTER, "ultrafast" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_SPEED_SLOWER, "slower" }, { CA_ARG_SPEED_FASTER, "faster" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_SPEED_RESET, "reset" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_shield[] = { { CA_ARG_SHIELD_HEADLINE, "[shield]" }, { CA_ARG_SHIELD_OFF, "off" }, { CA_ARG_SHIELD_NORMAL, "normal" }, { CA_ARG_SHIELD_DEADLY, "deadly" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_artwork[] = { { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_RESET, "reset" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_gravity[] = { { CA_ARG_GRAVITY_HEADLINE, "[gravity]" }, { CA_ARG_GRAVITY_ON, "on" }, { CA_ARG_GRAVITY_OFF, "off" }, { CA_ARG_GRAVITY_TOGGLE, "toggle" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_direction[] = { { CA_ARG_DIRECTION_HEADLINE, "[dir.]" }, { CA_ARG_DIRECTION_NONE, "none" }, { CA_ARG_DIRECTION_LEFT, "left" }, { CA_ARG_DIRECTION_RIGHT, "right" }, { CA_ARG_DIRECTION_UP, "up" }, { CA_ARG_DIRECTION_DOWN, "down" }, { CA_ARG_DIRECTION_TRIGGER, "trigger" }, { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_scan_mode[] = { { CA_ARG_SCAN_MODE_HEADLINE, "[mode]" }, { CA_ARG_SCAN_MODE_NORMAL, "normal" }, { CA_ARG_SCAN_MODE_REVERSE, "reverse" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_inventory[] = { { CA_ARG_INVENTORY_HEADLINE, "[add]" }, { CA_ARG_ELEMENT_TARGET, "+ target" }, { CA_ARG_ELEMENT_TRIGGER, "+ trigger" }, { CA_ARG_ELEMENT_ACTION, "+ action" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]" }, { CA_ARG_INVENTORY_RM_TARGET, "- target" }, { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger" }, { CA_ARG_INVENTORY_RM_ACTION, "- action" }, { CA_ARG_INVENTORY_RM_FIRST, "- first" }, { CA_ARG_INVENTORY_RM_LAST, "- last" }, { CA_ARG_INVENTORY_RM_ALL, "- all" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_INVENTORY_RESET, "reset" }, { -1, NULL } }; static char options_change_page_strings[MAX_CHANGE_PAGES][10]; static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] = { { -1, NULL } }; static struct ValueTextInfo options_group_choice_mode[] = { { ANIM_RANDOM, "random" }, { ANIM_LOOP, "loop" }, { ANIM_LINEAR, "linear" }, { ANIM_PINGPONG, "pingpong" }, { ANIM_PINGPONG2, "pingpong 2" }, { -1, NULL } }; static struct ValueTextInfo *action_arg_modes[] = { options_action_mode_none, options_action_mode_assign, options_action_mode_add_remove, options_action_mode_calculate, }; static struct { int value; int mode; struct ValueTextInfo *options; } action_arg_options[] = { { CA_NO_ACTION, 0, options_action_arg_none, }, { CA_EXIT_PLAYER, 0, options_action_arg_player, }, { CA_KILL_PLAYER, 0, options_action_arg_player, }, { CA_MOVE_PLAYER, 0, options_action_arg_direction, }, { CA_RESTART_LEVEL, 0, options_action_arg_none, }, { CA_SHOW_ENVELOPE, 0, options_action_arg_envelope, }, { CA_SET_LEVEL_TIME, 3, options_action_arg_number, }, { CA_SET_LEVEL_GEMS, 3, options_action_arg_number, }, { CA_SET_LEVEL_SCORE, 3, options_action_arg_number, }, { CA_SET_LEVEL_WIND, 1, options_action_arg_direction, }, { CA_SET_LEVEL_RANDOM_SEED, 1, options_action_arg_number, }, { CA_SET_PLAYER_KEYS, 2, options_action_arg_key, }, { CA_SET_PLAYER_SPEED, 1, options_action_arg_speed, }, { CA_SET_PLAYER_SHIELD, 1, options_action_arg_shield, }, { CA_SET_PLAYER_GRAVITY, 1, options_action_arg_gravity, }, { CA_SET_PLAYER_ARTWORK, 1, options_action_arg_artwork, }, { CA_SET_PLAYER_INVENTORY, 0, options_action_arg_inventory, }, { CA_SET_CE_VALUE, 3, options_action_arg_value, }, { CA_SET_CE_SCORE, 3, options_action_arg_value, }, { CA_SET_CE_ARTWORK, 1, options_action_arg_artwork, }, { CA_SET_ENGINE_SCAN_MODE, 1, options_action_arg_scan_mode, }, { -1, FALSE, NULL } }; static struct { int x, y; int gadget_id; int gadget_id_align; int size; /* char size of selectbox or '-1' (dynamically determined) */ struct ValueTextInfo *options; int *value; char *text_left, *text_right, *infotext; } selectbox_info[ED_NUM_SELECTBOX] = { /* ---------- level and editor settings ---------------------------------- */ { -1, ED_LEVEL_SETTINGS_YPOS(7), GADGET_ID_TIME_OR_STEPS, GADGET_ID_LEVEL_TIMELIMIT_UP, -1, options_time_or_steps, &level.use_step_counter, NULL, "(0 => no limit)", "time or step limit" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(11), GADGET_ID_GAME_ENGINE_TYPE, GADGET_ID_NONE, -1, options_game_engine_type, &level.game_engine_type, "game engine:", NULL, "game engine" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(10), GADGET_ID_WIND_DIRECTION, GADGET_ID_NONE, -1, options_wind_direction, &level.wind_direction_initial, "initial wind direction:", NULL, "initial wind direction" }, /* ---------- element settings: configure (several elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(6), GADGET_ID_PLAYER_SPEED, GADGET_ID_NONE, -1, options_player_speed, &level.initial_player_stepsize[0], "initial player speed:", NULL, "initial player speed" }, /* ---------- element settings: configure 1 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_ACCESS_TYPE, GADGET_ID_NONE, -1, options_access_type, &custom_element.access_type, NULL, NULL, "type of access to this field" }, { -1, ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_ACCESS_LAYER, GADGET_ID_CUSTOM_ACCESS_TYPE, -1, options_access_layer, &custom_element.access_layer, NULL, NULL, "layer of access for this field" }, { -1, ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_ACCESS_PROTECTED, GADGET_ID_CUSTOM_ACCESS_LAYER, -1, options_access_protected, &custom_element.access_protected, NULL, NULL, "protected access for this field" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_ACCESS_DIRECTION, GADGET_ID_NONE, -1, options_access_direction, &custom_element.access_direction, "from", NULL, "access direction for this field" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CUSTOM_WALK_TO_ACTION, GADGET_ID_NONE, -1, options_walk_to_action, &custom_element.walk_to_action, NULL, NULL, "diggable/collectible/pushable" }, /* ---------- element settings: configure 2 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_MOVE_PATTERN, GADGET_ID_NONE, -1, options_move_pattern, &custom_element.move_pattern, "can move", NULL, "element move pattern" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_MOVE_DIRECTION, GADGET_ID_NONE, -1, options_move_direction, &custom_element.move_direction_initial, "starts moving", NULL, "initial element move direction" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_MOVE_STEPSIZE, GADGET_ID_NONE, -1, options_move_stepsize, &custom_element.move_stepsize, "move/fall speed", NULL, "speed of element movement" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE, GADGET_ID_NONE, -1, options_move_leave_type, &custom_element.move_leave_type, "can dig: can", ":", "leave behind or change element" }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_SMASH_TARGETS, GADGET_ID_CUSTOM_CAN_SMASH, -1, options_smash_targets, &custom_element.smash_targets, "can smash", NULL, "elements that can be smashed" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CUSTOM_SLIPPERY_TYPE, GADGET_ID_NONE, -1, options_slippery_type, &custom_element.slippery_type, "slippery", NULL, "where other elements fall down" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_DEADLINESS, GADGET_ID_NONE, -1, options_deadliness, &custom_element.deadliness, "deadly when", NULL, "deadliness of element" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_EXPLOSION_TYPE, GADGET_ID_NONE, -1, options_explosion_type, &custom_element.explosion_type, "can explode", NULL, "explosion type" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CHANGE_TIME_UNITS, GADGET_ID_NONE, -1, options_time_units, &custom_element_change.delay_frames, "delay time given in", NULL, "delay time units for change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CHANGE_DIRECT_ACTION, GADGET_ID_NONE, -1, options_change_direct_action, &custom_element_change.direct_action, NULL, NULL, "type of direct action" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CHANGE_OTHER_ACTION, GADGET_ID_NONE, -1, options_change_other_action, &custom_element_change.other_action, NULL, "element:", "type of other element action" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(6), GADGET_ID_CHANGE_SIDE, GADGET_ID_NONE, -1, options_change_trigger_side, &custom_element_change.trigger_side, "at", "side", "element side triggering change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CHANGE_PLAYER, GADGET_ID_NONE, -1, options_change_trigger_player, &custom_element_change.trigger_player, "player:", " ", "player that causes change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CHANGE_PAGE, GADGET_ID_CHANGE_PLAYER, -1, options_change_trigger_page, &custom_element_change.trigger_page, "page:", NULL, "change page that causes change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CHANGE_REPLACE_WHEN, GADGET_ID_NONE, -1, options_change_replace_when, &custom_element_change.replace_when, "replace when", NULL, "which elements can be replaced" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_TYPE, GADGET_ID_NONE, -1, options_action_type, &custom_element_change.action_type, NULL, NULL, "action on specified condition" }, { -1, ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_MODE, GADGET_ID_ACTION_TYPE, -1, options_action_mode_none, &custom_element_change.action_mode, NULL, NULL, "action operator" }, { -1, ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_ARG, GADGET_ID_ACTION_MODE, -1, options_action_arg_none, &custom_element_change.action_arg, NULL, NULL, "action parameter" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_SELECT_CHANGE_PAGE, GADGET_ID_NONE, 3, options_change_page, &custom_element.current_change_page, NULL, NULL, "element change page" }, /* ---------- element settings: configure (group elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(6), GADGET_ID_GROUP_CHOICE_MODE, GADGET_ID_NONE, -1, options_group_choice_mode, &group_element_info.choice_mode, "choice type:", NULL, "type of group element choice" }, }; static struct { int x, y; int gadget_id; int gadget_id_align; int size; char *text; char *text_left, *text_right, *infotext; } textbutton_info[ED_NUM_TEXTBUTTONS] = { { ED_LEVEL_SETTINGS_TABS_XPOS(0), ED_LEVEL_SETTINGS_TABS_YPOS(0), GADGET_ID_LEVELINFO_LEVEL, GADGET_ID_NONE, 8, "Level", NULL, NULL, "Configure level properties" }, { ED_LEVEL_SETTINGS_TABS_XPOS(1), ED_LEVEL_SETTINGS_TABS_YPOS(0), GADGET_ID_LEVELINFO_EDITOR, GADGET_ID_NONE, 8, "Editor", NULL, NULL, "Configure editor properties" }, { ED_ELEMENT_SETTINGS_TABS_XPOS(0), ED_ELEMENT_SETTINGS_TABS_YPOS(0), GADGET_ID_PROPERTIES_INFO, GADGET_ID_NONE, 8, "Info", NULL, NULL, "Show information about element" }, { ED_ELEMENT_SETTINGS_TABS_XPOS(1), ED_ELEMENT_SETTINGS_TABS_YPOS(0), GADGET_ID_PROPERTIES_CONFIG, GADGET_ID_NONE, 8, "Config", NULL, NULL, "Configure element properties" }, { ED_ELEMENT_SETTINGS_TABS_XPOS(1), ED_ELEMENT_SETTINGS_TABS_YPOS(0), GADGET_ID_PROPERTIES_CONFIG_1, GADGET_ID_NONE, 8, "Config 1", NULL, NULL, "Configure element properties, part 1" }, { ED_ELEMENT_SETTINGS_TABS_XPOS(2), ED_ELEMENT_SETTINGS_TABS_YPOS(0), GADGET_ID_PROPERTIES_CONFIG_2, GADGET_ID_NONE, 8, "Config 2", NULL, NULL, "Configure element properties, part 2" }, { ED_ELEMENT_SETTINGS_TABS_XPOS(3), ED_ELEMENT_SETTINGS_TABS_YPOS(0), GADGET_ID_PROPERTIES_CHANGE, GADGET_ID_NONE, 8, "Change", NULL, NULL, "Configure custom element change pages" }, { -1, ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_SAVE_AS_TEMPLATE, GADGET_ID_CUSTOM_USE_TEMPLATE, -1, "Save", " ", "As Template", "Save current settings as new template" }, { -1, ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_ADD_CHANGE_PAGE, GADGET_ID_PASTE_CHANGE_PAGE, -1, "New", NULL, NULL, "Add new change page" }, { -1, ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_DEL_CHANGE_PAGE, GADGET_ID_ADD_CHANGE_PAGE, -1, "Delete", NULL, NULL, "Delete current change page" }, }; static struct { int gd_x, gd_y; int x, y; int width, height; int gadget_id; int gadget_id_align; char *text_left, *text_right, *infotext; } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] = { { ED_BUTTON_MINUS_XPOS, ED_BUTTON_COUNT_YPOS, ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(14), ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, GADGET_ID_PREV_CHANGE_PAGE, GADGET_ID_NONE, NULL, NULL, "select previous change page" }, { ED_BUTTON_PLUS_XPOS, ED_BUTTON_COUNT_YPOS, -1, ED_ELEMENT_SETTINGS_YPOS(14), ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, GADGET_ID_NEXT_CHANGE_PAGE, GADGET_ID_SELECT_CHANGE_PAGE, NULL, "change page", "select next change page" }, { ED_COPY_CHANGE_PAGE_XPOS, ED_COPY_CHANGE_PAGE_YPOS, -1, ED_ELEMENT_SETTINGS_YPOS(14), ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, GADGET_ID_COPY_CHANGE_PAGE, GADGET_ID_NEXT_CHANGE_PAGE, " ", NULL, "copy settings from this change page" }, { ED_PASTE_CHANGE_PAGE_XPOS, ED_PASTE_CHANGE_PAGE_YPOS, -1, ED_ELEMENT_SETTINGS_YPOS(14), ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, GADGET_ID_PASTE_CHANGE_PAGE, GADGET_ID_COPY_CHANGE_PAGE, NULL, NULL, "paste settings to this change page" }, }; static struct { int gd_x, gd_y; int x, y; int gadget_id; char *infotext; } scrollbutton_info[ED_NUM_SCROLLBUTTONS] = { { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else ED_SCROLL_UP_XPOS, ED_SCROLL_UP_YPOS, #endif GADGET_ID_SCROLL_UP, "scroll level editing area up" }, { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else ED_SCROLL_DOWN_XPOS, ED_SCROLL_DOWN_YPOS, #endif GADGET_ID_SCROLL_DOWN, "scroll level editing area down" }, { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else ED_SCROLL_LEFT_XPOS, ED_SCROLL_LEFT_YPOS, #endif GADGET_ID_SCROLL_LEFT, "scroll level editing area left" }, { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else ED_SCROLL_RIGHT_XPOS, ED_SCROLL_RIGHT_YPOS, #endif GADGET_ID_SCROLL_RIGHT, "scroll level editing area right" }, { ED_SCROLLBUTTON2_XPOS, ED_SCROLLBUTTON2_YPOS + 0 * ED_SCROLLBUTTON2_YSIZE, ED_SCROLL2_UP_XPOS, ED_SCROLL2_UP_YPOS, GADGET_ID_SCROLL_LIST_UP, "scroll element list up ('Page Up')" }, { ED_SCROLLBUTTON2_XPOS, ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE, ED_SCROLL2_DOWN_XPOS, ED_SCROLL2_DOWN_YPOS, GADGET_ID_SCROLL_LIST_DOWN, "scroll element list down ('Page Down')" }, }; static struct { int gd_x, gd_y; int x, y; int width, height; int wheel_x, wheel_y; int wheel_width, wheel_height; int type; int gadget_id; char *infotext; } scrollbar_info[ED_NUM_SCROLLBARS] = { { ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ #else SX + ED_SCROLL_HORIZONTAL_XPOS, SY + ED_SCROLL_HORIZONTAL_YPOS, ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE, SX, SY, SXSIZE, SYSIZE, #endif GD_TYPE_SCROLLBAR_HORIZONTAL, GADGET_ID_SCROLL_HORIZONTAL, "scroll level editing area horizontally" }, { ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ #else SX + ED_SCROLL_VERTICAL_XPOS, SY + ED_SCROLL_VERTICAL_YPOS, ED_SCROLL_VERTICAL_XSIZE, ED_SCROLL_VERTICAL_YSIZE, SX, SY, SXSIZE, SYSIZE, #endif GD_TYPE_SCROLLBAR_VERTICAL, GADGET_ID_SCROLL_VERTICAL, "scroll level editing area vertically" }, { ED_SCROLLBAR2_XPOS, ED_SCROLLBAR2_YPOS, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ ED_SCROLL2_VERTICAL_XSIZE, ED_SCROLL2_VERTICAL_YSIZE, -1, -1, /* these values are not constant, but can change at runtime */ #else DX + ED_SCROLL2_VERTICAL_XPOS, DY + ED_SCROLL2_VERTICAL_YPOS, ED_SCROLL2_VERTICAL_XSIZE, ED_SCROLL2_VERTICAL_YSIZE, DX, DY, #endif DXSIZE, DYSIZE, GD_TYPE_SCROLLBAR_VERTICAL, GADGET_ID_SCROLL_LIST_VERTICAL, "scroll element list vertically" } }; static struct { int x, y; int gadget_id; int gadget_id_align; int radio_button_nr; int *value; int checked_value; char *text_left, *text_right, *infotext; } radiobutton_info[ED_NUM_RADIOBUTTONS] = { { -1, ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_RANDOM_PERCENTAGE, GADGET_ID_LEVEL_RANDOM_UP, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_PERCENTAGE, " ", "percentage", "use percentage for random elements" }, { -1, ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_RANDOM_QUANTITY, GADGET_ID_RANDOM_PERCENTAGE, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_QUANTITY, " ", "quantity", "use quantity for random elements" } }; static struct { int x, y; int gadget_id; int gadget_id_align; boolean *value; char *text_left, *text_right, *infotext; } checkbutton_info[ED_NUM_CHECKBUTTONS] = { /* ---------- level and editor settings ---------------------------------- */ { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(1), GADGET_ID_RANDOM_RESTRICTED, GADGET_ID_NONE, &random_placement_background_restricted, NULL, "restrict random placement to:", "set random placement restriction" }, /* ---------- element settings: configure (various elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_STICK_ELEMENT, GADGET_ID_NONE, &stick_element_properties_window, NULL, "stick this screen to edit content","stick this screen to edit content" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_EM_SLIPPERY_GEMS, GADGET_ID_NONE, &level.em_slippery_gems, NULL, "slip down from certain flat walls","use EM/DC style slipping behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_EM_EXPLODES_BY_FIRE, GADGET_ID_NONE, &level.em_explodes_by_fire, NULL, "explodes with chain reaction", "use R'n'D style explosion behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_USE_SPRING_BUG, GADGET_ID_NONE, &level.use_spring_bug, NULL, "use spring pushing bug", "use odd spring pushing behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_USE_TIME_ORB_BUG, GADGET_ID_NONE, &level.use_time_orb_bug, NULL, "use time orb bug", "use odd time orb behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_RANDOM_BALL_CONTENT, GADGET_ID_NONE, &level.ball_random, NULL, "create single random element", "only create one element from content" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_INITIAL_BALL_STATE, GADGET_ID_NONE, &level.ball_state_initial, NULL, "magic ball initially activated", "activate magic ball after level start" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_GROW_INTO_DIGGABLE, GADGET_ID_NONE, &level.grow_into_diggable, NULL, "can grow into anything diggable", "grow into more than just sand" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_AUTO_EXIT_SOKOBAN, GADGET_ID_NONE, &level.auto_exit_sokoban, NULL, "exit level if all fields solved", "automatically finish Sokoban levels" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CONTINUOUS_SNAPPING, GADGET_ID_NONE, &level.continuous_snapping, NULL, "continuos snapping", "use snapping without releasing key" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_BLOCK_SNAP_FIELD, GADGET_ID_NONE, &level.block_snap_field, NULL, "block snapped field when snapping", "use snapping delay to show animation" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_BLOCK_LAST_FIELD, GADGET_ID_NONE, &level.block_last_field, NULL, "block last field when moving", "player blocks last field when moving" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_SP_BLOCK_LAST_FIELD, GADGET_ID_NONE, &level.sp_block_last_field, NULL, "block last field when moving", "player blocks last field when moving" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_INSTANT_RELOCATION, GADGET_ID_NONE, &level.instant_relocation, NULL, "no scrolling when relocating", "player gets relocated without delay" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_SHIFTED_RELOCATION, GADGET_ID_NONE, &level.shifted_relocation, NULL, "no centering when relocating", "level not centered after relocation" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_USE_START_ELEMENT, GADGET_ID_NONE, &level.use_start_element[0], NULL, "use level start element:", "start level at this element's position" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_USE_ARTWORK_ELEMENT, GADGET_ID_NONE, &level.use_artwork_element[0], NULL, "use artwork from element:", "use player artwork from other element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_USE_EXPLOSION_ELEMENT, GADGET_ID_NONE, &level.use_explosion_element[0], NULL, "use explosion from element:", "use explosion properties from element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(12), GADGET_ID_INITIAL_GRAVITY, GADGET_ID_NONE, &level.initial_player_gravity[0], NULL, "use initial gravity", "set initial player gravity" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_USE_INITIAL_INVENTORY, GADGET_ID_NONE, &level.use_initial_inventory[0], NULL, "use initial inventory:", "use collected elements on level start" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CAN_PASS_TO_WALKABLE, GADGET_ID_NONE, &level.can_pass_to_walkable, NULL, "can pass to walkable element", "player can pass to empty or walkable" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CAN_FALL_INTO_ACID, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE_INTO_ACID], NULL, "can fall into acid (with gravity)","player can fall into acid pool" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_CAN_MOVE_INTO_ACID, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE_INTO_ACID], NULL, "can move into acid", "element can move into acid pool" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_DONT_COLLIDE_WITH, GADGET_ID_NONE, &custom_element_properties[EP_DONT_COLLIDE_WITH], NULL, "deadly when colliding with", "element is deadly when hitting player" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_ENVELOPE_AUTOWRAP, GADGET_ID_NONE, &level.envelope[0].autowrap, NULL, "auto-wrap", "automatically wrap envelope text" }, { -1, ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_ENVELOPE_CENTERED, GADGET_ID_ENVELOPE_AUTOWRAP, &level.envelope[0].centered, " ", "centered", "automatically center envelope text" }, /* ---------- element settings: configure 1 (custom elements) ----------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_USE_GRAPHIC, GADGET_ID_NONE, &custom_element.use_gfx_element, /* !!! add separate "use existing element sound" !!! */ #if 0 NULL, "use graphic/sound of element:", "use existing graphic and sound" #else NULL, "use graphic of element:", "use existing element graphic" #endif }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_USE_TEMPLATE, GADGET_ID_NONE, &level.use_custom_template, NULL, "use template", "use template for custom properties" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_ACCESSIBLE, GADGET_ID_NONE, &custom_element_properties[EP_ACCESSIBLE], NULL, NULL, "player can walk to or pass this field" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_GRAV_REACHABLE, GADGET_ID_NONE, &custom_element_properties[EP_GRAVITY_REACHABLE], NULL, "reachable despite gravity", "player can walk/dig despite gravity" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_CUSTOM_USE_LAST_VALUE, GADGET_ID_NONE, &custom_element.use_last_ce_value, NULL, "use last CE value after change", "use last CE value after change" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CUSTOM_WALK_TO_OBJECT, GADGET_ID_NONE, &custom_element_properties[EP_WALK_TO_OBJECT], NULL, NULL, "player can dig/collect/push element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_INDESTRUCTIBLE, GADGET_ID_NONE, &custom_element_properties[EP_INDESTRUCTIBLE], NULL, "indestructible", "element is indestructible" }, /* ---------- element settings: configure 2 (custom elements) ----------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_CAN_MOVE, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE], NULL, NULL, "element can move with some pattern" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_CAN_FALL, GADGET_ID_NONE, &custom_element_properties[EP_CAN_FALL], NULL, "can fall", "element can fall down" }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_CAN_SMASH, GADGET_ID_CUSTOM_CAN_FALL, &custom_element_properties[EP_CAN_SMASH], " ", NULL, "element can smash other elements" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CUSTOM_SLIPPERY, GADGET_ID_NONE, &custom_element_properties[EP_SLIPPERY], NULL, NULL, "other elements can fall down from it" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_DEADLY, GADGET_ID_NONE, &custom_element_properties[EP_DEADLY], NULL, NULL, "element can kill the player" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_CAN_EXPLODE, GADGET_ID_NONE, &custom_element_properties[EP_CAN_EXPLODE], NULL, NULL, "element can explode" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_FIRE, GADGET_ID_NONE, &custom_element_properties[EP_EXPLODES_BY_FIRE], NULL, "by fire", "element can explode by fire/explosion" }, { -1, ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_SMASH, GADGET_ID_CUSTOM_EXPLODE_FIRE, &custom_element_properties[EP_EXPLODES_SMASHED], " ", "smashed", "element can explode when smashed" }, { -1, ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_IMPACT, GADGET_ID_CUSTOM_EXPLODE_SMASH, &custom_element_properties[EP_EXPLODES_IMPACT], " ", "impact", "element can explode on impact" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_CAN_CHANGE, GADGET_ID_NONE, &custom_element_change.can_change, NULL, "element changes to:", "change element on specified condition" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CHANGE_DELAY, GADGET_ID_NONE, &custom_element_change_events[CE_DELAY], NULL, NULL, "element changes after delay" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CHANGE_BY_DIRECT_ACT, GADGET_ID_NONE, &custom_element_change_events[CE_BY_DIRECT_ACTION], NULL, NULL, "element changes by direct action" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CHANGE_BY_OTHER_ACT, GADGET_ID_NONE, &custom_element_change_events[CE_BY_OTHER_ACTION], NULL, NULL, "element changes by other element" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CHANGE_USE_EXPLOSION, GADGET_ID_NONE, &custom_element_change.explode, NULL, "explode instead of change", "element explodes instead of change" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CHANGE_USE_CONTENT, GADGET_ID_NONE, &custom_element_change.use_target_content, NULL, "use extended change target:", "element changes to more elements" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CHANGE_ONLY_COMPLETE, GADGET_ID_NONE, &custom_element_change.only_if_complete, NULL, "replace all or nothing", "only replace when all can be changed" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(12), GADGET_ID_CHANGE_USE_RANDOM, GADGET_ID_NONE, &custom_element_change.use_random_replace, NULL, NULL, "use percentage for random replace" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_CHANGE_HAS_ACTION, GADGET_ID_NONE, &custom_element_change.has_action, NULL, NULL, "execute action on specified condition" }, }; static struct { int x, y; int gadget_id; int gadget_id_align; int *value; int area_xsize, area_ysize; char *text_left, *text_right, *text_below, *infotext; } drawingarea_info[ED_NUM_DRAWING_AREAS] = { /* ---------- level playfield content ------------------------------------ */ { 0, 0, GADGET_ID_DRAWING_LEVEL, GADGET_ID_NONE, NULL, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else MAX_ED_FIELDX, MAX_ED_FIELDY, #endif NULL, NULL, NULL, NULL }, /* ---------- yam yam content -------------------------------------------- */ { ED_AREA_YAMYAM_CONTENT_XPOS(0), ED_AREA_YAMYAM_CONTENT_YPOS(0), GADGET_ID_YAMYAM_CONTENT_0, GADGET_ID_NONE, &level.yamyam_content[0].e[0][0], 3, 3, NULL, NULL, "1", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(1), ED_AREA_YAMYAM_CONTENT_YPOS(1), GADGET_ID_YAMYAM_CONTENT_1, GADGET_ID_NONE, &level.yamyam_content[1].e[0][0], 3, 3, NULL, NULL, "2", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(2), ED_AREA_YAMYAM_CONTENT_YPOS(2), GADGET_ID_YAMYAM_CONTENT_2, GADGET_ID_NONE, &level.yamyam_content[2].e[0][0], 3, 3, NULL, NULL, "3", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(3), ED_AREA_YAMYAM_CONTENT_YPOS(3), GADGET_ID_YAMYAM_CONTENT_3, GADGET_ID_NONE, &level.yamyam_content[3].e[0][0], 3, 3, NULL, NULL, "4", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(4), ED_AREA_YAMYAM_CONTENT_YPOS(4), GADGET_ID_YAMYAM_CONTENT_4, GADGET_ID_NONE, &level.yamyam_content[4].e[0][0], 3, 3, NULL, NULL, "5", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(5), ED_AREA_YAMYAM_CONTENT_YPOS(5), GADGET_ID_YAMYAM_CONTENT_5, GADGET_ID_NONE, &level.yamyam_content[5].e[0][0], 3, 3, NULL, NULL, "6", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(6), ED_AREA_YAMYAM_CONTENT_YPOS(6), GADGET_ID_YAMYAM_CONTENT_6, GADGET_ID_NONE, &level.yamyam_content[6].e[0][0], 3, 3, NULL, NULL, "7", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS(7), ED_AREA_YAMYAM_CONTENT_YPOS(7), GADGET_ID_YAMYAM_CONTENT_7, GADGET_ID_NONE, &level.yamyam_content[7].e[0][0], 3, 3, NULL, NULL, "8", NULL }, /* ---------- magic ball content ----------------------------------------- */ { ED_AREA_MAGIC_BALL_CONTENT_XPOS(0), ED_AREA_MAGIC_BALL_CONTENT_YPOS(0), GADGET_ID_MAGIC_BALL_CONTENT_0, GADGET_ID_NONE, &level.ball_content[0].e[0][0], 3, 3, NULL, NULL, "1", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(1), ED_AREA_MAGIC_BALL_CONTENT_YPOS(1), GADGET_ID_MAGIC_BALL_CONTENT_1, GADGET_ID_NONE, &level.ball_content[1].e[0][0], 3, 3, NULL, NULL, "2", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(2), ED_AREA_MAGIC_BALL_CONTENT_YPOS(2), GADGET_ID_MAGIC_BALL_CONTENT_2, GADGET_ID_NONE, &level.ball_content[2].e[0][0], 3, 3, NULL, NULL, "3", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(3), ED_AREA_MAGIC_BALL_CONTENT_YPOS(3), GADGET_ID_MAGIC_BALL_CONTENT_3, GADGET_ID_NONE, &level.ball_content[3].e[0][0], 3, 3, NULL, NULL, "4", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(4), ED_AREA_MAGIC_BALL_CONTENT_YPOS(4), GADGET_ID_MAGIC_BALL_CONTENT_4, GADGET_ID_NONE, &level.ball_content[4].e[0][0], 3, 3, NULL, NULL, "5", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(5), ED_AREA_MAGIC_BALL_CONTENT_YPOS(5), GADGET_ID_MAGIC_BALL_CONTENT_5, GADGET_ID_NONE, &level.ball_content[5].e[0][0], 3, 3, NULL, NULL, "6", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(6), ED_AREA_MAGIC_BALL_CONTENT_YPOS(6), GADGET_ID_MAGIC_BALL_CONTENT_6, GADGET_ID_NONE, &level.ball_content[6].e[0][0], 3, 3, NULL, NULL, "7", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS(7), ED_AREA_MAGIC_BALL_CONTENT_YPOS(7), GADGET_ID_MAGIC_BALL_CONTENT_7, GADGET_ID_NONE, &level.ball_content[7].e[0][0], 3, 3, NULL, NULL, "8", NULL }, /* ---------- android content -------------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(5), GADGET_ID_ANDROID_CONTENT, GADGET_ID_NONE, &level.android_clone_element[0], MAX_ANDROID_ELEMENTS, 1, "elements:", NULL, NULL, "elements android can clone" }, /* ---------- amoeba content --------------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(3), GADGET_ID_AMOEBA_CONTENT, GADGET_ID_NONE, &level.amoeba_content, 1, 1, "content:", NULL, NULL, "amoeba content" }, /* ---------- level start element ---------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(9), GADGET_ID_START_ELEMENT, GADGET_ID_USE_START_ELEMENT, &level.start_element[0], 1, 1, NULL, NULL, NULL, "level start element" }, /* ---------- player artwork element ------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(10), GADGET_ID_ARTWORK_ELEMENT, GADGET_ID_USE_ARTWORK_ELEMENT, &level.artwork_element[0], 1, 1, NULL, NULL, NULL, "element for player artwork" }, /* ---------- player explosion element ----------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(11), GADGET_ID_EXPLOSION_ELEMENT, GADGET_ID_USE_EXPLOSION_ELEMENT, &level.explosion_element[0], 1, 1, NULL, NULL, NULL, "element for player explosion" }, /* ---------- player initial inventory ----------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), GADGET_ID_INVENTORY_CONTENT, GADGET_ID_USE_INITIAL_INVENTORY, &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1, NULL, NULL, NULL, "content for initial inventory" }, /* ---------- element settings: configure 1 (custom elements) ----------- */ /* ---------- custom graphic --------------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_GRAPHIC, GADGET_ID_CUSTOM_USE_GRAPHIC, &custom_element.gfx_element_initial,1, 1, NULL, NULL, NULL, "custom graphic element" }, /* ---------- element settings: configure 2 (custom elements) ----------- */ /* ---------- custom content (when exploding) ---------------------------- */ { -1, ED_AREA_3X3_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_CONTENT, GADGET_ID_NONE, /* align three rows */ &custom_element.content.e[0][0], 3, 3, "content:", NULL, NULL, NULL }, /* ---------- custom enter and leave element (when moving) --------------- */ { ED_AREA_1X1_SETTINGS_XPOS(1), ED_AREA_1X1_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_MOVE_ENTER, GADGET_ID_NONE, &custom_element.move_enter_element, 1, 1, "can dig:", " ", NULL, "element that can be digged/collected" }, { -1, ED_AREA_1X1_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_MOVE_LEAVE, GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE, &custom_element.move_leave_element, 1, 1, NULL, NULL, NULL, "element that will be left behind" }, /* ---------- element settings: advanced (custom elements) --------------- */ /* ---------- custom change target --------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_CHANGE_TARGET, GADGET_ID_CUSTOM_CAN_CHANGE, &custom_element_change.target_element, 1, 1, NULL, "after/when:", NULL, "new target element after change" }, /* ---------- custom change content (extended change target) ------------- */ { -1, ED_AREA_3X3_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_CHANGE_CONTENT, GADGET_ID_NONE, /* align three rows */ &custom_element_change.target_content.e[0][0], 3, 3, NULL, NULL, NULL, "new extended elements after change" }, /* ---------- custom change trigger (element causing change) ------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(5), GADGET_ID_CUSTOM_CHANGE_TRIGGER, GADGET_ID_CHANGE_OTHER_ACTION, &custom_element_change.initial_trigger_element, 1, 1, NULL, NULL, NULL, "other element triggering change" }, /* ---------- custom change action (element used for action) ------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(13), GADGET_ID_CUSTOM_CHANGE_ACTION, GADGET_ID_ACTION_ARG, &custom_element_change.action_element, 1, 1, NULL, NULL, NULL, "element used as action parameter" }, /* ---------- group element content -------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(4), GADGET_ID_GROUP_CONTENT, GADGET_ID_NONE, &group_element_info.element[0], MAX_ELEMENTS_IN_GROUP, 1, "content:", NULL, NULL, NULL }, /* ---------- random background (for random painting) -------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(-1), GADGET_ID_RANDOM_BACKGROUND, GADGET_ID_RANDOM_RESTRICTED, &random_placement_background_element, 1, 1, NULL, NULL, NULL, "random placement background" }, }; /* ----------------------------------------------------------------------------- some internally used variables ----------------------------------------------------------------------------- */ /* actual size of level editor drawing area */ #if 1 static int ed_fieldx, ed_fieldy; #else static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1; #endif /* actual position of level editor drawing area in level playfield */ static int level_xpos = -1, level_ypos = -1; #if 1 #define IN_ED_FIELD(x,y) IN_FIELD(x, y, ed_fieldx, ed_fieldy) #else #define IN_ED_FIELD(x,y) ((x)>=0 && (x)=0 &&(y)= 1 && button <= 3) #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \ (button) == 2 ? new_element2 : \ (button) == 3 ? new_element3 : EL_EMPTY) #define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10) /* forward declaration for internal use */ static void ModifyEditorCounterValue(int, int); static void ModifyEditorCounterLimits(int, int, int); static void ModifyEditorSelectboxValue(int, int); static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *); static void ModifyEditorDrawingArea(int, int, int); static void ModifyEditorElementList(); static void AdjustElementListScrollbar(); static void RedrawDrawingElements(); static void DrawDrawingWindow(); static void DrawLevelInfoWindow(); static void DrawPropertiesWindow(); static void UpdateCustomElementGraphicGadgets(); static boolean checkPropertiesConfig(int); static void CopyLevelToUndoBuffer(int); static void HandleDrawingAreas(struct GadgetInfo *); static void HandleCounterButtons(struct GadgetInfo *); static void HandleTextInputGadgets(struct GadgetInfo *); static void HandleTextAreaGadgets(struct GadgetInfo *); static void HandleSelectboxGadgets(struct GadgetInfo *); static void HandleTextbuttonGadgets(struct GadgetInfo *); static void HandleGraphicbuttonGadgets(struct GadgetInfo *); static void HandleRadiobuttons(struct GadgetInfo *); static void HandleCheckbuttons(struct GadgetInfo *); static void HandleControlButtons(struct GadgetInfo *); static void HandleDrawingAreaInfo(struct GadgetInfo *); static void PrintEditorGadgetInfoText(struct GadgetInfo *); static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS]; static int right_gadget_border[NUM_EDITOR_GADGETS]; static int drawing_function = GADGET_ID_SINGLE_ITEMS; static int last_drawing_function = GADGET_ID_SINGLE_ITEMS; static boolean draw_with_brush = FALSE; static int properties_element = 0; static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static int undo_buffer_position = 0; static int undo_buffer_steps = 0; static int edit_mode; static int edit_mode_levelinfo; static int edit_mode_properties; static int element_shift = 0; static int editor_el_players[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4 }; static int *editor_el_players_ptr = editor_el_players; static int num_editor_el_players = SIZEOF_ARRAY_INT(editor_el_players); static int editor_hl_boulderdash[] = { EL_INTERNAL_CASCADE_BD_ACTIVE, EL_CHAR('B'), EL_CHAR('D'), EL_EMPTY, }; static int editor_el_boulderdash[] = { EL_EMPTY, EL_SAND, EL_BD_ROCK, EL_BD_DIAMOND, EL_STEELWALL, EL_BD_WALL, EL_BD_EXPANDABLE_WALL, EL_BD_MAGIC_WALL, EL_BD_AMOEBA, EL_BD_BUTTERFLY_UP, EL_BD_FIREFLY_UP, EL_EXIT_CLOSED, EL_BD_BUTTERFLY_LEFT, EL_BD_FIREFLY_LEFT, EL_BD_BUTTERFLY_RIGHT, EL_BD_FIREFLY_RIGHT, EL_EMPTY, EL_BD_BUTTERFLY_DOWN, EL_BD_FIREFLY_DOWN, EL_EXIT_OPEN, }; static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash; static int *editor_el_boulderdash_ptr = editor_el_boulderdash; static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash); static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash); static int editor_hl_emerald_mine[] = { EL_INTERNAL_CASCADE_EM_ACTIVE, EL_CHAR('E'), EL_CHAR('M'), EL_EMPTY, }; static int editor_el_emerald_mine[] = { EL_SAND, EL_ROCK, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL, EL_STEELWALL, EL_WALL, EL_WALL_SLIPPERY, EL_MAGIC_WALL, EL_EMERALD, EL_DIAMOND, EL_NUT, EL_BOMB, EL_WALL_EMERALD, EL_WALL_DIAMOND, EL_DYNAMITE, EL_DYNAMITE_ACTIVE, EL_YAMYAM, EL_BUG_UP, EL_SPACESHIP_UP, EL_ROBOT, EL_BUG_LEFT, EL_SPACESHIP_LEFT, EL_BUG_RIGHT, EL_SPACESHIP_RIGHT, EL_ROBOT_WHEEL, EL_BUG_DOWN, EL_SPACESHIP_DOWN, EL_INVISIBLE_WALL, EL_ACID_POOL_TOPLEFT, EL_ACID, EL_ACID_POOL_TOPRIGHT, EL_AMOEBA_DROP, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_AMOEBA_WET, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_EXIT_CLOSED, EL_EM_EXIT_OPEN, EL_EM_STEEL_EXIT_CLOSED, EL_EM_STEEL_EXIT_OPEN, }; static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine; static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine; static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine); static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine); static int editor_hl_emerald_mine_club[] = { EL_INTERNAL_CASCADE_EMC_ACTIVE, EL_CHAR('E'), EL_CHAR('M'), EL_CHAR('C'), }; static int editor_el_emerald_mine_club[] = { EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_13, EL_EMC_WALL_14, EL_EMC_WALL_15, EL_EMC_WALL_16, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_EMC_WALL_9, EL_EMC_WALL_10, EL_EMC_WALL_11, EL_EMC_WALL_12, EL_EMC_GRASS, EL_EMC_FAKE_GRASS, EL_EMC_PLANT, EL_EMC_DRIPPER, EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_SWITCH, EL_SPRING, EL_EMC_SPRING_BUMPER, EL_EMC_LENSES, EL_EMC_MAGNIFIER, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_BALLOON, EL_YAMYAM_UP, EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_ANY, EL_YAMYAM_LEFT, EL_BALLOON_SWITCH_LEFT, EL_YAMYAM_RIGHT, EL_BALLOON_SWITCH_RIGHT, EL_EMC_ANDROID, EL_YAMYAM_DOWN, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_NONE, }; static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club; static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club; static int num_editor_hl_emerald_mine_club=SIZEOF_ARRAY_INT(editor_hl_emerald_mine_club); static int num_editor_el_emerald_mine_club=SIZEOF_ARRAY_INT(editor_el_emerald_mine_club); static int editor_hl_rnd[] = { EL_INTERNAL_CASCADE_RND_ACTIVE, EL_CHAR('R'), EL_CHAR('N'), EL_CHAR('D'), }; static int editor_el_rnd[] = { EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_ARROW_LEFT, EL_ARROW_RIGHT, EL_ARROW_UP, EL_ARROW_DOWN, EL_AMOEBA_DEAD, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_GAME_OF_LIFE, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_BIOMAZE, EL_WALL_EMERALD_YELLOW, EL_WALL_EMERALD_RED, EL_WALL_EMERALD_PURPLE, EL_WALL_BD_DIAMOND, EL_SPEED_PILL, EL_PACMAN_UP, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_PACMAN_LEFT, EL_DARK_YAMYAM, EL_PACMAN_RIGHT, EL_EMPTY, EL_BLACK_ORB, EL_PACMAN_DOWN, EL_LAMP, EL_LAMP_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_STONEBLOCK, EL_MOLE, EL_PENGUIN, EL_PIG, EL_DRAGON, EL_BUG, EL_MOLE_UP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_MOLE_LEFT, EL_SATELLITE, EL_MOLE_RIGHT, EL_PACMAN, EL_SPACESHIP, EL_MOLE_DOWN, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_WALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, }; static int *editor_hl_rnd_ptr = editor_hl_rnd; static int *editor_el_rnd_ptr = editor_el_rnd; static int num_editor_hl_rnd = SIZEOF_ARRAY_INT(editor_hl_rnd); static int num_editor_el_rnd = SIZEOF_ARRAY_INT(editor_el_rnd); static int editor_hl_sokoban[] = { EL_INTERNAL_CASCADE_SB_ACTIVE, EL_CHAR('S'), EL_CHAR('B'), EL_EMPTY, }; static int editor_el_sokoban[] = { EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_SOKOBAN_FIELD_PLAYER, }; static int *editor_hl_sokoban_ptr = editor_hl_sokoban; static int *editor_el_sokoban_ptr = editor_el_sokoban; static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban); static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban); static int editor_hl_supaplex[] = { EL_INTERNAL_CASCADE_SP_ACTIVE, EL_CHAR('S'), EL_CHAR('P'), EL_EMPTY, }; static int editor_el_supaplex[] = { EL_SP_MURPHY, EL_EMPTY, EL_SP_BASE, EL_SP_BUGGY_BASE, EL_SP_INFOTRON, EL_SP_ZONK, EL_SP_SNIKSNAK, EL_SP_ELECTRON, EL_SP_DISK_RED, EL_SP_DISK_ORANGE, EL_SP_DISK_YELLOW, EL_SP_TERMINAL, EL_SP_EXIT_CLOSED, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_HARDWARE_YELLOW, EL_SP_CHIP_TOP, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_BOTTOM, }; static int *editor_hl_supaplex_ptr = editor_hl_supaplex; static int *editor_el_supaplex_ptr = editor_el_supaplex; static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex); static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex); static int editor_hl_diamond_caves[] = { EL_INTERNAL_CASCADE_DC_ACTIVE, EL_CHAR('D'), EL_CHAR('C'), EL_CHAR('2'), }; static int editor_el_diamond_caves[] = { EL_PEARL, EL_CRYSTAL, EL_WALL_PEARL, EL_WALL_CRYSTAL, EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_TIMEGATE_CLOSED, EL_TIMEGATE_OPEN, EL_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_STEELWALL_SLIPPERY, EL_INVISIBLE_SAND, EL_QUICKSAND_FAST_EMPTY, EL_QUICKSAND_FAST_FULL, EL_LANDMINE, EL_DC_LANDMINE, EL_SHIELD_NORMAL, EL_SHIELD_DEADLY, EL_EXTRA_TIME, EL_DC_MAGIC_WALL, EL_ENVELOPE_1, EL_ENVELOPE_2, EL_ENVELOPE_3, EL_ENVELOPE_4, EL_SIGN_RADIOACTIVITY, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, #if 0 EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_EMPTY, EL_EMPTY, EL_EMPTY, EL_SPERMS, EL_BULLET, EL_HEART, EL_CROSS, EL_FRANKIE, EL_EMPTY, EL_EMPTY, EL_EMPTY, #endif EL_DC_STEELWALL_2_SINGLE, EL_DC_STEELWALL_2_TOP, EL_SIGN_EXCLAMATION, EL_SIGN_STOP, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_GATE_WHITE, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_2_BOTTOM, EL_DC_KEY_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_GATE_FAKE_GRAY, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_DC_STEELWALL_1_RIGHT, EL_EMPTY, EL_DC_STEELWALL_1_LEFT, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_TOPLEFT_2, EL_EXPANDABLE_STEELWALL_ANY, }; static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves; static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves; static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves); static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves); static int editor_hl_dx_boulderdash[] = { EL_INTERNAL_CASCADE_DX_ACTIVE, EL_CHAR('D'), EL_CHAR('X'), EL_EMPTY, }; static int editor_el_dx_boulderdash[] = { EL_EMPTY, EL_TUBE_RIGHT_DOWN, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_DOWN, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_ANY, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL, EL_TUBE_RIGHT_UP, EL_TUBE_HORIZONTAL_UP, EL_TUBE_LEFT_UP, EL_TRAP, EL_DX_SUPABOMB, EL_EMPTY, EL_EMPTY }; static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash; static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash; static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash); static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash); static int editor_hl_chars[] = { EL_INTERNAL_CASCADE_CHARS_ACTIVE, EL_CHAR('T'), EL_CHAR('X'), EL_CHAR('T'), }; static int editor_el_chars[] = { EL_CHAR(' '), EL_CHAR('!'), EL_CHAR('"'), EL_CHAR('#'), EL_CHAR('$'), EL_CHAR('%'), EL_CHAR('&'), EL_CHAR('\''), EL_CHAR('('), EL_CHAR(')'), EL_CHAR('*'), EL_CHAR('+'), EL_CHAR(','), EL_CHAR('-'), EL_CHAR('.'), EL_CHAR('/'), EL_CHAR('0'), EL_CHAR('1'), EL_CHAR('2'), EL_CHAR('3'), EL_CHAR('4'), EL_CHAR('5'), EL_CHAR('6'), EL_CHAR('7'), EL_CHAR('8'), EL_CHAR('9'), EL_CHAR(':'), EL_CHAR(';'), EL_CHAR('<'), EL_CHAR('='), EL_CHAR('>'), EL_CHAR('?'), EL_CHAR('@'), EL_CHAR('A'), EL_CHAR('B'), EL_CHAR('C'), EL_CHAR('D'), EL_CHAR('E'), EL_CHAR('F'), EL_CHAR('G'), EL_CHAR('H'), EL_CHAR('I'), EL_CHAR('J'), EL_CHAR('K'), EL_CHAR('L'), EL_CHAR('M'), EL_CHAR('N'), EL_CHAR('O'), EL_CHAR('P'), EL_CHAR('Q'), EL_CHAR('R'), EL_CHAR('S'), EL_CHAR('T'), EL_CHAR('U'), EL_CHAR('V'), EL_CHAR('W'), EL_CHAR('X'), EL_CHAR('Y'), EL_CHAR('Z'), EL_CHAR('['), EL_CHAR('\\'), EL_CHAR(']'), EL_CHAR('^'), EL_CHAR('_'), EL_CHAR('©'), EL_CHAR('Ä'), EL_CHAR('Ö'), EL_CHAR('Ü'), EL_CHAR('°'), EL_CHAR('®'), EL_CHAR(FONT_ASCII_CURSOR), EL_CHAR(FONT_ASCII_BUTTON), EL_CHAR(FONT_ASCII_UP), EL_CHAR(FONT_ASCII_DOWN), EL_CHAR(' '), EL_CHAR(' ') }; static int *editor_hl_chars_ptr = editor_hl_chars; static int *editor_el_chars_ptr = editor_el_chars; static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars); static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars); static int editor_hl_steel_chars[] = { EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE, EL_STEEL_CHAR('T'), EL_STEEL_CHAR('X'), EL_STEEL_CHAR('T'), }; static int editor_el_steel_chars[] = { EL_STEEL_CHAR(' '), EL_STEEL_CHAR('!'), EL_STEEL_CHAR('"'), EL_STEEL_CHAR('#'), EL_STEEL_CHAR('$'), EL_STEEL_CHAR('%'), EL_STEEL_CHAR('&'), EL_STEEL_CHAR('\''), EL_STEEL_CHAR('('), EL_STEEL_CHAR(')'), EL_STEEL_CHAR('*'), EL_STEEL_CHAR('+'), EL_STEEL_CHAR(','), EL_STEEL_CHAR('-'), EL_STEEL_CHAR('.'), EL_STEEL_CHAR('/'), EL_STEEL_CHAR('0'), EL_STEEL_CHAR('1'), EL_STEEL_CHAR('2'), EL_STEEL_CHAR('3'), EL_STEEL_CHAR('4'), EL_STEEL_CHAR('5'), EL_STEEL_CHAR('6'), EL_STEEL_CHAR('7'), EL_STEEL_CHAR('8'), EL_STEEL_CHAR('9'), EL_STEEL_CHAR(':'), EL_STEEL_CHAR(';'), EL_STEEL_CHAR('<'), EL_STEEL_CHAR('='), EL_STEEL_CHAR('>'), EL_STEEL_CHAR('?'), EL_STEEL_CHAR('@'), EL_STEEL_CHAR('A'), EL_STEEL_CHAR('B'), EL_STEEL_CHAR('C'), EL_STEEL_CHAR('D'), EL_STEEL_CHAR('E'), EL_STEEL_CHAR('F'), EL_STEEL_CHAR('G'), EL_STEEL_CHAR('H'), EL_STEEL_CHAR('I'), EL_STEEL_CHAR('J'), EL_STEEL_CHAR('K'), EL_STEEL_CHAR('L'), EL_STEEL_CHAR('M'), EL_STEEL_CHAR('N'), EL_STEEL_CHAR('O'), EL_STEEL_CHAR('P'), EL_STEEL_CHAR('Q'), EL_STEEL_CHAR('R'), EL_STEEL_CHAR('S'), EL_STEEL_CHAR('T'), EL_STEEL_CHAR('U'), EL_STEEL_CHAR('V'), EL_STEEL_CHAR('W'), EL_STEEL_CHAR('X'), EL_STEEL_CHAR('Y'), EL_STEEL_CHAR('Z'), EL_STEEL_CHAR('['), EL_STEEL_CHAR('\\'), EL_STEEL_CHAR(']'), EL_STEEL_CHAR('^'), EL_STEEL_CHAR('_'), EL_STEEL_CHAR('©'), EL_STEEL_CHAR('Ä'), EL_STEEL_CHAR('Ö'), EL_STEEL_CHAR('Ü'), EL_STEEL_CHAR('°'), EL_STEEL_CHAR('®'), EL_STEEL_CHAR(FONT_ASCII_CURSOR), EL_STEEL_CHAR(FONT_ASCII_BUTTON), EL_STEEL_CHAR(FONT_ASCII_UP), EL_STEEL_CHAR(FONT_ASCII_DOWN), EL_STEEL_CHAR(' '), EL_STEEL_CHAR(' ') }; static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars; static int *editor_el_steel_chars_ptr = editor_el_steel_chars; static int num_editor_hl_steel_chars = SIZEOF_ARRAY_INT(editor_hl_steel_chars); static int num_editor_el_steel_chars = SIZEOF_ARRAY_INT(editor_el_steel_chars); static int editor_hl_custom[] = { EL_INTERNAL_CASCADE_CE_ACTIVE, EL_CHAR('C'), EL_CHAR('E'), EL_EMPTY, }; static int editor_el_custom[] = { EL_CUSTOM_START + 0, EL_CUSTOM_START + 1, EL_CUSTOM_START + 2, EL_CUSTOM_START + 3, EL_CUSTOM_START + 4, EL_CUSTOM_START + 5, EL_CUSTOM_START + 6, EL_CUSTOM_START + 7, EL_CUSTOM_START + 8, EL_CUSTOM_START + 9, EL_CUSTOM_START + 10, EL_CUSTOM_START + 11, EL_CUSTOM_START + 12, EL_CUSTOM_START + 13, EL_CUSTOM_START + 14, EL_CUSTOM_START + 15, EL_CUSTOM_START + 16, EL_CUSTOM_START + 17, EL_CUSTOM_START + 18, EL_CUSTOM_START + 19, EL_CUSTOM_START + 20, EL_CUSTOM_START + 21, EL_CUSTOM_START + 22, EL_CUSTOM_START + 23, EL_CUSTOM_START + 24, EL_CUSTOM_START + 25, EL_CUSTOM_START + 26, EL_CUSTOM_START + 27, EL_CUSTOM_START + 28, EL_CUSTOM_START + 29, EL_CUSTOM_START + 30, EL_CUSTOM_START + 31, EL_CUSTOM_START + 32, EL_CUSTOM_START + 33, EL_CUSTOM_START + 34, EL_CUSTOM_START + 35, EL_CUSTOM_START + 36, EL_CUSTOM_START + 37, EL_CUSTOM_START + 38, EL_CUSTOM_START + 39, EL_CUSTOM_START + 40, EL_CUSTOM_START + 41, EL_CUSTOM_START + 42, EL_CUSTOM_START + 43, EL_CUSTOM_START + 44, EL_CUSTOM_START + 45, EL_CUSTOM_START + 46, EL_CUSTOM_START + 47, EL_CUSTOM_START + 48, EL_CUSTOM_START + 49, EL_CUSTOM_START + 50, EL_CUSTOM_START + 51, EL_CUSTOM_START + 52, EL_CUSTOM_START + 53, EL_CUSTOM_START + 54, EL_CUSTOM_START + 55, EL_CUSTOM_START + 56, EL_CUSTOM_START + 57, EL_CUSTOM_START + 58, EL_CUSTOM_START + 59, EL_CUSTOM_START + 60, EL_CUSTOM_START + 61, EL_CUSTOM_START + 62, EL_CUSTOM_START + 63, EL_CUSTOM_START + 64, EL_CUSTOM_START + 65, EL_CUSTOM_START + 66, EL_CUSTOM_START + 67, EL_CUSTOM_START + 68, EL_CUSTOM_START + 69, EL_CUSTOM_START + 70, EL_CUSTOM_START + 71, EL_CUSTOM_START + 72, EL_CUSTOM_START + 73, EL_CUSTOM_START + 74, EL_CUSTOM_START + 75, EL_CUSTOM_START + 76, EL_CUSTOM_START + 77, EL_CUSTOM_START + 78, EL_CUSTOM_START + 79, EL_CUSTOM_START + 80, EL_CUSTOM_START + 81, EL_CUSTOM_START + 82, EL_CUSTOM_START + 83, EL_CUSTOM_START + 84, EL_CUSTOM_START + 85, EL_CUSTOM_START + 86, EL_CUSTOM_START + 87, EL_CUSTOM_START + 88, EL_CUSTOM_START + 89, EL_CUSTOM_START + 90, EL_CUSTOM_START + 91, EL_CUSTOM_START + 92, EL_CUSTOM_START + 93, EL_CUSTOM_START + 94, EL_CUSTOM_START + 95, EL_CUSTOM_START + 96, EL_CUSTOM_START + 97, EL_CUSTOM_START + 98, EL_CUSTOM_START + 99, EL_CUSTOM_START + 100, EL_CUSTOM_START + 101, EL_CUSTOM_START + 102, EL_CUSTOM_START + 103, EL_CUSTOM_START + 104, EL_CUSTOM_START + 105, EL_CUSTOM_START + 106, EL_CUSTOM_START + 107, EL_CUSTOM_START + 108, EL_CUSTOM_START + 109, EL_CUSTOM_START + 110, EL_CUSTOM_START + 111, EL_CUSTOM_START + 112, EL_CUSTOM_START + 113, EL_CUSTOM_START + 114, EL_CUSTOM_START + 115, EL_CUSTOM_START + 116, EL_CUSTOM_START + 117, EL_CUSTOM_START + 118, EL_CUSTOM_START + 119, EL_CUSTOM_START + 120, EL_CUSTOM_START + 121, EL_CUSTOM_START + 122, EL_CUSTOM_START + 123, EL_CUSTOM_START + 124, EL_CUSTOM_START + 125, EL_CUSTOM_START + 126, EL_CUSTOM_START + 127, EL_CUSTOM_START + 128, EL_CUSTOM_START + 129, EL_CUSTOM_START + 130, EL_CUSTOM_START + 131, EL_CUSTOM_START + 132, EL_CUSTOM_START + 133, EL_CUSTOM_START + 134, EL_CUSTOM_START + 135, EL_CUSTOM_START + 136, EL_CUSTOM_START + 137, EL_CUSTOM_START + 138, EL_CUSTOM_START + 139, EL_CUSTOM_START + 140, EL_CUSTOM_START + 141, EL_CUSTOM_START + 142, EL_CUSTOM_START + 143, EL_CUSTOM_START + 144, EL_CUSTOM_START + 145, EL_CUSTOM_START + 146, EL_CUSTOM_START + 147, EL_CUSTOM_START + 148, EL_CUSTOM_START + 149, EL_CUSTOM_START + 150, EL_CUSTOM_START + 151, EL_CUSTOM_START + 152, EL_CUSTOM_START + 153, EL_CUSTOM_START + 154, EL_CUSTOM_START + 155, EL_CUSTOM_START + 156, EL_CUSTOM_START + 157, EL_CUSTOM_START + 158, EL_CUSTOM_START + 159, EL_CUSTOM_START + 160, EL_CUSTOM_START + 161, EL_CUSTOM_START + 162, EL_CUSTOM_START + 163, EL_CUSTOM_START + 164, EL_CUSTOM_START + 165, EL_CUSTOM_START + 166, EL_CUSTOM_START + 167, EL_CUSTOM_START + 168, EL_CUSTOM_START + 169, EL_CUSTOM_START + 170, EL_CUSTOM_START + 171, EL_CUSTOM_START + 172, EL_CUSTOM_START + 173, EL_CUSTOM_START + 174, EL_CUSTOM_START + 175, EL_CUSTOM_START + 176, EL_CUSTOM_START + 177, EL_CUSTOM_START + 178, EL_CUSTOM_START + 179, EL_CUSTOM_START + 180, EL_CUSTOM_START + 181, EL_CUSTOM_START + 182, EL_CUSTOM_START + 183, EL_CUSTOM_START + 184, EL_CUSTOM_START + 185, EL_CUSTOM_START + 186, EL_CUSTOM_START + 187, EL_CUSTOM_START + 188, EL_CUSTOM_START + 189, EL_CUSTOM_START + 190, EL_CUSTOM_START + 191, EL_CUSTOM_START + 192, EL_CUSTOM_START + 193, EL_CUSTOM_START + 194, EL_CUSTOM_START + 195, EL_CUSTOM_START + 196, EL_CUSTOM_START + 197, EL_CUSTOM_START + 198, EL_CUSTOM_START + 199, EL_CUSTOM_START + 200, EL_CUSTOM_START + 201, EL_CUSTOM_START + 202, EL_CUSTOM_START + 203, EL_CUSTOM_START + 204, EL_CUSTOM_START + 205, EL_CUSTOM_START + 206, EL_CUSTOM_START + 207, EL_CUSTOM_START + 208, EL_CUSTOM_START + 209, EL_CUSTOM_START + 210, EL_CUSTOM_START + 211, EL_CUSTOM_START + 212, EL_CUSTOM_START + 213, EL_CUSTOM_START + 214, EL_CUSTOM_START + 215, EL_CUSTOM_START + 216, EL_CUSTOM_START + 217, EL_CUSTOM_START + 218, EL_CUSTOM_START + 219, EL_CUSTOM_START + 220, EL_CUSTOM_START + 221, EL_CUSTOM_START + 222, EL_CUSTOM_START + 223, EL_CUSTOM_START + 224, EL_CUSTOM_START + 225, EL_CUSTOM_START + 226, EL_CUSTOM_START + 227, EL_CUSTOM_START + 228, EL_CUSTOM_START + 229, EL_CUSTOM_START + 230, EL_CUSTOM_START + 231, EL_CUSTOM_START + 232, EL_CUSTOM_START + 233, EL_CUSTOM_START + 234, EL_CUSTOM_START + 235, EL_CUSTOM_START + 236, EL_CUSTOM_START + 237, EL_CUSTOM_START + 238, EL_CUSTOM_START + 239, EL_CUSTOM_START + 240, EL_CUSTOM_START + 241, EL_CUSTOM_START + 242, EL_CUSTOM_START + 243, EL_CUSTOM_START + 244, EL_CUSTOM_START + 245, EL_CUSTOM_START + 246, EL_CUSTOM_START + 247, EL_CUSTOM_START + 248, EL_CUSTOM_START + 249, EL_CUSTOM_START + 250, EL_CUSTOM_START + 251, EL_CUSTOM_START + 252, EL_CUSTOM_START + 253, EL_CUSTOM_START + 254, EL_CUSTOM_START + 255 }; static int *editor_hl_custom_ptr = editor_hl_custom; static int *editor_el_custom_ptr = editor_el_custom; static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom); static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom); static int editor_hl_group[] = { EL_INTERNAL_CASCADE_GE_ACTIVE, EL_CHAR('G'), EL_CHAR('E'), EL_EMPTY, }; static int editor_el_group[] = { EL_GROUP_START + 0, EL_GROUP_START + 1, EL_GROUP_START + 2, EL_GROUP_START + 3, EL_GROUP_START + 4, EL_GROUP_START + 5, EL_GROUP_START + 6, EL_GROUP_START + 7, EL_GROUP_START + 8, EL_GROUP_START + 9, EL_GROUP_START + 10, EL_GROUP_START + 11, EL_GROUP_START + 12, EL_GROUP_START + 13, EL_GROUP_START + 14, EL_GROUP_START + 15, EL_GROUP_START + 16, EL_GROUP_START + 17, EL_GROUP_START + 18, EL_GROUP_START + 19, EL_GROUP_START + 20, EL_GROUP_START + 21, EL_GROUP_START + 22, EL_GROUP_START + 23, EL_GROUP_START + 24, EL_GROUP_START + 25, EL_GROUP_START + 26, EL_GROUP_START + 27, EL_GROUP_START + 28, EL_GROUP_START + 29, EL_GROUP_START + 30, EL_GROUP_START + 31 }; static int *editor_hl_group_ptr = editor_hl_group; static int *editor_el_group_ptr = editor_el_group; static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group); static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group); static int editor_hl_reference[] = { EL_INTERNAL_CASCADE_REF_ACTIVE, EL_CHAR('R'), EL_CHAR('E'), EL_CHAR('F') }; static int editor_el_reference[] = { EL_TRIGGER_PLAYER, EL_TRIGGER_ELEMENT, EL_TRIGGER_CE_VALUE, EL_TRIGGER_CE_SCORE, EL_SELF, EL_ANY_ELEMENT, EL_CURRENT_CE_VALUE, EL_CURRENT_CE_SCORE, EL_PREV_CE_8, EL_PREV_CE_7, EL_PREV_CE_6, EL_PREV_CE_5, EL_PREV_CE_4, EL_PREV_CE_3, EL_PREV_CE_2, EL_PREV_CE_1, EL_NEXT_CE_1, EL_NEXT_CE_2, EL_NEXT_CE_3, EL_NEXT_CE_4, EL_NEXT_CE_5, EL_NEXT_CE_6, EL_NEXT_CE_7, EL_NEXT_CE_8, }; static int *editor_hl_reference_ptr = editor_hl_reference; static int *editor_el_reference_ptr = editor_el_reference; static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference); static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference); static int editor_hl_user_defined[] = { EL_INTERNAL_CASCADE_USER_ACTIVE, EL_CHAR('M'), EL_CHAR('Y'), EL_EMPTY, }; static int *editor_hl_user_defined_ptr = editor_hl_user_defined; static int *editor_el_user_defined_ptr = NULL; static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined); static int num_editor_el_user_defined = 0; static int editor_hl_dynamic[] = { EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE, EL_CHAR('U'), EL_CHAR('S'), EL_CHAR('E'), }; static int *editor_hl_dynamic_ptr = editor_hl_dynamic; static int *editor_el_dynamic_ptr = NULL; static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic); static int num_editor_el_dynamic = 0; static int editor_hl_empty[] = { }; static int editor_el_empty[ED_NUM_ELEMENTLIST_BUTTONS]; static int *editor_hl_empty_ptr = editor_hl_empty; static int *editor_el_empty_ptr = editor_el_empty; static int num_editor_hl_empty = 0; static int num_editor_el_empty = 0; /* dynamically determined, if needed */ static boolean use_el_empty = FALSE; static int *editor_elements = NULL; /* dynamically allocated */ static int num_editor_elements = 0; /* dynamically determined */ static boolean setup_editor_show_always = TRUE; static boolean setup_editor_cascade_never = FALSE; static int editor_hl_unused[] = { EL_EMPTY }; static int *editor_hl_unused_ptr = editor_hl_unused; static int num_editor_hl_unused = 0; static struct { boolean *setup_value; boolean *setup_cascade_value; int **headline_list; int *headline_list_size; int **element_list; int *element_list_size; boolean last_setup_value; } editor_elements_info[] = { { &setup_editor_show_always, &setup_editor_cascade_never, &editor_hl_unused_ptr, &num_editor_hl_unused, &editor_el_players_ptr, &num_editor_el_players }, { &setup.editor.el_boulderdash, &setup.editor_cascade.el_bd, &editor_hl_boulderdash_ptr, &num_editor_hl_boulderdash, &editor_el_boulderdash_ptr, &num_editor_el_boulderdash }, { &setup.editor.el_emerald_mine, &setup.editor_cascade.el_em, &editor_hl_emerald_mine_ptr, &num_editor_hl_emerald_mine, &editor_el_emerald_mine_ptr, &num_editor_el_emerald_mine }, { &setup.editor.el_emerald_mine_club, &setup.editor_cascade.el_emc, &editor_hl_emerald_mine_club_ptr, &num_editor_hl_emerald_mine_club, &editor_el_emerald_mine_club_ptr, &num_editor_el_emerald_mine_club }, { &setup.editor.el_more, &setup.editor_cascade.el_rnd, &editor_hl_rnd_ptr, &num_editor_hl_rnd, &editor_el_rnd_ptr, &num_editor_el_rnd }, { &setup.editor.el_sokoban, &setup.editor_cascade.el_sb, &editor_hl_sokoban_ptr, &num_editor_hl_sokoban, &editor_el_sokoban_ptr, &num_editor_el_sokoban }, { &setup.editor.el_supaplex, &setup.editor_cascade.el_sp, &editor_hl_supaplex_ptr, &num_editor_hl_supaplex, &editor_el_supaplex_ptr, &num_editor_el_supaplex }, { &setup.editor.el_diamond_caves, &setup.editor_cascade.el_dc, &editor_hl_diamond_caves_ptr, &num_editor_hl_diamond_caves, &editor_el_diamond_caves_ptr, &num_editor_el_diamond_caves }, { &setup.editor.el_dx_boulderdash, &setup.editor_cascade.el_dx, &editor_hl_dx_boulderdash_ptr, &num_editor_hl_dx_boulderdash, &editor_el_dx_boulderdash_ptr, &num_editor_el_dx_boulderdash }, { &setup.editor.el_chars, &setup.editor_cascade.el_chars, &editor_hl_chars_ptr, &num_editor_hl_chars, &editor_el_chars_ptr, &num_editor_el_chars }, { &setup.editor.el_steel_chars, &setup.editor_cascade.el_steel_chars, &editor_hl_steel_chars_ptr, &num_editor_hl_steel_chars, &editor_el_steel_chars_ptr, &num_editor_el_steel_chars }, { &setup.editor.el_custom, &setup.editor_cascade.el_ce, &editor_hl_custom_ptr, &num_editor_hl_custom, &editor_el_custom_ptr, &num_editor_el_custom }, { &setup.editor.el_custom, &setup.editor_cascade.el_ge, &editor_hl_group_ptr, &num_editor_hl_group, &editor_el_group_ptr, &num_editor_el_group }, { &setup.editor.el_custom, &setup.editor_cascade.el_ref, &editor_hl_reference_ptr, &num_editor_hl_reference, &editor_el_reference_ptr, &num_editor_el_reference }, { &setup.editor.el_user_defined, &setup.editor_cascade.el_user, &editor_hl_user_defined_ptr, &num_editor_hl_user_defined, &editor_el_user_defined_ptr, &num_editor_el_user_defined }, { &setup.editor.el_dynamic, &setup.editor_cascade.el_dynamic, &editor_hl_dynamic_ptr, &num_editor_hl_dynamic, &editor_el_dynamic_ptr, &num_editor_el_dynamic, }, { &use_el_empty, &use_el_empty, &editor_hl_empty_ptr, &num_editor_hl_empty, &editor_el_empty_ptr, &num_editor_el_empty, }, { NULL, NULL, NULL, NULL, NULL, NULL } }; /* ----------------------------------------------------------------------------- functions ----------------------------------------------------------------------------- */ static int getMaxInfoTextLength() { return (SXSIZE / getFontWidth(FONT_TEXT_2)); } static int getTextWidthForGadget(char *text) { if (text == NULL) return 0; return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE); } static int getTextWidthForDrawingArea(char *text) { if (text == NULL) return 0; return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE); } static int getRightGadgetBorder(struct GadgetInfo *gi, char *text) { return (gi->x + gi->width + getTextWidthForGadget(text)); } static char *getElementInfoText(int element) { char *info_text = NULL; if (element < MAX_NUM_ELEMENTS) { if (strlen(element_info[element].description) > 0) info_text = element_info[element].description; else if (element_info[element].custom_description != NULL) info_text = element_info[element].custom_description; else if (element_info[element].editor_description != NULL) info_text = element_info[element].editor_description; } if (info_text == NULL) info_text = INFOTEXT_UNKNOWN_ELEMENT; return info_text; } char *getElementDescriptionFilename(int element) { char *docs_dir = options.docs_directory; char *elements_subdir = "elements"; static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); /* 1st try: look for element description file for exactly this element */ sprintf(basename, "%s.txt", element_info[element].token_name); filename = getPath3(docs_dir, elements_subdir, basename); if (fileExists(filename)) return filename; free(filename); /* 2nd try: look for element description file for this element's class */ sprintf(basename, "%s.txt", element_info[element].class_name); filename = getPath3(docs_dir, elements_subdir, basename); if (fileExists(filename)) return filename; return NULL; } static void InitDynamicEditorElementList(int **elements, int *num_elements) { boolean element_found[NUM_FILE_ELEMENTS]; int i, x, y; /* initialize list of used elements to "not used" */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) element_found[i] = FALSE; /* find all elements used in current level */ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] < NUM_FILE_ELEMENTS) /* should always be true */ element_found[Feld[x][y]] = TRUE; *num_elements = 0; /* count number of elements used in current level */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i]) (*num_elements)++; /* add space for up to 3 more elements for padding that may be needed */ *num_elements += 3; /* free memory for old list of elements, if needed */ checked_free(*elements); /* allocate memory for new list of elements */ *elements = checked_malloc(*num_elements * sizeof(int)); *num_elements = 0; /* add all elements used in current level (non-custom/group elements) */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i))) (*elements)[(*num_elements)++] = i; /* add all elements used in current level (custom/group elements) */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i))) (*elements)[(*num_elements)++] = i; while (*num_elements % 4) /* pad with empty elements, if needed */ (*elements)[(*num_elements)++] = EL_EMPTY; } static void ReinitializeElementList() { static boolean initialization_needed = TRUE; int pos = 0; int i, j; if (initialization_needed) { LoadSetup_EditorCascade(); /* load last editor cascade state */ /* initialize editor cascade element from saved cascade state */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { int *cascade_element = &(*editor_elements_info[i].headline_list)[0]; boolean cascade_value = *editor_elements_info[i].setup_cascade_value; if (IS_EDITOR_CASCADE(*cascade_element)) *cascade_element = (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) : EL_CASCADE_INACTIVE(*cascade_element)); } initialization_needed = FALSE; } checked_free(editor_elements); /* reload optional user defined element list for each invocation of editor */ LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr, &num_editor_el_user_defined); /* initialize dynamic level element list for each invocation of editor */ InitDynamicEditorElementList(&editor_el_dynamic_ptr, &num_editor_el_dynamic); /* initialize list of empty elements (used for padding, if needed) */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) editor_el_empty[i] = EL_EMPTY; /* do some sanity checks for each element from element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { for (j = 0; j < *editor_elements_info[i].element_list_size; j++) { int element = (*editor_elements_info[i].element_list)[j]; if (element >= NUM_FILE_ELEMENTS) Error(ERR_WARN, "editor element %d is runtime element", element); if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT)) Error(ERR_WARN, "no element description for element %d", element); } } num_editor_elements = 0; use_el_empty = FALSE; /* determine size of element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { boolean found_inactive_cascade = FALSE; if (*editor_elements_info[i].setup_value) { if (setup.editor.el_headlines) { num_editor_elements += *editor_elements_info[i].headline_list_size; for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { int element = (*editor_elements_info[i].headline_list)[j]; if (IS_EDITOR_CASCADE_INACTIVE(element)) found_inactive_cascade = TRUE; } } if (found_inactive_cascade) continue; num_editor_elements += *editor_elements_info[i].element_list_size; } } if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS) { /* offer at least as many elements as element buttons exist */ use_el_empty = TRUE; num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements; num_editor_elements += num_editor_el_empty; } editor_elements = checked_malloc(num_editor_elements * sizeof(int)); /* fill element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { boolean found_inactive_cascade = FALSE; if (*editor_elements_info[i].setup_value) { if (setup.editor.el_headlines) { for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { int element = (*editor_elements_info[i].headline_list)[j]; editor_elements[pos++] = element; if (IS_EDITOR_CASCADE_INACTIVE(element)) found_inactive_cascade = TRUE; } } if (found_inactive_cascade) continue; for (j = 0; j < *editor_elements_info[i].element_list_size; j++) editor_elements[pos++] = (*editor_elements_info[i].element_list)[j]; } } /* (this function is also called before editor gadgets are initialized!) */ AdjustElementListScrollbar(); } void PrintEditorElementList() { boolean *stop = &setup.editor.el_user_defined; int i, j; for (i = 0; editor_elements_info[i].setup_value != stop; i++) { int cascade_element = (*editor_elements_info[i].headline_list)[0]; if (IS_EDITOR_CASCADE(cascade_element)) { int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element); char *headline = element_info[cascade_element_show].editor_description; printf_line_with_prefix("# ", "-", 77); printf("# %s\n", headline); printf_line_with_prefix("# ", "-", 77); } for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { int element = (*editor_elements_info[i].headline_list)[j]; if (IS_EDITOR_CASCADE(element)) element = EL_CHAR_MINUS; printf("# %s\n", element_info[element].token_name); } if (j > 0) printf("#\n"); for (j = 0; j < *editor_elements_info[i].element_list_size; j++) { int element = (*editor_elements_info[i].element_list)[j]; printf("# %s\n", element_info[element].token_name); } if (j > 0) printf("#\n"); } } static void ReinitializeElementListButtons() { static boolean last_setup_value_headlines = FALSE; static boolean initialization_needed = TRUE; int i; if (!initialization_needed) /* check if editor element setup has changed */ { if (last_setup_value_headlines != setup.editor.el_headlines) initialization_needed = TRUE; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) if (editor_elements_info[i].last_setup_value != *editor_elements_info[i].setup_value) initialization_needed = TRUE; } if (!initialization_needed) return; FreeLevelEditorGadgets(); CreateLevelEditorGadgets(); /* store current setup values for next invocation of this function */ last_setup_value_headlines = setup.editor.el_headlines; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) editor_elements_info[i].last_setup_value = *editor_elements_info[i].setup_value; initialization_needed = FALSE; } static void DrawElementBorder(int dest_x, int dest_y, int width, int height, boolean input) { int border_graphic = (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER); Bitmap *src_bitmap; int src_x, src_y; int bx = (input ? 4 : 8); int by = (input ? 4 : 8); int bx2 = TILEX - bx; int by2 = TILEY - by; int i; getGraphicSource(border_graphic, 0, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, drawto, src_x, src_y, bx, by, dest_x - bx, dest_y - by); BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y, bx, by, dest_x + width, dest_y - by); BlitBitmap(src_bitmap, drawto, src_x, src_y + by2, bx, by, dest_x - bx, dest_y + height); BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by2, bx, by, dest_x + width, dest_y + height); for (i = 0; i < width / MINI_TILEX; i++) { BlitBitmap(src_bitmap, drawto, src_x + bx, src_y, MINI_TILEX, by, dest_x + i * MINI_TILEX, dest_y - by); BlitBitmap(src_bitmap, drawto, src_x + bx, src_y + by2, MINI_TILEX, by, dest_x + i * MINI_TILEX, dest_y + height); } for (i = 0; i < height / MINI_TILEY; i++) { BlitBitmap(src_bitmap, drawto, src_x, src_y + by, bx, MINI_TILEY, dest_x - bx, dest_y + i * MINI_TILEY); BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by, bx, MINI_TILEY, dest_x + width, dest_y + i * MINI_TILEY); } ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2); } static void DrawDrawingArea(int id) { struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x, y; int *value = drawingarea_info[id].value; int area_xsize = drawingarea_info[id].area_xsize; int area_ysize = drawingarea_info[id].area_ysize; for (x = 0; x < area_xsize; x++) for (y = 0; y < area_ysize; y++) DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY, el2edimg(value[x * area_ysize + y])); } 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); BlitBitmap(drawto, drawto, SX + (dx == -1 ? MINI_TILEX : 0), SY + (dy == -1 ? MINI_TILEY : 0), (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0), (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0), SX + (dx == +1 ? MINI_TILEX : 0), SY + (dy == +1 ? MINI_TILEY : 0)); if (dx) { x = (dx == 1 ? 0 : ed_fieldx - 1); for (y = 0; y < ed_fieldy; y++) DrawMiniElementOrWall(x, y, from_x, from_y); } else if (dy) { y = (dy == 1 ? 0 : ed_fieldy - 1); for (x = 0; x < ed_fieldx; x++) DrawMiniElementOrWall(x, y, from_x, from_y); } redraw_mask |= REDRAW_FIELD; BackToFront(); } static void CreateControlButtons() { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; unsigned long event_mask; int i; /* create toolbox buttons */ for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) { int id = i; int width, height; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y1, gd_y2; int button_type; int radio_button_nr; boolean checked; if (id == GADGET_ID_SINGLE_ITEMS || id == GADGET_ID_CONNECTED_ITEMS || id == GADGET_ID_LINE || id == GADGET_ID_ARC || id == GADGET_ID_TEXT || id == GADGET_ID_RECTANGLE || id == GADGET_ID_FILLED_BOX || id == GADGET_ID_FLOOD_FILL || id == GADGET_ID_GRAB_BRUSH || id == GADGET_ID_PICK_ELEMENT || id == GADGET_ID_CUSTOM_COPY_FROM || id == GADGET_ID_CUSTOM_COPY_TO || id == GADGET_ID_CUSTOM_EXCHANGE) { button_type = GD_TYPE_RADIO_BUTTON; radio_button_nr = RADIO_NR_DRAWING_TOOLBOX; checked = (id == drawing_function ? TRUE : FALSE); event_mask = GD_EVENT_PRESSED; } else { button_type = GD_TYPE_NORMAL_BUTTON; radio_button_nr = RADIO_NR_NONE; checked = FALSE; if (id == GADGET_ID_WRAP_LEFT || id == GADGET_ID_WRAP_RIGHT || id == GADGET_ID_WRAP_UP || id == GADGET_ID_WRAP_DOWN) event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; else event_mask = GD_EVENT_RELEASED; } if (id < ED_NUM_CTRL1_BUTTONS) { int x = i % ED_CTRL1_BUTTONS_HORIZ; int y = i / ED_CTRL1_BUTTONS_HORIZ; gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE; gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE; width = ED_CTRL1_BUTTON_XSIZE; height = ED_CTRL1_BUTTON_YSIZE; gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset; gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_GFX_YPOS + gd_yoffset; gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_ALT_GFX_YPOS + gd_yoffset; } else if (id < ED_NUM_CTRL1_2_BUTTONS) { int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ; int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ; gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE; gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE; width = ED_CTRL2_BUTTON_XSIZE; height = ED_CTRL2_BUTTON_YSIZE; gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset; gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL2_BUTTONS_GFX_YPOS + gd_yoffset; gd_y2 = 0; /* no alternative graphic for these buttons */ } else if (id < ED_NUM_CTRL1_3_BUTTONS) { int x = (i - ED_NUM_CTRL1_2_BUTTONS) % ED_CTRL3_BUTTONS_HORIZ + 1; int y = (i - ED_NUM_CTRL1_2_BUTTONS) / ED_CTRL3_BUTTONS_HORIZ; gd_xoffset = ED_CTRL3_BUTTONS_XPOS + x * ED_CTRL3_BUTTON_XSIZE; gd_yoffset = ED_CTRL3_BUTTONS_YPOS + y * ED_CTRL3_BUTTON_YSIZE; width = ED_CTRL3_BUTTON_XSIZE; height = ED_CTRL3_BUTTON_YSIZE; gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset; gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_GFX_YPOS + gd_yoffset; gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_ALT_GFX_YPOS + gd_yoffset; } else { int x = (i - ED_NUM_CTRL1_3_BUTTONS) % ED_CTRL4_BUTTONS_HORIZ; int y = (i - ED_NUM_CTRL1_3_BUTTONS) / ED_CTRL4_BUTTONS_HORIZ + 3; gd_xoffset = ED_CTRL4_BUTTONS_XPOS + x * ED_CTRL4_BUTTON_XSIZE; gd_yoffset = ED_CTRL4_BUTTONS_YPOS + y * ED_CTRL4_BUTTON_YSIZE; width = ED_CTRL4_BUTTON_XSIZE; height = ED_CTRL4_BUTTON_YSIZE; gd_x1 = DOOR_GFX_PAGEX6 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX5 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset; gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL4_BUTTONS_GFX_YPOS + gd_yoffset; gd_y2 = 0; /* no alternative graphic for these buttons */ } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, control_info[i].text, GDI_X, EX + gd_xoffset, GDI_Y, EY + gd_yoffset, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, button_type, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_RADIO_NR, radio_button_nr, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1, GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2, GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } /* these values are not constant, but can change at runtime */ scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_UP].x = ED_SCROLL_UP_XPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_UP].y = ED_SCROLL_UP_YPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].x = ED_SCROLL_DOWN_XPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y = ED_SCROLL_DOWN_YPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_LEFT].x = ED_SCROLL_LEFT_XPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_LEFT].y = ED_SCROLL_LEFT_YPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS; scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS; /* create buttons for scrolling of drawing area and element list */ for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++) { int id = scrollbutton_info[i].gadget_id; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; x = scrollbutton_info[i].x; y = scrollbutton_info[i].y; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; if (id == GADGET_ID_SCROLL_LIST_UP || id == GADGET_ID_SCROLL_LIST_DOWN) { x += DX; y += DY; width = ED_SCROLLBUTTON2_XSIZE; height = ED_SCROLLBUTTON2_YSIZE; gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x; gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y; gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE; gd_y2 = gd_y1; } else { x += SX; y += SY; width = ED_SCROLLBUTTON_XSIZE; height = ED_SCROLLBUTTON_YSIZE; gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x; gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y; gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE; gd_y2 = gd_y1; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } /* create buttons for element list */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) { Bitmap *deco_bitmap; int deco_x, deco_y, deco_xpos, deco_ypos; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y; int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ; int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ; int id = GADGET_ID_ELEMENTLIST_FIRST + i; int element = editor_elements[i]; event_mask = GD_EVENT_RELEASED; gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE; gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE; gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE; gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS; getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y); deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2; deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, getElementInfoText(element), GDI_X, DX + gd_xoffset, GDI_Y, DY + gd_yoffset, GDI_WIDTH, ED_ELEMENTLIST_XSIZE, GDI_HEIGHT, ED_ELEMENTLIST_YSIZE, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_DECORATION_POSITION, deco_xpos, deco_ypos, GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY, GDI_DECORATION_SHIFTING, 1, 1, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateCounterButtons() { int max_infotext_len = getMaxInfoTextLength(); int i; /* these values are not constant, but can change at runtime */ counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].x = DX + 5 - SX; counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].y = DY + 3 - SY; for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++) { int j; int x = SX + counterbutton_info[i].x; /* down count button */ int y = SY + counterbutton_info[i].y; /* determine horizontal position to the right of specified gadget */ if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[counterbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (counterbutton_info[i].text_left != NULL) x += getTextWidthForGadget(counterbutton_info[i].text_left); for (j = 0; j < 2; j++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; int id = (j == 0 ? counterbutton_info[i].gadget_id_down : counterbutton_info[i].gadget_id_up); int gd_xoffset; int gd_x, gd_x1, gd_x2, gd_y; int x_size, y_size; unsigned long event_mask; char infotext[max_infotext_len + 1]; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; if (i == ED_COUNTER_ID_SELECT_LEVEL) { int sid = (j == 0 ? ED_SCROLLBUTTON_ID_AREA_LEFT : ED_SCROLLBUTTON_ID_AREA_RIGHT); event_mask |= GD_EVENT_RELEASED; if (j == 1) x += 2 * ED_GADGET_DISTANCE; y += ED_GADGET_DISTANCE; gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].gd_x; gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE; gd_y = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].gd_y; x_size = ED_SCROLLBUTTON_XSIZE; y_size = ED_SCROLLBUTTON_YSIZE; } else { gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS); gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset; gd_y = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS; x_size = ED_BUTTON_COUNT_XSIZE; y_size = ED_BUTTON_COUNT_YSIZE; } sprintf(infotext, "%s counter value by 1, 5 or 10", (j == 0 ? "decrease" : "increase")); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, x_size, GDI_HEIGHT, y_size, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCounterButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, counterbutton_info[i].text_right); x += gi->width + ED_GADGET_DISTANCE; /* text count button */ if (j == 0) { int font_type = FONT_INPUT_1; int font_type_active = FONT_INPUT_1_ACTIVE; int gd_width = ED_WIN_COUNT_XSIZE; id = counterbutton_info[i].gadget_id_text; event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; if (i == ED_COUNTER_ID_SELECT_LEVEL) { font_type = FONT_LEVEL_NUMBER; #if 1 font_type_active = FONT_LEVEL_NUMBER_ACTIVE; #else font_type_active = FONT_LEVEL_NUMBER; #endif x += 2 * ED_GADGET_DISTANCE; y -= ED_GADGET_DISTANCE; gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS; gd_width = ED_WIN_COUNT2_XSIZE; } else { gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, "enter counter value", GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC, GDI_NUMBER_VALUE, 0, GDI_NUMBER_MIN, counterbutton_info[i].min_value, GDI_NUMBER_MAX, counterbutton_info[i].max_value, GDI_TEXT_SIZE, 3, /* minimal counter text size */ GDI_TEXT_FONT, font_type, GDI_TEXT_FONT_ACTIVE, font_type_active, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y, GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE, GDI_DESIGN_WIDTH, gd_width, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCounterButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, counterbutton_info[i].text_right); x += gi->width + ED_GADGET_DISTANCE; /* up count button */ } } } } static void CreateDrawingAreas() { int i; /* these values are not constant, but can change at runtime */ drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX; drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY; for (i = 0; i < ED_NUM_DRAWING_AREAS; i++) { struct GadgetInfo *gi; unsigned long event_mask; int id = drawingarea_info[i].gadget_id; int x = SX + drawingarea_info[i].x; int y = SY + drawingarea_info[i].y; int area_xsize = drawingarea_info[i].area_xsize; int area_ysize = drawingarea_info[i].area_ysize; event_mask = GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; /* determine horizontal position to the right of specified gadget */ if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[drawingarea_info[i].gadget_id_align] + ED_DRAWINGAREA_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (drawingarea_info[i].text_left != NULL) x += getTextWidthForDrawingArea(drawingarea_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_DRAWING_AREA, GDI_AREA_SIZE, area_xsize, area_ysize, GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleDrawingAreaInfo, GDI_CALLBACK_ACTION, HandleDrawingAreas, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, drawingarea_info[i].text_right); } } static void CreateTextInputGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTINPUT; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int gd_x, gd_y; struct GadgetInfo *gi; unsigned long event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = textinput_info[i].gadget_id; event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS; sprintf(infotext, "Enter %s", textinput_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, SX + textinput_info[i].x, GDI_Y, SY + textinput_info[i].y, GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC, GDI_TEXT_VALUE, textinput_info[i].value, GDI_TEXT_SIZE, textinput_info[i].size, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y, GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE, GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextInputGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateTextAreaGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTAREAS; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int gd_x, gd_y; struct GadgetInfo *gi; unsigned long event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = textarea_info[i].gadget_id; int area_xsize = textarea_info[i].xsize; int area_ysize = textarea_info[i].ysize; event_mask = GD_EVENT_TEXT_LEAVING; gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS; sprintf(infotext, "Enter %s", textarea_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, SX + textarea_info[i].x, GDI_Y, SY + textarea_info[i].y, GDI_TYPE, GD_TYPE_TEXT_AREA, GDI_AREA_SIZE, area_xsize, area_ysize, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y, GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE, GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextAreaGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateSelectboxGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i, j; for (i = 0; i < ED_NUM_SELECTBOX; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int gd_x, gd_y; struct GadgetInfo *gi; unsigned long event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = selectbox_info[i].gadget_id; int x = SX + selectbox_info[i].x; int y = SY + selectbox_info[i].y; if (selectbox_info[i].size == -1) /* dynamically determine size */ { /* (we cannot use -1 for uninitialized values if we directly compare with results from strlen(), because the '<' and '>' operation will implicitely cast -1 to an unsigned integer value!) */ selectbox_info[i].size = 0; for (j = 0; selectbox_info[i].options[j].text != NULL; j++) if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size) selectbox_info[i].size = strlen(selectbox_info[i].options[j].text); selectbox_info[i].size++; /* add one character empty space */ } event_mask = GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS; /* determine horizontal position to the right of specified gadget */ if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[selectbox_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (selectbox_info[i].text_left != NULL) x += getTextWidthForGadget(selectbox_info[i].text_left); sprintf(infotext, "Select %s", selectbox_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_SELECTBOX, GDI_SELECTBOX_OPTIONS, selectbox_info[i].options, GDI_TEXT_SIZE, selectbox_info[i].size, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y, GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE, GDI_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE, GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleSelectboxGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, selectbox_info[i].text_right); } } static void CreateTextbuttonGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTBUTTONS; i++) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int gd_x1, gd_x2, gd_y1, gd_y2; struct GadgetInfo *gi; unsigned long event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = textbutton_info[i].gadget_id; int x = SX + textbutton_info[i].x; int y = SY + textbutton_info[i].y; if (textbutton_info[i].size == -1) /* dynamically determine size */ textbutton_info[i].size = strlen(textbutton_info[i].text); event_mask = GD_EVENT_RELEASED; if ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) || (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE)) { gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS; gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS; gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS; gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS; } else { gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS; gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS; gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS; gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS; } sprintf(infotext, "%s", textbutton_info[i].infotext); infotext[max_infotext_len] = '\0'; /* determine horizontal position to the right of specified gadget */ if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[textbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (textbutton_info[i].text_left != NULL) x += getTextWidthForGadget(textbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_TEXT_BUTTON, GDI_TEXT_VALUE, textbutton_info[i].text, GDI_TEXT_SIZE, textbutton_info[i].size, GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1, GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2, GDI_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE, GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE, GDI_DECORATION_SHIFTING, 1, 1, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextbuttonGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, textbutton_info[i].text_right); } } static void CreateGraphicbuttonGadgets() { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; unsigned long event_mask; int i; /* create buttons for scrolling of drawing area and element list */ for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++) { int id = graphicbutton_info[i].gadget_id; int gd_x1, gd_x2, gd_y1, gd_y2; int x = SX + graphicbutton_info[i].x; int y = SY + graphicbutton_info[i].y; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; if (i <= ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE) { gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x; gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y; gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x; gd_y2 = gd_y1; } else /* (i <= ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) */ { gd_x1 = DOOR_GFX_PAGEX6 + graphicbutton_info[i].gd_x; gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y; gd_x2 = gd_x1 - ED_BUTTON_COUNT_XSIZE; gd_y2 = gd_y1; } /* determine horizontal position to the right of specified gadget */ if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (graphicbutton_info[i].text_left != NULL) x += getTextWidthForGadget(graphicbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, graphicbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, graphicbutton_info[i].width, GDI_HEIGHT, graphicbutton_info[i].height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, graphicbutton_info[i].text_right); } } static void CreateScrollbarGadgets() { int i; /* these values are not constant, but can change at runtime */ scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x = SX + ED_SCROLL_HORIZONTAL_XPOS; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y = SY + ED_SCROLL_HORIZONTAL_YPOS; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width = ED_SCROLL_HORIZONTAL_XSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height = ED_SCROLL_HORIZONTAL_YSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x = SX; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y = SY; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width = SXSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].x = SX + ED_SCROLL_VERTICAL_XPOS; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].y = SY + ED_SCROLL_VERTICAL_YPOS; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].width = ED_SCROLL_VERTICAL_XSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height = ED_SCROLL_VERTICAL_YSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x = SX; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y = SY; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width = SXSIZE; scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE; scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].x = DX + ED_SCROLL2_VERTICAL_XPOS; scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].y = DY + ED_SCROLL2_VERTICAL_YPOS; scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX; scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY; for (i = 0; i < ED_NUM_SCROLLBARS; i++) { int id = scrollbar_info[i].gadget_id; Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int gd_x1, gd_x2, gd_y1, gd_y2; struct GadgetInfo *gi; int items_max, items_visible, item_position; unsigned long event_mask; if (i == ED_SCROLLBAR_ID_LIST_VERTICAL) { items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ; items_visible = ED_ELEMENTLIST_BUTTONS_VERT; item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ; } else /* drawing area scrollbars */ { if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL) { items_max = MAX(lev_fieldx + 2, ed_fieldx); items_visible = ed_fieldx; item_position = 0; } else { items_max = MAX(lev_fieldy + 2, ed_fieldy); items_visible = ed_fieldy; item_position = 0; } } event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].gd_x; gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ? scrollbar_info[i].height : scrollbar_info[i].width)); gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y; gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbar_info[i].infotext, GDI_X, scrollbar_info[i].x, GDI_Y, scrollbar_info[i].y, GDI_WIDTH, scrollbar_info[i].width, GDI_HEIGHT, scrollbar_info[i].height, GDI_TYPE, scrollbar_info[i].type, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_WHEEL_AREA_X, scrollbar_info[i].wheel_x, GDI_WHEEL_AREA_Y, scrollbar_info[i].wheel_y, GDI_WHEEL_AREA_WIDTH, scrollbar_info[i].wheel_width, GDI_WHEEL_AREA_HEIGHT, scrollbar_info[i].wheel_height, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateCheckbuttonGadgets() { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; unsigned long event_mask; int gd_x1, gd_x2, gd_x3, gd_x4, gd_y; int i; event_mask = GD_EVENT_PRESSED; gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS; gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS; gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS; gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS; for (i = 0; i < ED_NUM_CHECKBUTTONS; i++) { int id = checkbutton_info[i].gadget_id; int x = SX + checkbutton_info[i].x; int y = SY + checkbutton_info[i].y; if (id == GADGET_ID_STICK_ELEMENT) gd_y = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS; else gd_y = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS; /* determine horizontal position to the right of specified gadget */ if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[checkbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (checkbutton_info[i].text_left != NULL) x += getTextWidthForGadget(checkbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, checkbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, ED_CHECKBUTTON_XSIZE, GDI_HEIGHT, ED_CHECKBUTTON_YSIZE, GDI_TYPE, GD_TYPE_CHECK_BUTTON, GDI_CHECKED, *checkbutton_info[i].value, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y, GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCheckbuttons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, checkbutton_info[i].text_right); } } static void CreateRadiobuttonGadgets() { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; struct GadgetInfo *gi; unsigned long event_mask; int gd_x1, gd_x2, gd_x3, gd_x4, gd_y; int i; event_mask = GD_EVENT_PRESSED; gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS; gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS; gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS; gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS; gd_y = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS; for (i = 0; i < ED_NUM_RADIOBUTTONS; i++) { int id = radiobutton_info[i].gadget_id; int x = SX + radiobutton_info[i].x; int y = SY + radiobutton_info[i].y; int checked = (*radiobutton_info[i].value == radiobutton_info[i].checked_value); /* determine horizontal position to the right of specified gadget */ if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[radiobutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (radiobutton_info[i].text_left != NULL) x += getTextWidthForGadget(radiobutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, radiobutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, ED_CHECKBUTTON_XSIZE, GDI_HEIGHT, ED_CHECKBUTTON_YSIZE, GDI_TYPE, GD_TYPE_RADIO_BUTTON, GDI_RADIO_NR, radiobutton_info[i].radio_button_nr, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y, GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y, GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleRadiobuttons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, radiobutton_info[i].text_right); } } void CreateLevelEditorGadgets() { int old_game_status = game_status; /* setting 'game_status' is needed to get the right fonts for the editor */ game_status = GAME_MODE_EDITOR; /* these values are not constant, but can change at runtime */ ed_fieldx = MAX_ED_FIELDX - 1; ed_fieldy = MAX_ED_FIELDY - 1; ReinitializeElementList(); CreateControlButtons(); CreateScrollbarGadgets(); /* order of function calls is important because of cross-references */ CreateCheckbuttonGadgets(); CreateCounterButtons(); CreateRadiobuttonGadgets(); CreateTextInputGadgets(); CreateTextAreaGadgets(); CreateSelectboxGadgets(); CreateGraphicbuttonGadgets(); CreateTextbuttonGadgets(); CreateDrawingAreas(); game_status = old_game_status; } void FreeLevelEditorGadgets() { int i; for (i = 0; i < NUM_EDITOR_GADGETS; i++) { FreeGadget(level_editor_gadget[i]); level_editor_gadget[i] = NULL; } } static void MapCounterButtons(int id) { int gadget_id_down = counterbutton_info[id].gadget_id_down; int gadget_id_text = counterbutton_info[id].gadget_id_text; int gadget_id_up = counterbutton_info[id].gadget_id_up; struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down]; struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text]; struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up]; int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset_above = MINI_TILEX + ED_GADGET_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi_down->x - xoffset_left; int x_right; /* set after gadget position was modified */ int y_above = gi_down->y - yoffset_above; int x = gi_down->x; int y; /* set after gadget position was modified */ /* counter limits must be changed first to prevent value truncation */ ModifyEditorCounterLimits(id, counterbutton_info[id].min_value, counterbutton_info[id].max_value); /* right text position might have changed after setting position above */ x_right = gi_up->x + gi_up->width + xoffset_right; ModifyEditorCounterValue(id, *counterbutton_info[id].value); /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */ if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 && id <= ED_COUNTER_ID_ELEMENT_VALUE4) { ModifyGadget(gi_down, GDI_Y, SY + counterbutton_info[id].y, GDI_END); ModifyGadget(gi_text, GDI_Y, SY + counterbutton_info[id].y, GDI_END); ModifyGadget(gi_up, GDI_Y, SY + counterbutton_info[id].y, GDI_END); } /* vertical position might have changed after setting position above */ y = gi_up->y + yoffset; if (counterbutton_info[id].text_above) DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1); if (counterbutton_info[id].text_left) DrawText(x_left, y, counterbutton_info[id].text_left, FONT_TEXT_1); if (counterbutton_info[id].text_right) DrawText(x_right, y, counterbutton_info[id].text_right, FONT_TEXT_1); MapGadget(gi_down); MapGadget(gi_text); MapGadget(gi_up); } static void MapControlButtons() { int counter_id; int i; /* map toolbox buttons (excluding special CE toolbox buttons) */ for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++) MapGadget(level_editor_gadget[i]); /* map buttons to select elements */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]); /* map buttons to select level */ counter_id = ED_COUNTER_ID_SELECT_LEVEL; counterbutton_info[counter_id].min_value = leveldir_current->first_level; counterbutton_info[counter_id].max_value = leveldir_current->last_level; MapCounterButtons(counter_id); } static void MapDrawingArea(int id) { struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int area_xsize = gi->drawing.area_xsize; int area_ysize = gi->drawing.area_ysize; int xoffset_left= getTextWidthForDrawingArea(drawingarea_info[id].text_left); int xoffset_below= getTextWidth(drawingarea_info[id].text_below,FONT_TEXT_1); int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE; int x_below = gi->x + (gi->width - xoffset_below) / 2; int y_side = gi->y + (gi->height - getFontHeight(FONT_TEXT_1)) / 2; int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE; if (drawingarea_info[id].text_left) DrawText(x_left, y_side, drawingarea_info[id].text_left, FONT_TEXT_1); if (drawingarea_info[id].text_right) DrawText(x_right, y_side, drawingarea_info[id].text_right, FONT_TEXT_1); if (drawingarea_info[id].text_below) DrawText(x_below, y_below, drawingarea_info[id].text_below, FONT_TEXT_1); if (id != ED_DRAWING_ID_DRAWING_LEVEL) { DrawElementBorder(gi->x, gi->y, area_xsize * MINI_TILEX, area_ysize * MINI_TILEY, TRUE); DrawDrawingArea(id); } MapGadget(gi); } static void MapTextInputGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id]; int xoffset_above = 0; int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE); int x_above = textinput_info[id].x + xoffset_above; int y_above = textinput_info[id].y + yoffset_above; if (textinput_info[id].text_above) DrawTextS(x_above, y_above, FONT_TEXT_1, textinput_info[id].text_above); ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END); MapGadget(gi); } static void MapTextAreaGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id]; int xoffset_above = 0; int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE); int x_above = textarea_info[id].x + xoffset_above; int y_above = textarea_info[id].y + yoffset_above; if (textarea_info[id].text_above) DrawTextS(x_above, y_above, FONT_TEXT_1, textarea_info[id].text_above); ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END); MapGadget(gi); } static void MapSelectboxGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; if (selectbox_info[id].text_left) DrawText(x_left, y, selectbox_info[id].text_left, FONT_TEXT_1); if (selectbox_info[id].text_right) DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1); ModifyEditorSelectboxValue(id, *selectbox_info[id].value); MapGadget(gi); } static void MapTextbuttonGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; /* only show button to delete change pages when more than minimum pages */ if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && custom_element.num_change_pages == MIN_CHANGE_PAGES) return; if (textbutton_info[id].text_left) DrawText(x_left, y, textbutton_info[id].text_left, FONT_TEXT_1); if (textbutton_info[id].text_right) DrawText(x_right, y, textbutton_info[id].text_right, FONT_TEXT_1); MapGadget(gi); } static void MapGraphicbuttonGadget(int id) { struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; if (graphicbutton_info[id].text_left) DrawText(x_left, y, graphicbutton_info[id].text_left, FONT_TEXT_1); if (graphicbutton_info[id].text_right) DrawText(x_right, y, graphicbutton_info[id].text_right, FONT_TEXT_1); MapGadget(gi); } static void MapRadiobuttonGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; boolean checked = (*radiobutton_info[id].value == radiobutton_info[id].checked_value); if (radiobutton_info[id].text_left) DrawText(x_left, y, radiobutton_info[id].text_left, FONT_TEXT_1); if (radiobutton_info[id].text_right) DrawText(x_right, y, radiobutton_info[id].text_right, FONT_TEXT_1); ModifyGadget(gi, GDI_CHECKED, checked, GDI_END); MapGadget(gi); } static void MapCheckbuttonGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left, x_right, y; /* set after gadget position was modified */ /* set position for gadgets with dynamically determined position */ if (checkbutton_info[id].x != -1) /* do not change dynamic positions */ ModifyGadget(gi, GDI_X, SX + checkbutton_info[id].x, GDI_END); ModifyGadget(gi, GDI_Y, SY + checkbutton_info[id].y, GDI_END); x_left = gi->x - xoffset_left; x_right = gi->x + gi->width + xoffset_right; y = gi->y + yoffset; if (checkbutton_info[id].text_left) DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1); if (checkbutton_info[id].text_right) DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1); ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END); MapGadget(gi); } static void MapMainDrawingArea() { boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx); boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy); int i; for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++) { if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT || i == ED_SCROLLBUTTON_ID_AREA_RIGHT) && no_horizontal_scrollbar) || ((i == ED_SCROLLBUTTON_ID_AREA_UP || i == ED_SCROLLBUTTON_ID_AREA_DOWN) && no_vertical_scrollbar)) continue; MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]); } for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++) { if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) || (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar)) continue; MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]); } MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL); } static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map) { int i; for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) { if (i == GADGET_ID_CUSTOM_COPY_FROM || i == GADGET_ID_CUSTOM_COPY_TO || i == GADGET_ID_CUSTOM_EXCHANGE || i == GADGET_ID_CUSTOM_COPY || i == GADGET_ID_CUSTOM_PASTE) { if (map) MapGadget(level_editor_gadget[i]); else UnmapGadget(level_editor_gadget[i]); } } } static void MapLevelEditorToolboxCustomGadgets() { MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE); } static void UnmapLevelEditorToolboxCustomGadgets() { MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE); } static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map) { Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; int i; for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++) { if (i != GADGET_ID_SINGLE_ITEMS && i != GADGET_ID_PROPERTIES && i != GADGET_ID_PICK_ELEMENT) { struct GadgetInfo *gi = level_editor_gadget[i]; if (map) MapGadget(gi); else { UnmapGadget(gi); BlitBitmap(gd_bitmap, drawto, DOOR_GFX_PAGEX6 + ED_CTRL_NO_BUTTONS_GFX_XPOS, DOOR_GFX_PAGEY1 + ED_CTRL_NO_BUTTONS_GFX_YPOS, gi->width, gi->height, gi->x, gi->y); redraw_mask |= REDRAW_DOOR_3; } } } } static void MapLevelEditorToolboxDrawingGadgets() { MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE); } static void UnmapLevelEditorToolboxDrawingGadgets() { MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE); } static void UnmapDrawingArea(int id) { UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]); } static void UnmapLevelEditorWindowGadgets() { int i; for (i = 0; i < NUM_EDITOR_GADGETS; i++) if (level_editor_gadget[i]->x < SX + SXSIZE) UnmapGadget(level_editor_gadget[i]); } void UnmapLevelEditorGadgets() { int i; for (i = 0; i < NUM_EDITOR_GADGETS; i++) UnmapGadget(level_editor_gadget[i]); } static void ResetUndoBuffer() { undo_buffer_position = -1; undo_buffer_steps = -1; CopyLevelToUndoBuffer(UNDO_IMMEDIATE); level.changed = FALSE; } static void DrawEditModeWindow() { ModifyEditorElementList(); RedrawDrawingElements(); if (edit_mode == ED_MODE_INFO) DrawLevelInfoWindow(); else if (edit_mode == ED_MODE_PROPERTIES) DrawPropertiesWindow(); else /* edit_mode == ED_MODE_DRAWING */ DrawDrawingWindow(); } static boolean LevelChanged() { boolean field_changed = FALSE; int x, y; #if 1 /* changed read-only levels can now be saved in personal level set */ #else if (leveldir_current->readonly) return FALSE; #endif for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] != level.field[x][y]) field_changed = TRUE; return (level.changed || field_changed); } static boolean PrepareSavingIntoPersonalLevelSet() { static LevelDirTree *last_copied_leveldir = NULL; static LevelDirTree *last_written_leveldir = NULL; static int last_copied_level_nr = -1; static int last_written_level_nr = -1; LevelDirTree *leveldir_former = leveldir_current; int level_nr_former = level_nr; int new_level_nr; // remember last mod/save so that for current session, we write // back to the same personal copy, asking only about overwrite. if (leveldir_current == last_copied_leveldir && level_nr == last_copied_level_nr) { // "cd" to personal level set dir (as used when writing last copy) leveldir_current = last_written_leveldir; level_nr = last_written_level_nr; return TRUE; } if (!Request("This level is read only ! " "Save into personal level set ?", REQ_ASK)) return FALSE; // "cd" to personal level set dir (for writing copy the first time) leveldir_current = getTreeInfoFromIdentifier(leveldir_first, getLoginName()); // find unused level number for (new_level_nr = leveldir_current->first_level; ; new_level_nr++) { static char *level_filename = NULL; setString(&level_filename, getDefaultLevelFilename(new_level_nr)); if (!fileExists(level_filename)) break; } last_copied_leveldir = leveldir_former; last_copied_level_nr = level_nr_former; last_written_leveldir = leveldir_current; last_written_level_nr = level_nr = new_level_nr; return TRUE; } static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name) { static char *filename_levelinfo = NULL, *mod_name = NULL; FILE *file; // annotate this copy-and-mod in personal levelinfo.conf setString(&filename_levelinfo, getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME)); if ((file = fopen(filename_levelinfo, MODE_APPEND))) { fprintf(file, "\n"); fprintf(file, "# level %d was modified from:\n", level_nr); fprintf(file, "# - previous level set name: %s\n", former_name); fprintf(file, "# - level within previous set: %d \"%s\"\n", level.file_info.nr, level.name); fprintf(file, "# - previous author: %s\n", level.author); fprintf(file, "# - previous save date: "); if (level.creation_date.src == DATE_SRC_LEVELFILE) { fprintf(file, "%04d-%02d-%02d\n", level.creation_date.year, level.creation_date.month, level.creation_date.day); } else { fprintf(file, "not recorded\n"); } fclose(file); } if (level_nr > leveldir_current->last_level) { static char *temp_levelinfo = NULL; FILE *temp_file = NULL; char line[MAX_LINE_LEN]; setString(&temp_levelinfo, getPath2(getCurrentLevelDir(), getStringCat2(LEVELINFO_FILENAME, ".new"))); if ((file = fopen(filename_levelinfo, MODE_READ)) && (temp_file = fopen(temp_levelinfo, MODE_WRITE))) { while (fgets(line, MAX_LINE_LEN, file)) { if (!strPrefix(line, "levels:")) fputs(line, temp_file); else fprintf(temp_file, "%-32s%d\n", "levels:", level_nr + 9); } } if (temp_file) fclose(temp_file); if (file) fclose(file); // needs error handling; also, ok on dos/win? unlink(filename_levelinfo); rename(temp_levelinfo, filename_levelinfo); } // else: allow the save even if annotation failed // now... spray graffiti on the old level vital statistics // user can change these; just trying to set a good baseline // don't truncate names for fear of making offensive or silly: // long-named original author only recorded in levelinfo.conf. // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe" if (!strEqual(level.author, leveldir_current->author)) { setString(&mod_name, getStringCat3(leveldir_current->author, " after ", level.author)); if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN) setString(&mod_name, getStringCat2(leveldir_current->author, " (ed.)")); if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN) setString(&mod_name, leveldir_current->author); strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN); // less worried about truncation here setString(&mod_name, getStringCat2("Mod: ", level.name)); strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN); } } static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY], short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY]) { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) dst[x][y] = src[x][y]; } static int setSelectboxValue(int selectbox_id, int new_value) { int new_index_value = 0; int i; for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++) if (selectbox_info[selectbox_id].options[i].value == new_value) new_index_value = i; *selectbox_info[selectbox_id].value = selectbox_info[selectbox_id].options[new_index_value].value; return new_index_value; } static void setSelectboxSpecialActionVariablesIfNeeded() { int i; /* change action mode and arg variables according to action type variable */ for (i = 0; action_arg_options[i].value != -1; i++) { if (action_arg_options[i].value == custom_element_change.action_type) { int mode = action_arg_options[i].mode; /* only change if corresponding selectbox has changed */ if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options != action_arg_modes[mode]) custom_element_change.action_mode = -1; /* only change if corresponding selectbox has changed */ if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options != action_arg_options[i].options) custom_element_change.action_arg = -1; break; } } } static void setSelectboxSpecialActionOptions() { int i; /* change action mode and arg selectbox according to action type selectbox */ for (i = 0; action_arg_options[i].value != -1; i++) { if (action_arg_options[i].value == custom_element_change.action_type) { int mode = action_arg_options[i].mode; ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE, action_arg_modes[mode]); ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE, custom_element_change.action_mode); ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG, action_arg_options[i].options); ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG, custom_element_change.action_arg); break; } } } static void copy_custom_element_settings(int element_from, int element_to) { struct ElementInfo *ei_from = &element_info[element_from]; struct ElementInfo *ei_to = &element_info[element_to]; copyElementInfo(ei_from, ei_to); } static void replace_custom_element_in_settings(int element_from, int element_to) { int i, j, x, y; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (ei->content.e[x][y] == element_from) ei->content.e[x][y] = element_to; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; if (change->target_element == element_from) change->target_element = element_to; if (change->initial_trigger_element == element_from) change->initial_trigger_element = element_to; if (change->action_element == element_from) change->action_element = element_to; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (change->target_content.e[x][y] == element_from) change->target_content.e[x][y] = element_to; } if (ei->group != NULL) /* group or internal */ for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++) if (ei->group->element[j] == element_from) ei->group->element[j] = element_to; } } static void replace_custom_element_in_playfield(int element_from, int element_to) { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) if (Feld[x][y] == element_from) Feld[x][y] = element_to; } static boolean CopyCustomElement(int element_old, int element_new, int copy_mode) { if (copy_mode == GADGET_ID_CUSTOM_COPY) { element_new = (IS_CUSTOM_ELEMENT(element_old) ? EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP); copy_mode = GADGET_ID_CUSTOM_COPY_TO; } else if (copy_mode == GADGET_ID_CUSTOM_PASTE) { element_old = (IS_CUSTOM_ELEMENT(element_new) ? EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP); copy_mode = GADGET_ID_CUSTOM_COPY_TO; level.changed = TRUE; } else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new)) { Request("Please choose custom element !", REQ_CONFIRM); return FALSE; } else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new)) { Request("Please choose group element !", REQ_CONFIRM); return FALSE; } else { level.changed = TRUE; } if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM) { copy_custom_element_settings(element_new, element_old); } else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO) { copy_custom_element_settings(element_old, element_new); } else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE) { copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY); copy_custom_element_settings(element_new, element_old); copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new); replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY); replace_custom_element_in_settings(element_new, element_old); replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new); replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY); replace_custom_element_in_playfield(element_new, element_old); replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new); } UpdateCustomElementGraphicGadgets(); DrawPropertiesWindow(); return TRUE; } static void CopyCustomElementPropertiesToEditor(int element) { int i; int current_change_page = element_info[element].current_change_page; /* dynamically (re)build selectbox for selecting change page */ for (i = 0; i < element_info[element].num_change_pages; i++) { sprintf(options_change_page_strings[i], "%d", i + 1); options_change_page[i].value = i; options_change_page[i].text = options_change_page_strings[i]; } options_change_page[i].value = -1; options_change_page[i].text = NULL; /* needed here to initialize combined element properties */ InitElementPropertiesEngine(level.game_version); element_info[element].change = &element_info[element].change_page[current_change_page]; custom_element = element_info[element]; custom_element_change = *element_info[element].change; /* needed to initially set selectbox options for special action options */ setSelectboxSpecialActionOptions(); /* needed to initially set selectbox value variables to reliable defaults */ for (i = 0; i < ED_NUM_SELECTBOX; i++) setSelectboxValue(i, *selectbox_info[i].value); for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) custom_element_properties[i] = HAS_PROPERTY(element, i); for (i = 0; i < NUM_CHANGE_EVENTS; i++) custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i); /* ---------- element settings: configure (custom elements) ------------- */ /* set accessible layer selectbox help value */ custom_element.access_type = (IS_WALKABLE(element) ? EP_WALKABLE : IS_PASSABLE(element) ? EP_PASSABLE : custom_element.access_type); custom_element.access_layer = (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER : IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE : IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER : custom_element.access_layer); custom_element.access_protected = (IS_PROTECTED(element) ? 1 : 0); custom_element_properties[EP_ACCESSIBLE] = (IS_ACCESSIBLE_OVER(element) || IS_ACCESSIBLE_INSIDE(element) || IS_ACCESSIBLE_UNDER(element)); /* set walk-to-object action selectbox help value */ custom_element.walk_to_action = (IS_DIGGABLE(element) ? EP_DIGGABLE : IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY : IS_DROPPABLE(element) ? EP_DROPPABLE : IS_THROWABLE(element) ? EP_THROWABLE : IS_PUSHABLE(element) ? EP_PUSHABLE : custom_element.walk_to_action); custom_element_properties[EP_WALK_TO_OBJECT] = (IS_DIGGABLE(element) || IS_COLLECTIBLE_ONLY(element) || IS_DROPPABLE(element) || IS_THROWABLE(element) || IS_PUSHABLE(element)); /* set smash targets selectbox help value */ custom_element.smash_targets = (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING : CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES : CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER : custom_element.smash_targets); custom_element_properties[EP_CAN_SMASH] = (CAN_SMASH_EVERYTHING(element) || CAN_SMASH_ENEMIES(element) || CAN_SMASH_PLAYER(element)); /* set deadliness selectbox help value */ custom_element.deadliness = (DONT_TOUCH(element) ? EP_DONT_TOUCH : DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY : DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH : DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO : custom_element.deadliness); custom_element_properties[EP_DEADLY] = (DONT_TOUCH(element) || DONT_GET_HIT_BY(element) || DONT_COLLIDE_WITH(element) || DONT_RUN_INTO(element)); /* ---------- element settings: advanced (custom elements) --------------- */ /* set "change by direct action" selectbox help value */ custom_element_change.direct_action = (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED : HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING : HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING : HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED : HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT : HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED : HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES : HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES : HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO : HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO : custom_element_change.direct_action); /* set "change by other element action" selectbox help value */ custom_element_change.other_action = (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X : HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X : HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X : HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X : HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X : HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X : HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X : HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X : HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X : HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X : HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X : HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X : HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X : HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X : custom_element_change.other_action); } static void CopyGroupElementPropertiesToEditor(int element) { group_element_info = *element_info[element].group; custom_element = element_info[element]; /* needed for description */ } static void CopyClassicElementPropertiesToEditor(int element) { if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) custom_element_properties[EP_CAN_MOVE_INTO_ACID] = getMoveIntoAcidProperty(&level, element); if (MAYBE_DONT_COLLIDE_WITH(element)) custom_element_properties[EP_DONT_COLLIDE_WITH] = getDontCollideWithProperty(&level, element); } static void CopyElementPropertiesToEditor(int element) { if (IS_CUSTOM_ELEMENT(element)) CopyCustomElementPropertiesToEditor(element); else if (IS_GROUP_ELEMENT(element)) CopyGroupElementPropertiesToEditor(element); else CopyClassicElementPropertiesToEditor(element); } static void CopyCustomElementPropertiesToGame(int element) { int i; int access_type_and_layer; /* mark that this custom element has been modified */ custom_element.modified_settings = TRUE; level.changed = TRUE; if (level.use_custom_template) { if (Request("Copy and modify level template ?", REQ_ASK)) { level.use_custom_template = FALSE; ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE], GDI_CHECKED, FALSE, GDI_END); } else { LoadLevelTemplate(-1); /* this resets all element modifications ... */ DrawEditModeWindow(); /* ... and copies them to 'custom_element' */ } } element_info[element] = custom_element; *element_info[element].change = custom_element_change; /* ---------- element settings: configure (custom elements) ------------- */ /* set accessible property from checkbox and selectbox */ custom_element_properties[EP_WALKABLE_OVER] = FALSE; custom_element_properties[EP_WALKABLE_INSIDE] = FALSE; custom_element_properties[EP_WALKABLE_UNDER] = FALSE; custom_element_properties[EP_PASSABLE_OVER] = FALSE; custom_element_properties[EP_PASSABLE_INSIDE] = FALSE; custom_element_properties[EP_PASSABLE_UNDER] = FALSE; access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ? EP_WALKABLE_OVER : EP_PASSABLE_OVER) + (custom_element.access_layer - EP_ACCESSIBLE_OVER)); custom_element_properties[access_type_and_layer] = custom_element_properties[EP_ACCESSIBLE]; custom_element_properties[EP_PROTECTED] = (custom_element.access_protected != 0 && custom_element_properties[EP_ACCESSIBLE]); /* set walk-to-object property from checkbox and selectbox */ custom_element_properties[EP_DIGGABLE] = FALSE; custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE; custom_element_properties[EP_DROPPABLE] = FALSE; custom_element_properties[EP_THROWABLE] = FALSE; custom_element_properties[EP_PUSHABLE] = FALSE; custom_element_properties[custom_element.walk_to_action] = custom_element_properties[EP_WALK_TO_OBJECT]; /* set smash property from checkbox and selectbox */ custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE; custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE; custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE; custom_element_properties[custom_element.smash_targets] = custom_element_properties[EP_CAN_SMASH]; /* set deadliness property from checkbox and selectbox */ custom_element_properties[EP_DONT_RUN_INTO] = FALSE; custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE; custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE; custom_element_properties[EP_DONT_TOUCH] = FALSE; custom_element_properties[custom_element.deadliness] = custom_element_properties[EP_DEADLY]; /* ---------- element settings: advanced (custom elements) --------------- */ /* set player change event from checkbox and selectbox */ custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE; custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE; custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE; custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SWITCHED] = FALSE; custom_element_change_events[CE_HITTING_SOMETHING] = FALSE; custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE; custom_element_change_events[CE_BLOCKED] = FALSE; custom_element_change_events[CE_IMPACT] = FALSE; custom_element_change_events[CE_SMASHED] = FALSE; custom_element_change_events[CE_VALUE_CHANGES] = FALSE; custom_element_change_events[CE_SCORE_CHANGES] = FALSE; custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE; custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE; custom_element_change_events[custom_element_change.direct_action] = custom_element_change_events[CE_BY_DIRECT_ACTION]; /* set other element action change event from checkbox and selectbox */ custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE; custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE; custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE; custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE; custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE; custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE; custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE; custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE; custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE; custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE; custom_element_change_events[CE_TOUCHING_X] = FALSE; custom_element_change_events[CE_HITTING_X] = FALSE; custom_element_change_events[CE_DIGGING_X] = FALSE; custom_element_change_events[CE_HIT_BY_X] = FALSE; custom_element_change_events[CE_SWITCH_OF_X] = FALSE; custom_element_change_events[CE_CHANGE_OF_X] = FALSE; custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE; custom_element_change_events[CE_MOVE_OF_X] = FALSE; custom_element_change_events[CE_CREATION_OF_X] = FALSE; custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE; custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE; custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE; custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE; custom_element_change_events[custom_element_change.other_action] = custom_element_change_events[CE_BY_OTHER_ACTION]; for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) SET_PROPERTY(element, i, custom_element_properties[i]); for (i = 0; i < NUM_CHANGE_EVENTS; i++) SET_CHANGE_EVENT(element, i, custom_element_change_events[i]); /* copy change events also to special level editor variable */ custom_element = element_info[element]; custom_element_change = *element_info[element].change; } static void CopyGroupElementPropertiesToGame(int element) { element_info[element] = custom_element; *element_info[element].group = group_element_info; /* mark that this group element has been modified */ element_info[element].modified_settings = TRUE; level.changed = TRUE; } static void CopyClassicElementPropertiesToGame(int element) { if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) setMoveIntoAcidProperty(&level, element, custom_element_properties[EP_CAN_MOVE_INTO_ACID]); if (MAYBE_DONT_COLLIDE_WITH(element)) setDontCollideWithProperty(&level, element, custom_element_properties[EP_DONT_COLLIDE_WITH]); } static void CopyElementPropertiesToGame(int element) { if (IS_CUSTOM_ELEMENT(element)) CopyCustomElementPropertiesToGame(element); else if (IS_GROUP_ELEMENT(element)) CopyGroupElementPropertiesToGame(element); else CopyClassicElementPropertiesToGame(element); } void CheckElementDescriptions() { int i; for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i)) Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i)); } void DrawLevelEd() { StopAnimation(); CloseDoor(DOOR_CLOSE_ALL); #if 1 FadeOut(REDRAW_FIELD); #endif #if 1 /* needed if different viewport properties defined for editor */ ChangeViewportPropertiesIfNeeded(); #endif OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY); #if DEBUG CheckElementDescriptions(); #endif if (level_editor_test_game) { CopyPlayfield(level.field, Feld); CopyPlayfield(FieldBackup, level.field); level_editor_test_game = FALSE; } else { edit_mode = ED_MODE_DRAWING; edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL; edit_mode_properties = ED_MODE_PROPERTIES_INFO; ResetUndoBuffer(); level_xpos = -1; level_ypos = -1; } /* copy default editor door content to main double buffer */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); #if 0 printf("::: %d, %d / %d, %d\n", VX, VY, EX, EY); #endif /* draw bigger door */ DrawSpecialEditorDoor(); /* draw new control window */ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY); redraw_mask |= REDRAW_ALL; #if 1 FreeLevelEditorGadgets(); CreateLevelEditorGadgets(); #endif ReinitializeElementList(); /* update dynamic level element list */ ReinitializeElementListButtons(); /* custom element may look different */ InitElementPropertiesGfxElement(); #if 1 UnmapAllGadgets(); #else UnmapTapeButtons(); #endif MapControlButtons(); #if 0 FadeOut(REDRAW_FIELD); #endif DrawEditModeWindow(); #if 1 FadeIn(REDRAW_FIELD); #endif /* copy actual editor door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); #if 1 /* draw new control window (with border) to window */ redraw_mask |= REDRAW_ALL; BackToFront(); #endif OpenDoor(DOOR_OPEN_1); } static void AdjustDrawingAreaGadgets() { int ed_xsize = lev_fieldx + 2; int ed_ysize = lev_fieldy + 2; int max_ed_fieldx = MAX_ED_FIELDX; int max_ed_fieldy = MAX_ED_FIELDY; boolean horizontal_scrollbar_needed; boolean vertical_scrollbar_needed; int x, y, width, height; int xoffset, yoffset; /* check if we need any scrollbars */ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx); vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy); /* check if we have a smaller editor field because of scrollbars */ if (horizontal_scrollbar_needed) max_ed_fieldy = MAX_ED_FIELDY - 1; if (vertical_scrollbar_needed) max_ed_fieldx = MAX_ED_FIELDX - 1; /* check again if we now need more scrollbars because of less space */ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx); vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy); /* check if editor field gets even smaller after adding new scrollbars */ if (horizontal_scrollbar_needed) max_ed_fieldy = MAX_ED_FIELDY - 1; if (vertical_scrollbar_needed) max_ed_fieldx = MAX_ED_FIELDX - 1; ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx); ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy); ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL], GDI_WIDTH, ed_fieldx * MINI_TILEX, GDI_HEIGHT, ed_fieldy * MINI_TILEY, GDI_AREA_SIZE, ed_fieldx, ed_fieldy, GDI_END); xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0); yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0); x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset; y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END); width = scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset; height = scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_WIDTH, width, GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_HEIGHT, height, GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy, GDI_END); } static void AdjustLevelScrollPosition() { if (level_xpos < -1) level_xpos = -1; if (level_xpos > lev_fieldx - ed_fieldx + 1) level_xpos = lev_fieldx - ed_fieldx + 1; if (lev_fieldx < ed_fieldx - 2) level_xpos = -1; if (level_ypos < -1) level_ypos = -1; if (level_ypos > lev_fieldy - ed_fieldy + 1) level_ypos = lev_fieldy - ed_fieldy + 1; if (lev_fieldy < ed_fieldy - 2) level_ypos = -1; } static void AdjustEditorScrollbar(int id) { struct GadgetInfo *gi = level_editor_gadget[id]; int items_max, items_visible, item_position; if (id == GADGET_ID_SCROLL_HORIZONTAL) { items_max = MAX(lev_fieldx + 2, ed_fieldx); items_visible = ed_fieldx; item_position = level_xpos + 1; } else { items_max = MAX(lev_fieldy + 2, ed_fieldy); items_visible = ed_fieldy; item_position = level_ypos + 1; } if (item_position > items_max - items_visible) item_position = items_max - items_visible; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void AdjustElementListScrollbar() { struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]; int items_max, items_visible, item_position; /* correct position of element list scrollbar */ if (element_shift < 0) element_shift = 0; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ; items_visible = ED_ELEMENTLIST_BUTTONS_VERT; item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void ModifyEditorCounterValue(int counter_id, int new_value) { int *counter_value = counterbutton_info[counter_id].value; int gadget_id = counterbutton_info[counter_id].gadget_id_text; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END); if (counter_value != NULL) *counter_value = gi->textinput.number_value; } static void ModifyEditorCounterLimits(int counter_id, int min, int max) { int gadget_id = counterbutton_info[counter_id].gadget_id_text; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END); if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 && counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4) { int gadget_id_up = counterbutton_info[counter_id].gadget_id_up; struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up]; ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END); ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_DISTANCE,GDI_END); } } static void ModifyEditorSelectboxValue(int selectbox_id, int new_value) { int gadget_id = selectbox_info[selectbox_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; int new_index_value = setSelectboxValue(selectbox_id, new_value); ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END); } static void ModifyEditorSelectboxOptions(int selectbox_id, struct ValueTextInfo *options) { int gadget_id = selectbox_info[selectbox_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; selectbox_info[selectbox_id].options = options; /* set index to zero -- list may be shorter now (correct later, if needed) */ ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0, GDI_SELECTBOX_OPTIONS, options, GDI_END); } static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize) { int gadget_id = drawingarea_info[drawingarea_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; drawingarea_info[drawingarea_id].area_xsize = xsize; drawingarea_info[drawingarea_id].area_ysize = ysize; ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END); } static void ModifyEditorElementList() { int i; for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) { int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; struct GadgetDesign *gd = &gi->deco.design; int element = editor_elements[element_shift + i]; UnmapGadget(gi); getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y); ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END); MapGadget(gi); } } static void PickDrawingElement(int button, int element) { if (button < 1 || button > 3) return; if (button == 1) { new_element1 = element; DrawMiniGraphicExt(drawto, DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS, el2edimg(new_element1)); } else if (button == 2) { new_element2 = element; DrawMiniGraphicExt(drawto, DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS, el2edimg(new_element2)); } else { new_element3 = element; DrawMiniGraphicExt(drawto, DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS, el2edimg(new_element3)); } redraw_mask |= REDRAW_DOOR_1; } static void RedrawDrawingElements() { PickDrawingElement(1, new_element1); PickDrawingElement(2, new_element2); PickDrawingElement(3, new_element3); } static void DrawDrawingWindow() { stick_element_properties_window = FALSE; SetMainBackgroundImage(IMG_UNDEFINED); ClearField(); UnmapLevelEditorWindowGadgets(); UnmapLevelEditorToolboxCustomGadgets(); AdjustDrawingAreaGadgets(); AdjustLevelScrollPosition(); AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL); AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL); DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); MapMainDrawingArea(); MapLevelEditorToolboxDrawingGadgets(); } static int getTabulatorBarWidth() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE]; return gd_gi4->x - gd_gi1->x + gd_gi4->width; } static void DrawLevelInfoTabulatorGadgets() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL]; struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED]; int gd_x = gd->x + gd_gi1->border.width / 2; int gd_y = gd->y + gd_gi1->height - 1; Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y); int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL; int id_last = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR; #if 1 #else int max_tabs = 2; #endif int i; for (i = id_first; i <= id_last; i++) { int gadget_id = textbutton_info[i].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; boolean active = (i != edit_mode_levelinfo); /* draw background line below tabulator button */ ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1); /* draw solid line below inactive tabulator buttons */ if (!active && tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, 1, tab_color); ModifyGadget(gi, GDI_ACTIVE, active, GDI_END); MapTextbuttonGadget(i); } #if 1 /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1, getTabulatorBarWidth(), ED_GADGET_DISTANCE, tab_color); #else /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1, max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE, ED_GADGET_DISTANCE, tab_color); #endif } static void DrawPropertiesTabulatorGadgets() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED]; int gd_x = gd->x + gd_gi1->border.width / 2; int gd_y = gd->y + gd_gi1->height - 1; Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y); int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO; int id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG; #if 1 #else int max_tabs = 4; #endif int i; /* draw two config tabulators for player elements */ if (ELEM_IS_PLAYER(properties_element)) id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2; /* draw two config and one "change" tabulator for custom elements */ if (IS_CUSTOM_ELEMENT(properties_element)) id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE; for (i = id_first; i <= id_last; i++) { int gadget_id = textbutton_info[i].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; boolean active = (i != edit_mode_properties); /* use "config 1" and "config 2" instead of "config" for players and CEs */ if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG && (ELEM_IS_PLAYER(properties_element) || IS_CUSTOM_ELEMENT(properties_element))) continue; /* draw background line below tabulator button */ ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1); /* draw solid line below inactive tabulator buttons */ if (!active && tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, 1, tab_color); ModifyGadget(gi, GDI_ACTIVE, active, GDI_END); MapTextbuttonGadget(i); } #if 1 /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1, getTabulatorBarWidth(), ED_GADGET_DISTANCE, tab_color); #else /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1, max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE, ED_GADGET_DISTANCE, tab_color); #endif } static void DrawLevelInfoLevel() { int i; /* draw counter gadgets */ for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++) MapSelectboxGadget(i); /* draw text input gadgets */ for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++) MapTextInputGadget(i); } static void DrawLevelInfoEditor() { int i; /* draw counter gadgets */ for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++) MapCounterButtons(i); /* draw checkbutton gadgets */ for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++) MapCheckbuttonGadget(i); /* draw radiobutton gadgets */ for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++) MapRadiobuttonGadget(i); /* draw drawing area */ MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND); } static void DrawLevelInfoWindow() { stick_element_properties_window = FALSE; UnmapLevelEditorWindowGadgets(); SetMainBackgroundImage(IMG_BACKGROUND_EDITOR); ClearField(); #if 1 #if 1 DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Global Settings"); #else DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Level Settings"); DrawTextSCentered(ED_SETTINGS2_YPOS, FONT_TITLE_1, "Editor Settings"); #endif #else DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS, "Level Settings", FONT_TITLE_1); DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS, "Editor Settings", FONT_TITLE_1); #endif DrawLevelInfoTabulatorGadgets(); if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL) DrawLevelInfoLevel(); else /* (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR) */ DrawLevelInfoEditor(); } static void DrawCustomContentArea() { int id = ED_DRAWING_ID_CUSTOM_CONTENT; struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS]; int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE]; int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT]; int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE; /* add distance for potential left text (without drawing area border) */ x2 += getTextWidthForGadget(drawingarea_info[id].text_left); ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT); } static void DrawCustomChangeContentArea() { int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT; struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT]; int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN]; int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE]; int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE; ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END); MapDrawingArea(id); } static void DrawYamYamContentAreas() { int x = SX + ED_AREA_YAMYAM_CONTENT_XPOS(3) + 4 * MINI_TILEX; int y = SY + ED_AREA_YAMYAM_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE; int i; /* display counter to choose number of element content areas */ MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) { int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i; if (i < level.num_yamyam_contents) { MapDrawingArea(id); } else { int font_height = getFontHeight(FONT_TEXT_1); UnmapDrawingArea(id); /* delete content areas in case of reducing number of them */ DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2, SY + drawingarea_info[id].y - MINI_TILEY / 2, 4 * MINI_TILEX, 4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height); } } DrawText(x, y + 0 * MINI_TILEY, "content", FONT_TEXT_1); DrawText(x, y + 1 * MINI_TILEY, "when", FONT_TEXT_1); DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1); } static void DrawMagicBallContentAreas() { int x = SX + ED_AREA_MAGIC_BALL_CONTENT_XPOS(3) + 4 * MINI_TILEX; int y = SY + ED_AREA_MAGIC_BALL_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE; int i; /* display counter to choose number of element content areas */ MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) { int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i; if (i < level.num_ball_contents) { MapDrawingArea(id); } else { int font_height = getFontHeight(FONT_TEXT_1); UnmapDrawingArea(id); /* delete content areas in case of reducing number of them */ DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2, SY + drawingarea_info[id].y - MINI_TILEY / 2, 4 * MINI_TILEX, 4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height); } } DrawText(x, y + 0 * MINI_TILEY, "generated", FONT_TEXT_1); DrawText(x, y + 1 * MINI_TILEY, "when", FONT_TEXT_1); DrawText(x, y + 2 * MINI_TILEY, "active", FONT_TEXT_1); } static void DrawAndroidElementArea(int element) { int num_elements = level.num_android_clone_elements; int id = ED_DRAWING_ID_ANDROID_CONTENT; int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2; int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2; int xsize = MAX_ANDROID_ELEMENTS; int ysize = 1; /* display counter to choose number of element areas */ MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT); if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY); MapDrawingArea(id); } static void DrawGroupElementArea(int element) { int num_elements = group_element_info.num_elements; int id = ED_DRAWING_ID_GROUP_CONTENT; int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2; int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2; int xsize = MAX_ELEMENTS_IN_GROUP; int ysize = 1; if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY); MapDrawingArea(id); } static void DrawPlayerInitialInventoryArea(int element) { int player_nr = GET_PLAYER_NR(element); int num_elements = level.initial_inventory_size[player_nr]; int id = ED_DRAWING_ID_INVENTORY_CONTENT; int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2; int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2; int xsize = MAX_INITIAL_INVENTORY_SIZE; int ysize = 1; /* determine horizontal position to the right of specified gadget */ if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE) sx += (right_gadget_border[drawingarea_info[id].gadget_id_align] + ED_DRAWINGAREA_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY); MapDrawingArea(id); } static void DrawEnvelopeTextArea(int envelope_nr) { int id = ED_TEXTAREA_ID_ENVELOPE_INFO; struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id]; UnmapGadget(gi); DrawBackground(gi->x, gi->y, gi->width, gi->height); if (envelope_nr != -1) textarea_info[id].value = level.envelope[envelope_nr].text; ModifyGadget(gi, GDI_AREA_SIZE, *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value, *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value, GDI_END); MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO); } static boolean PrintInfoText(char *text, int font_nr, int start_line) { int font_height = getFontHeight(font_nr); int pad_x = ED_ELEMENT_SETTINGS_XPOS(0); int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE; int sx = SX + pad_x; int sy = SY + pad_y; int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1; if (start_line >= max_lines_per_screen) return FALSE; DrawText(sx, sy + start_line * font_height, text, font_nr); return TRUE; } static int PrintElementDescriptionFromFile(char *filename, int start_line) { int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int pad_x = ED_ELEMENT_SETTINGS_XPOS(0); int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE; int sx = SX + pad_x; int sy = SY + pad_y + start_line * font_height; int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width; int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1; return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1, max_lines_per_screen, 0, -1, TRUE, FALSE, FALSE); } static void DrawPropertiesInfo() { static struct { int value; char *text; } properties[] = { /* configurable properties */ { EP_WALKABLE_OVER, "- player can walk over it" }, { EP_WALKABLE_INSIDE, "- player can walk inside it" }, { EP_WALKABLE_UNDER, "- player can walk under it" }, { EP_PASSABLE_OVER, "- player can pass over it" }, { EP_PASSABLE_INSIDE, "- player can pass through it" }, { EP_PASSABLE_UNDER, "- player can pass under it" }, { EP_PROTECTED, "- player is protected by it" }, { EP_DIGGABLE, "- can be digged away" }, { EP_COLLECTIBLE, "- can be collected" }, { EP_DROPPABLE, "- can be dropped after collecting" }, { EP_THROWABLE, "- can be thrown after collecting" }, { EP_PUSHABLE, "- can be pushed" }, { EP_CAN_FALL, "- can fall" }, { EP_CAN_MOVE, "- can move" }, { EP_CAN_SMASH_PLAYER, "- can smash player" }, #if 0 { EP_CAN_SMASH_ENEMIES, "- can smash good and bad guys" }, #endif { EP_CAN_SMASH_EVERYTHING, "- can smash everything smashable" }, { EP_SLIPPERY, "- slippery for falling elements" }, { EP_EM_SLIPPERY_WALL, "- slippery for some gems (EM style)" }, { EP_DONT_RUN_INTO, "- deadly when running into" }, { EP_DONT_COLLIDE_WITH, "- deadly when colliding with" }, { EP_DONT_GET_HIT_BY, "- deadly when getting hit by" }, { EP_DONT_TOUCH, "- deadly when touching" }, { EP_INDESTRUCTIBLE, "- indestructible" }, { EP_CAN_EXPLODE_BY_FIRE, "- can explode by fire or explosions" }, { EP_CAN_EXPLODE_SMASHED, "- can explode when smashed" }, { EP_CAN_EXPLODE_IMPACT, "- can explode on impact" }, { EP_CAN_CHANGE, "- can change to other element" }, /* pre-defined properties */ { EP_CAN_PASS_MAGIC_WALL, "- can pass magic walls" }, { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)" }, { EP_SWITCHABLE, "- can be switched" }, #if 0 { EP_HAS_EDITOR_CONTENT, "- can contain other elements" }, #endif { -1, NULL } }; char *filename = getElementDescriptionFilename(properties_element); char *percentage_text = "In this level:"; char *properties_text = "Standard properties:"; float percentage; int num_elements_in_level; int num_standard_properties = 0; int font1_nr = FONT_TEXT_1; int font2_nr = FONT_TEXT_2; int font1_width = getFontWidth(font1_nr); int font2_height = getFontHeight(font2_nr); int pad_x = ED_ELEMENT_SETTINGS_XPOS(0); int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE; int screen_line = 0; int i, x, y; if (setup.editor.show_element_token) { DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3, "[%s]", element_info[properties_element].token_name); screen_line++; } /* ----- print number of elements / percentage of this element in level */ num_elements_in_level = 0; for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] == properties_element) num_elements_in_level++; percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy); DrawTextS(pad_x, pad_y + screen_line * font2_height, font1_nr, percentage_text); DrawTextF(pad_x + strlen(percentage_text) * font1_width, pad_y + screen_line++ * font2_height, font2_nr, "%d (%.2f%%)", num_elements_in_level, percentage); screen_line++; /* ----- print standard properties of this element */ DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font1_nr, properties_text); for (i = 0; properties[i].value != -1; i++) { if (!HAS_PROPERTY(properties_element, properties[i].value)) continue; DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font2_nr, properties[i].text); num_standard_properties++; } if (num_standard_properties == 0) DrawTextS(pad_x + strlen(properties_text) * font1_width, pad_y + (screen_line - 1) * font2_height, font2_nr, "none"); screen_line++; /* ----- print special description of this element */ PrintInfoText("Description:", FONT_TEXT_1, screen_line); if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0) PrintInfoText("No description available.", FONT_TEXT_1, screen_line); } #define TEXT_COLLECTING "Score for collecting" #define TEXT_SMASHING "Score for smashing" #define TEXT_SLURPING "Score for slurping robot" #define TEXT_CRACKING "Score for cracking" #define TEXT_AMOEBA_SPEED "Speed of amoeba growth" #define TEXT_DURATION "Duration when activated" #define TEXT_BALL_DELAY "Element generation delay" #define TEXT_MOVE_SPEED "Speed of android moving" #define TEXT_CLONE_SPEED "Speed of android cloning" #define TEXT_GAME_OF_LIFE_1 "Min neighbours to survive" #define TEXT_GAME_OF_LIFE_2 "Max neighbours to survive" #define TEXT_GAME_OF_LIFE_3 "Min neighbours to create" #define TEXT_GAME_OF_LIFE_4 "Max neighbours to create" #define TEXT_TIME_BONUS "Extra time to solve level" static struct { int element; int *value; char *text; } elements_with_counter[] = { { EL_EMERALD, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_BD_DIAMOND, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_YELLOW, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_RED, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_PURPLE, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_SP_INFOTRON, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_DIAMOND, &level.score[SC_DIAMOND], TEXT_COLLECTING }, { EL_CRYSTAL, &level.score[SC_CRYSTAL], TEXT_COLLECTING }, { EL_PEARL, &level.score[SC_PEARL], TEXT_COLLECTING }, { EL_BUG, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_RIGHT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_UP, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_LEFT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_DOWN, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_UP, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG], TEXT_SMASHING }, { EL_SP_ELECTRON, &level.score[SC_BUG], TEXT_SMASHING }, { EL_SPACESHIP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_UP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_LEFT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_DOWN, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_UP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SP_SNIKSNAK, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_YAMYAM, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_LEFT, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_RIGHT, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_UP, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_DOWN, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_DARK_YAMYAM, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_ROBOT, &level.score[SC_ROBOT], TEXT_SMASHING }, { EL_PACMAN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_RIGHT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_UP, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_LEFT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_DOWN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_NUT, &level.score[SC_NUT], TEXT_CRACKING }, { EL_DYNAMITE, &level.score[SC_DYNAMITE], TEXT_COLLECTING }, { EL_EM_DYNAMITE, &level.score[SC_DYNAMITE], TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_SHIELD_NORMAL, &level.score[SC_SHIELD], TEXT_COLLECTING }, { EL_SHIELD_DEADLY, &level.score[SC_SHIELD], TEXT_COLLECTING }, { EL_EXTRA_TIME, &level.extra_time_score, TEXT_COLLECTING }, { EL_KEY_1, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_2, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_3, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_4, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_1, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_2, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_3, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_4, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_5, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_6, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_7, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_8, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_DC_KEY_WHITE, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_AMOEBA_WET, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_AMOEBA_DRY, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_AMOEBA_FULL, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_BD_AMOEBA, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_EMC_DRIPPER, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_BD_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_DC_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_ROBOT_WHEEL, &level.time_wheel, TEXT_DURATION }, { EL_TIMEGATE_SWITCH, &level.time_timegate, TEXT_DURATION }, { EL_DC_TIMEGATE_SWITCH,&level.time_timegate, TEXT_DURATION }, { EL_LIGHT_SWITCH, &level.time_light, TEXT_DURATION }, { EL_LIGHT_SWITCH_ACTIVE, &level.time_light, TEXT_DURATION }, { EL_SHIELD_NORMAL, &level.shield_normal_time, TEXT_DURATION }, { EL_SHIELD_DEADLY, &level.shield_deadly_time, TEXT_DURATION }, { EL_EXTRA_TIME, &level.extra_time, TEXT_TIME_BONUS }, { EL_TIME_ORB_FULL, &level.time_orb_time, TEXT_TIME_BONUS }, { EL_GAME_OF_LIFE, &level.game_of_life[0], TEXT_GAME_OF_LIFE_1 }, { EL_GAME_OF_LIFE, &level.game_of_life[1], TEXT_GAME_OF_LIFE_2 }, { EL_GAME_OF_LIFE, &level.game_of_life[2], TEXT_GAME_OF_LIFE_3 }, { EL_GAME_OF_LIFE, &level.game_of_life[3], TEXT_GAME_OF_LIFE_4 }, { EL_BIOMAZE, &level.biomaze[0], TEXT_GAME_OF_LIFE_1 }, { EL_BIOMAZE, &level.biomaze[1], TEXT_GAME_OF_LIFE_2 }, { EL_BIOMAZE, &level.biomaze[2], TEXT_GAME_OF_LIFE_3 }, { EL_BIOMAZE, &level.biomaze[3], TEXT_GAME_OF_LIFE_4 }, { EL_EMC_ANDROID, &level.android_move_time, TEXT_MOVE_SPEED }, { EL_EMC_ANDROID, &level.android_clone_time, TEXT_CLONE_SPEED }, { EL_EMC_MAGIC_BALL, &level.ball_time, TEXT_BALL_DELAY }, { EL_EMC_LENSES, &level.lenses_score, TEXT_COLLECTING }, { EL_EMC_MAGNIFIER, &level.magnify_score, TEXT_COLLECTING }, { EL_SPRING, &level.slurp_score, TEXT_SLURPING }, { EL_EMC_LENSES, &level.lenses_time, TEXT_DURATION }, { EL_EMC_MAGNIFIER, &level.magnify_time, TEXT_DURATION }, { -1, NULL, NULL } }; static boolean checkPropertiesConfig(int element) { int i; if (IS_GEM(element) || IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_ENVELOPE(element) || ELEM_IS_PLAYER(element) || HAS_EDITOR_CONTENT(element) || CAN_GROW(element) || COULD_MOVE_INTO_ACID(element) || MAYBE_DONT_COLLIDE_WITH(element) || element == EL_SOKOBAN_OBJECT || element == EL_SOKOBAN_FIELD_EMPTY || element == EL_SOKOBAN_FIELD_FULL) return TRUE; else for (i = 0; elements_with_counter[i].element != -1; i++) if (elements_with_counter[i].element == element) return TRUE; return FALSE; } static void DrawPropertiesConfig() { int max_num_element_counters = 4; int num_element_counters = 0; int i; if (!checkPropertiesConfig(properties_element)) { PrintInfoText("No configuration options available.", FONT_TEXT_1, 0); return; } /* check if there are elements where a value can be chosen for */ for (i = 0; elements_with_counter[i].element != -1; i++) { if (elements_with_counter[i].element == properties_element) { int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters; counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS( (HAS_EDITOR_CONTENT(properties_element) ? 1 : 0) + (CAN_GROW(properties_element) ? 1 : 0) + (COULD_MOVE_INTO_ACID(properties_element) ? 1 : 0) + (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) + (properties_element == EL_EMC_MAGIC_BALL ? 2 : 0) + num_element_counters); counterbutton_info[counter_id].value = elements_with_counter[i].value; counterbutton_info[counter_id].text_right= elements_with_counter[i].text; if (properties_element == EL_GAME_OF_LIFE || properties_element == EL_BIOMAZE) { counterbutton_info[counter_id].min_value = 0; /* min neighbours */ counterbutton_info[counter_id].max_value = 8; /* max neighbours */ } else { /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */ counterbutton_info[counter_id].min_value = MIN_SCORE; counterbutton_info[counter_id].max_value = MAX_SCORE; } MapCounterButtons(counter_id); num_element_counters++; if (num_element_counters >= max_num_element_counters) break; } } if (HAS_EDITOR_CONTENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); if (IS_AMOEBOID(properties_element)) MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT); else if (properties_element == EL_YAMYAM || properties_element == EL_YAMYAM_LEFT || properties_element == EL_YAMYAM_RIGHT || properties_element == EL_YAMYAM_UP || properties_element == EL_YAMYAM_DOWN) DrawYamYamContentAreas(); else if (properties_element == EL_EMC_MAGIC_BALL) { DrawMagicBallContentAreas(); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE); } else if (properties_element == EL_EMC_ANDROID) DrawAndroidElementArea(properties_element); } if (ELEM_IS_PLAYER(properties_element)) { int player_nr = GET_PLAYER_NR(properties_element); /* these properties can be set for every player individually */ if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1) { drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value = &level.start_element[player_nr]; drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value = &level.artwork_element[player_nr]; drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value = &level.explosion_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value = &level.use_start_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value = &level.use_artwork_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value = &level.use_explosion_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value = &level.initial_player_gravity[player_nr]; selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value = &level.initial_player_stepsize[player_nr]; MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID); MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ? ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD : ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE); MapDrawingArea(ED_DRAWING_ID_START_ELEMENT); MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT); MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT); MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED); } else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2) { drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value = &level.initial_inventory_content[player_nr][0]; counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value = &level.initial_inventory_size[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value = &level.use_initial_inventory[player_nr]; /* draw checkbutton gadgets */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY); /* draw counter gadgets */ MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE); /* draw drawing area gadgets */ DrawPlayerInitialInventoryArea(properties_element); } } if (IS_GEM(properties_element)) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS); if (properties_element == EL_EM_DYNAMITE) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE); if (COULD_MOVE_INTO_ACID(properties_element) && !ELEM_IS_PLAYER(properties_element) && (!IS_CUSTOM_ELEMENT(properties_element) || edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)) { /* set position for checkbutton for "can move into acid" */ checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x = ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0); checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y = ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 : HAS_EDITOR_CONTENT(properties_element) ? 1 : 0); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID); } if (MAYBE_DONT_COLLIDE_WITH(properties_element)) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH); if (properties_element == EL_SPRING) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG); if (properties_element == EL_TIME_ORB_FULL) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG); if (CAN_GROW(properties_element)) { checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y = ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE); } if (properties_element == EL_SOKOBAN_OBJECT || properties_element == EL_SOKOBAN_FIELD_EMPTY || properties_element == EL_SOKOBAN_FIELD_FULL) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN); if (IS_ENVELOPE(properties_element)) { int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE; int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE; int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP; int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED; int envelope_nr = properties_element - EL_ENVELOPE_1; counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize; counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize; checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap; checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered; /* display counter to choose size of envelope text area */ MapCounterButtons(counter1_id); MapCounterButtons(counter2_id); /* display checkbuttons to choose auto-wrap and alignment properties */ MapCheckbuttonGadget(button1_id); MapCheckbuttonGadget(button2_id); DrawEnvelopeTextArea(envelope_nr); } if (IS_CUSTOM_ELEMENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1) { /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CUSTOM1_FIRST; i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CUSTOM1_FIRST; i <= ED_COUNTER_ID_CUSTOM1_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CUSTOM1_FIRST; i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++) MapSelectboxGadget(i); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE); /* draw text input gadgets */ MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC); } else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2) { /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CUSTOM2_FIRST; i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CUSTOM2_FIRST; i <= ED_COUNTER_ID_CUSTOM2_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CUSTOM2_FIRST; i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++) MapSelectboxGadget(i); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER); MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE); DrawCustomContentArea(); } } else if (IS_GROUP_ELEMENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); /* draw checkbutton gadgets */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE); /* draw counter gadgets */ MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT); /* draw selectbox gadgets */ MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE); /* draw drawing area gadgets */ DrawGroupElementArea(properties_element); /* draw text input gadgets */ MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC); } } static void DrawPropertiesChangeDrawingAreas() { if (IS_CUSTOM_ELEMENT(properties_element)) { MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION); DrawCustomChangeContentArea(); } redraw_mask |= REDRAW_FIELD; } static void DrawPropertiesChange() { int i; /* needed to initially set selectbox options for special action options */ setSelectboxSpecialActionOptions(); /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CHANGE_FIRST; i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CHANGE_FIRST; i <= ED_COUNTER_ID_CHANGE_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CHANGE_FIRST; i <= ED_SELECTBOX_ID_CHANGE_LAST; i++) MapSelectboxGadget(i); /* draw textbutton gadgets */ for (i = ED_TEXTBUTTON_ID_CHANGE_FIRST; i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++) MapTextbuttonGadget(i); /* draw graphicbutton gadgets */ for (i = ED_GRAPHICBUTTON_ID_CHANGE_FIRST; i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++) MapGraphicbuttonGadget(i); /* draw drawing area gadgets */ DrawPropertiesChangeDrawingAreas(); } static void DrawEditorElementAnimation(int x, int y) { int graphic = el2img(properties_element); int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ? custom_element.ce_value_fixed_initial : ANIM_MODE(graphic) == ANIM_CE_SCORE ? custom_element.collect_score_initial : FrameCounter); DrawGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING); } static void DrawEditorElementName(int x, int y, int element) { char *element_name = getElementInfoText(element); int font_nr = FONT_TEXT_1; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_XPOS(0); int max_chars_per_line = max_text_width / font_width; char buffer[max_chars_per_line + 1]; if (strlen(element_name) <= max_chars_per_line) DrawTextS(x, y, font_nr, element_name); else { int next_pos = max_chars_per_line; strncpy(buffer, element_name, max_chars_per_line); buffer[max_chars_per_line] = '\0'; if (element_name[max_chars_per_line] == ' ') next_pos++; else { int i; for (i = max_chars_per_line - 1; i >= 0; i--) if (buffer[i] == ' ') break; if (strlen(&element_name[i + 1]) <= max_chars_per_line) { buffer[i] = '\0'; next_pos = i + 1; } } DrawTextS(x, y - font_height / 2, font_nr, buffer); strncpy(buffer, &element_name[next_pos], max_chars_per_line); buffer[max_chars_per_line] = '\0'; DrawTextS(x, y + font_height / 2, font_nr, buffer); } } static void DrawPropertiesWindow() { int xstart = 2; int ystart = 4; stick_element_properties_window = FALSE; /* make sure that previous properties edit mode exists for this element */ if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 && !IS_CUSTOM_ELEMENT(properties_element)) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2; if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG && !ELEM_IS_PLAYER(properties_element) && !IS_CUSTOM_ELEMENT(properties_element)) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG; if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG && (ELEM_IS_PLAYER(properties_element) || IS_CUSTOM_ELEMENT(properties_element))) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1; CopyElementPropertiesToEditor(properties_element); UnmapLevelEditorWindowGadgets(); UnmapLevelEditorToolboxDrawingGadgets(); UnmapLevelEditorToolboxCustomGadgets(); if (IS_CUSTOM_ELEMENT(properties_element) || IS_GROUP_ELEMENT(properties_element)) MapLevelEditorToolboxCustomGadgets(); SetMainBackgroundImage(IMG_BACKGROUND_EDITOR); ClearField(); #if 1 DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Element Settings"); #else DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS, "Element Settings", FONT_TITLE_1); #endif FrameCounter = 0; /* restart animation frame counter */ DrawElementBorder(SX + xstart * MINI_TILEX, SY + ystart * MINI_TILEY + MINI_TILEY / 2, TILEX, TILEY, FALSE); DrawEditorElementAnimation(SX + xstart * MINI_TILEX, SY + ystart * MINI_TILEY + MINI_TILEY / 2); DrawEditorElementName((xstart + 3) * MINI_TILEX + 1, (ystart + 1) * MINI_TILEY + 1, properties_element); DrawPropertiesTabulatorGadgets(); if (edit_mode_properties == ED_MODE_PROPERTIES_INFO) DrawPropertiesInfo(); else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE) DrawPropertiesChange(); else /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */ DrawPropertiesConfig(); } static void UpdateCustomElementGraphicGadgets() { struct ElementInfo *ei = &element_info[properties_element]; int i; ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : properties_element); ModifyEditorElementList(); RedrawDrawingElements(); /* force redraw of all mapped drawing area gadgets */ for (i = 0; i < ED_NUM_DRAWING_AREAS; i++) { struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id]; if (gi->mapped) MapDrawingArea(i); } } static int getOpenDirectionFromTube(int element) { switch (element) { case EL_TUBE_LEFT_UP: return (MV_LEFT | MV_UP); case EL_TUBE_LEFT_DOWN: return (MV_LEFT | MV_DOWN); case EL_TUBE_RIGHT_UP: return (MV_RIGHT | MV_UP); case EL_TUBE_RIGHT_DOWN: return (MV_RIGHT | MV_DOWN); case EL_TUBE_HORIZONTAL: return (MV_HORIZONTAL); case EL_TUBE_HORIZONTAL_UP: return (MV_HORIZONTAL | MV_UP); case EL_TUBE_HORIZONTAL_DOWN: return (MV_HORIZONTAL | MV_DOWN); case EL_TUBE_VERTICAL: return (MV_VERTICAL); case EL_TUBE_VERTICAL_LEFT: return (MV_VERTICAL | MV_LEFT); case EL_TUBE_VERTICAL_RIGHT: return (MV_VERTICAL | MV_RIGHT); case EL_TUBE_ANY: return (MV_ANY_DIRECTION); } return MV_NONE; } static int getTubeFromOpenDirection(int direction) { switch (direction) { case (MV_LEFT | MV_UP): return EL_TUBE_LEFT_UP; case (MV_LEFT | MV_DOWN): return EL_TUBE_LEFT_DOWN; case (MV_RIGHT | MV_UP): return EL_TUBE_RIGHT_UP; case (MV_RIGHT | MV_DOWN): return EL_TUBE_RIGHT_DOWN; case (MV_HORIZONTAL): return EL_TUBE_HORIZONTAL; case (MV_HORIZONTAL | MV_UP): return EL_TUBE_HORIZONTAL_UP; case (MV_HORIZONTAL | MV_DOWN): return EL_TUBE_HORIZONTAL_DOWN; case (MV_VERTICAL): return EL_TUBE_VERTICAL; case (MV_VERTICAL | MV_LEFT): return EL_TUBE_VERTICAL_LEFT; case (MV_VERTICAL | MV_RIGHT): return EL_TUBE_VERTICAL_RIGHT; case (MV_ANY_DIRECTION): return EL_TUBE_ANY; /* if only one direction, fall back to simple tube with that direction */ case (MV_LEFT): return EL_TUBE_HORIZONTAL; case (MV_RIGHT): return EL_TUBE_HORIZONTAL; case (MV_UP): return EL_TUBE_VERTICAL; case (MV_DOWN): return EL_TUBE_VERTICAL; } return EL_EMPTY; } static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getTubeFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromBelt(int element) { int belt_dir = getBeltDirFromBeltElement(element); return (belt_dir == MV_LEFT ? MV_RIGHT : belt_dir == MV_RIGHT ? MV_LEFT : belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir); } static int getBeltFromNrAndOpenDirection(int nr, int direction) { int belt_dir = (direction == MV_LEFT ? MV_RIGHT : direction == MV_RIGHT ? MV_LEFT : direction == MV_HORIZONTAL ? MV_NONE : direction); if (direction == MV_NONE) return EL_EMPTY; return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir); } static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction, int element_old) { int element_new = getBeltFromNrAndOpenDirection(nr, direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromPool(int element) { switch (element) { case EL_ACID_POOL_TOPLEFT: return (MV_DOWN | MV_RIGHT); case EL_ACID_POOL_TOPRIGHT: return (MV_DOWN | MV_LEFT); case EL_ACID_POOL_BOTTOMLEFT: return (MV_UP | MV_RIGHT); case EL_ACID_POOL_BOTTOMRIGHT: return (MV_UP | MV_LEFT); case EL_ACID_POOL_BOTTOM: return (MV_HORIZONTAL | MV_UP); case EL_ACID: return (MV_HORIZONTAL | MV_DOWN); } return MV_NONE; } static int getPoolFromOpenDirection(int direction) { switch (direction) { case (MV_DOWN | MV_RIGHT): return EL_ACID_POOL_TOPLEFT; case (MV_DOWN | MV_LEFT): return EL_ACID_POOL_TOPRIGHT; case (MV_UP | MV_RIGHT): return EL_ACID_POOL_BOTTOMLEFT; case (MV_UP | MV_LEFT): return EL_ACID_POOL_BOTTOMRIGHT; case (MV_HORIZONTAL | MV_UP): return EL_ACID_POOL_BOTTOM; case (MV_HORIZONTAL | MV_DOWN): return EL_ACID; } return EL_EMPTY; } static int getPoolFromOpenDirectionExt(int direction, int help_element) { int element = getPoolFromOpenDirection(direction); int help_direction = getOpenDirectionFromPool(help_element); if (element == EL_EMPTY) { int help_direction_vertical = help_direction & MV_VERTICAL; element = getPoolFromOpenDirection(direction | help_direction_vertical); } if (element == EL_EMPTY) { int help_direction_horizontal = help_direction & MV_HORIZONTAL; element = getPoolFromOpenDirection(direction | help_direction_horizontal); } return element; } static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getPoolFromOpenDirectionExt(direction, element_old); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromPillar(int element) { switch (element) { case EL_EMC_WALL_1: return (MV_DOWN); case EL_EMC_WALL_2: return (MV_VERTICAL); case EL_EMC_WALL_3: return (MV_UP); } return MV_NONE; } static int getPillarFromOpenDirection(int direction) { switch (direction) { case (MV_DOWN): return EL_EMC_WALL_1; case (MV_VERTICAL): return EL_EMC_WALL_2; case (MV_UP): return EL_EMC_WALL_3; } return EL_EMPTY; } static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getPillarFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromSteel2(int element) { switch (element) { case EL_DC_STEELWALL_2_LEFT: return (MV_RIGHT); case EL_DC_STEELWALL_2_RIGHT: return (MV_LEFT); case EL_DC_STEELWALL_2_TOP: return (MV_DOWN); case EL_DC_STEELWALL_2_BOTTOM: return (MV_UP); case EL_DC_STEELWALL_2_HORIZONTAL: return (MV_HORIZONTAL); case EL_DC_STEELWALL_2_VERTICAL: return (MV_VERTICAL); case EL_DC_STEELWALL_2_MIDDLE: return (MV_ANY_DIRECTION); case EL_DC_STEELWALL_2_SINGLE: return (MV_NONE); } return MV_NONE; } static int getSteel2FromOpenDirection(int direction) { switch (direction) { case (MV_RIGHT): return EL_DC_STEELWALL_2_LEFT; case (MV_LEFT): return EL_DC_STEELWALL_2_RIGHT; case (MV_DOWN): return EL_DC_STEELWALL_2_TOP; case (MV_UP): return EL_DC_STEELWALL_2_BOTTOM; case (MV_HORIZONTAL): return EL_DC_STEELWALL_2_HORIZONTAL; case (MV_VERTICAL): return EL_DC_STEELWALL_2_VERTICAL; case (MV_ANY_DIRECTION): return EL_DC_STEELWALL_2_MIDDLE; case (MV_NONE): return EL_DC_STEELWALL_2_SINGLE; } return EL_EMPTY; } static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getSteel2FromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromChip(int element) { switch (element) { case EL_SP_CHIP_SINGLE: return (MV_NONE); case EL_SP_CHIP_LEFT: return (MV_RIGHT); case EL_SP_CHIP_RIGHT: return (MV_LEFT); case EL_SP_CHIP_TOP: return (MV_DOWN); case EL_SP_CHIP_BOTTOM: return (MV_UP); } return MV_NONE; } static int getChipFromOpenDirection(int direction) { switch (direction) { case (MV_NONE): return EL_SP_CHIP_SINGLE; case (MV_LEFT): return EL_SP_CHIP_RIGHT; case (MV_RIGHT): return EL_SP_CHIP_LEFT; case (MV_UP): return EL_SP_CHIP_BOTTOM; case (MV_DOWN): return EL_SP_CHIP_TOP; } return EL_EMPTY; } static int getChipFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getChipFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getClosedTube(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromTube(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getTubeFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedBelt(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int nr = getBeltNrFromBeltElement(element_old); int direction_old = getOpenDirectionFromBelt(element_old); int direction_new = MV_NONE; int i; for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getBeltFromNrAndOpenDirection(nr, direction_new); } static int getClosedPool(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromPool(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getPoolFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedPillar(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromPillar(element_old); int direction_new = MV_NONE; int i; for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getPillarFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedSteel2(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromSteel2(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedChip(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromChip(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getChipFromOpenDirectionNotEmpty(direction_new, element_old); } static void SetElementSimple(int x, int y, int element, boolean change_level) { int sx = x - level_xpos; int sy = y - level_ypos; IntelliDrawBuffer[x][y] = element; if (change_level) Feld[x][y] = element; if (IN_ED_FIELD(sx, sy)) DrawMiniElement(sx, sy, element); } static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1, int x2, int y2, int *element2, int (*close_function)(int, int), boolean change_level) { /* set neighbour elements to newly determined connections */ SetElementSimple(x1, y1, *element1, change_level); SetElementSimple(x2, y2, *element2, change_level); /* remove all open connections of neighbour elements */ *element1 = close_function(x1, y1); *element2 = close_function(x2, y2); /* set neighbour elements to new, minimized connections */ SetElementSimple(x1, y1, *element1, change_level); SetElementSimple(x2, y2, *element2, change_level); } static void SetElementIntelliDraw(int x, int y, int new_element, boolean change_level, int button) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; static int last_x = -1; static int last_y = -1; int old_element = IntelliDrawBuffer[x][y]; if (new_element == EL_UNDEFINED) { last_x = -1; last_y = -1; return; } if (IS_TUBE(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_TUBE(old_element)) direction |= getOpenDirectionFromTube(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_TUBE(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromTube(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getTubeFromOpenDirection(last_direction_new); direction |= dir; } } new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedTube, change_level); } else if (IS_BELT(new_element)) { int belt_nr = getBeltNrFromBeltElement(new_element); int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_BELT(old_element)) direction |= getOpenDirectionFromBelt(old_element); for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_BELT(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_belt_nr = getBeltNrFromBeltElement(last_element_old); int last_direction_old = getOpenDirectionFromBelt(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr, last_direction_new); direction |= dir; } } new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedBelt, change_level); } else if (IS_ACID_POOL_OR_ACID(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_ACID_POOL_OR_ACID(old_element)) direction |= getOpenDirectionFromPool(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromPool(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getPoolFromOpenDirection(last_direction_new); direction |= dir; } } /* special corrections needed for intuitively correct acid pool drawing */ if (last_element_new == EL_EMPTY) last_element_new = new_element; else if (last_element_new != EL_UNDEFINED) new_element = last_element_new; new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedPool, change_level); } else if (IS_EMC_PILLAR(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_EMC_PILLAR(old_element)) direction |= getOpenDirectionFromPillar(old_element); for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromPillar(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getPillarFromOpenDirection(last_direction_new); direction |= dir; } } new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedPillar, change_level); } else if (IS_DC_STEELWALL_2(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_DC_STEELWALL_2(old_element)) direction |= getOpenDirectionFromSteel2(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromSteel2(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getSteel2FromOpenDirection(last_direction_new); direction |= dir; } } new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedSteel2, change_level); } else if (IS_SP_CHIP(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* (do not keep existing directions, regardless of kind of old element) */ for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromChip(last_element_old); int last_direction_new = last_direction_old | dir_opposite; if (last_direction_old == MV_NONE) { last_element_new = getChipFromOpenDirection(last_direction_new); direction |= dir; } else if (last_direction_old & (dir | dir_opposite)) { direction |= MV_DIR_OPPOSITE(last_direction_old); } else { direction |= MV_DIR_OPPOSITE(dir); } } } new_element = getChipFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedChip, change_level); } else if (IS_SP_HARDWARE_BASE(new_element)) { int nr = GetSimpleRandom(6); new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 : nr == 1 ? EL_SP_HARDWARE_BASE_2 : nr == 2 ? EL_SP_HARDWARE_BASE_3 : nr == 3 ? EL_SP_HARDWARE_BASE_4 : nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6); } else if (new_element == EL_SP_HARDWARE_GREEN || new_element == EL_SP_HARDWARE_BLUE || new_element == EL_SP_HARDWARE_RED) { int nr = GetSimpleRandom(3); new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN : nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED); } else if (IS_GROUP_ELEMENT(new_element)) { boolean connected_drawing = FALSE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element)) connected_drawing = TRUE; } if (!connected_drawing) ResolveGroupElement(new_element); new_element = GetElementFromGroupElement(new_element); } else if (IS_BELT_SWITCH(old_element)) { int belt_nr = getBeltNrFromBeltSwitchElement(old_element); int belt_dir = getBeltDirFromBeltSwitchElement(old_element); belt_dir = (belt_dir == MV_LEFT ? MV_NONE : belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT); new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir); } else { static int swappable_elements[][2] = { { EL_EXIT_CLOSED, EL_EXIT_OPEN }, { EL_DYNAMITE, EL_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE }, { EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL }, { EL_EMERALD, EL_WALL_EMERALD }, { EL_EMERALD_YELLOW, EL_WALL_EMERALD_YELLOW }, { EL_EMERALD_RED, EL_WALL_EMERALD_RED }, { EL_EMERALD_PURPLE, EL_WALL_EMERALD_PURPLE }, { EL_DIAMOND, EL_WALL_DIAMOND }, { EL_BD_DIAMOND, EL_WALL_BD_DIAMOND }, { EL_GATE_1, EL_GATE_1_GRAY }, { EL_GATE_2, EL_GATE_2_GRAY }, { EL_GATE_3, EL_GATE_3_GRAY }, { EL_GATE_4, EL_GATE_4_GRAY }, { EL_EM_GATE_1, EL_EM_GATE_1_GRAY }, { EL_EM_GATE_2, EL_EM_GATE_2_GRAY }, { EL_EM_GATE_3, EL_EM_GATE_3_GRAY }, { EL_EM_GATE_4, EL_EM_GATE_4_GRAY }, { EL_EMC_GATE_5, EL_EMC_GATE_5_GRAY }, { EL_EMC_GATE_6, EL_EMC_GATE_6_GRAY }, { EL_EMC_GATE_7, EL_EMC_GATE_7_GRAY }, { EL_EMC_GATE_8, EL_EMC_GATE_8_GRAY }, { EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY }, { EL_TIME_ORB_EMPTY, EL_TIME_ORB_FULL }, { EL_LAMP, EL_LAMP_ACTIVE }, { EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL }, { EL_SP_BASE, EL_SP_BUGGY_BASE }, { EL_PEARL, EL_WALL_PEARL }, { EL_CRYSTAL, EL_WALL_CRYSTAL }, { EL_TIMEGATE_CLOSED, EL_TIMEGATE_OPEN }, { EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_OPEN }, { EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN }, { EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN }, { EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE }, { EL_LANDMINE, EL_DC_LANDMINE }, { EL_SHIELD_NORMAL, EL_SHIELD_DEADLY }, { EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN }, { EL_EM_EXIT_CLOSED, EL_EM_EXIT_OPEN }, { EL_EM_STEEL_EXIT_CLOSED, EL_EM_STEEL_EXIT_OPEN }, { EL_QUICKSAND_FAST_EMPTY, EL_QUICKSAND_FAST_FULL }, { -1, -1 }, }; static int rotatable_elements[][4] = { { EL_BUG_UP, EL_BUG_RIGHT, EL_BUG_DOWN, EL_BUG_LEFT }, { EL_SPACESHIP_UP, EL_SPACESHIP_RIGHT, EL_SPACESHIP_DOWN, EL_SPACESHIP_LEFT }, { EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_RIGHT, EL_BD_BUTTERFLY_DOWN, EL_BD_BUTTERFLY_LEFT }, { EL_BD_FIREFLY_UP, EL_BD_FIREFLY_RIGHT, EL_BD_FIREFLY_DOWN, EL_BD_FIREFLY_LEFT }, { EL_PACMAN_UP, EL_PACMAN_RIGHT, EL_PACMAN_DOWN, EL_PACMAN_LEFT }, { EL_YAMYAM_UP, EL_YAMYAM_RIGHT, EL_YAMYAM_DOWN, EL_YAMYAM_LEFT }, { EL_ARROW_UP, EL_ARROW_RIGHT, EL_ARROW_DOWN, EL_ARROW_LEFT }, { EL_SP_PORT_UP, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT }, { EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT }, { EL_MOLE_UP, EL_MOLE_RIGHT, EL_MOLE_DOWN, EL_MOLE_LEFT }, { EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_RIGHT, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_LEFT }, { -1, -1, -1, -1, }, }; int i, j; for (i = 0; swappable_elements[i][0] != -1; i++) { int element1 = swappable_elements[i][0]; int element2 = swappable_elements[i][1]; if (old_element == element1 || old_element == element2) new_element = (old_element == element1 ? element2 : element1); } for (i = 0; rotatable_elements[i][0] != -1; i++) { for (j = 0; j < 4; j++) { int element = rotatable_elements[i][j]; if (old_element == element) new_element = (button == 1 ? rotatable_elements[i][(j + 3) % 4] : button == 2 ? rotatable_elements[i][0] : button == 3 ? rotatable_elements[i][(j + 1) % 4] : old_element); } } } SetElementSimple(x, y, new_element, change_level); last_x = x; last_y = y; } static void ResetIntelliDraw() { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) IntelliDrawBuffer[x][y] = Feld[x][y]; SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1); } static void SetElementExt(int x, int y, int element, boolean change_level, int button) { if (element < 0) SetElementSimple(x, y, Feld[x][y], change_level); else if (GetKeyModState() & KMOD_Shift) SetElementIntelliDraw(x, y, element, change_level, button); else SetElementSimple(x, y, element, change_level); } static void SetElement(int x, int y, int element) { SetElementExt(x, y, element, TRUE, -1); } static void SetElementButton(int x, int y, int element, int button) { SetElementExt(x, y, element, TRUE, button); } static void DrawLineElement(int sx, int sy, int element, boolean change_level) { int lx = sx + level_xpos; int ly = sy + level_ypos; SetElementExt(lx, ly, element, change_level, -1); } static void DrawLine(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int xsize = ABS(to_x - from_x); int ysize = ABS(to_y - from_y); int dx = (to_x < from_x ? -1 : +1); int dy = (to_y < from_y ? -1 : +1); int i; if (from_y == to_y) /* horizontal line */ { for (i = 0; i <= xsize; i++) DrawLineElement(from_x + i * dx, from_y, element, change_level); } else if (from_x == to_x) /* vertical line */ { for (i = 0; i <= ysize; i++) DrawLineElement(from_x, from_y + i * dy, element, change_level); } else /* diagonal line */ { if (ysize < xsize) /* a < 1 */ { float a = (float)ysize / (float)xsize; for (i = 0; i <= xsize; i++) { int x = dx * i; int y = dy * (int)(a * i + 0.5); DrawLineElement(from_x + x, from_y + y, element, change_level); } } else /* a >= 1 */ { float a = (float)xsize / (float)ysize; for (i = 0; i <= ysize; i++) { int x = dx * (int)(a * i + 0.5); int y = dy * i; DrawLineElement(from_x + x, from_y + y, element, change_level); } } } } static void DrawBox(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 DrawArcExt(int from_x, int from_y, int to_x2, int to_y2, int element, boolean change_level) { int to_x = to_x2 - (to_x2 > from_x ? +1 : -1); int to_y = to_y2 - (to_y2 > from_y ? +1 : -1); int len_x = ABS(to_x - from_x); int len_y = ABS(to_y - from_y); int radius, x, y; radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5); /* not optimal (some points get drawn twice) but simple, and fast enough for the few points we are drawing */ for (x = 0; x <= radius; x++) { int sx, sy, lx, ly; y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5); sx = from_x + x * (from_x < to_x2 ? +1 : -1); sy = from_y + y * (from_y < to_y2 ? +1 : -1); lx = sx + level_xpos; ly = sy + level_ypos; if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) DrawLineElement(sx, sy, element, change_level); } for (y = 0; y <= radius; y++) { int sx, sy, lx, ly; x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5); sx = from_x + x * (from_x < to_x2 ? +1 : -1); sy = from_y + y * (from_y < to_y2 ? +1 : -1); lx = sx + level_xpos; ly = sy + level_ypos; if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) DrawLineElement(sx, sy, element, change_level); } } static void DrawArc(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int to_x2 = to_x + (to_x < from_x ? -1 : +1); int to_y2 = to_y + (to_y > from_y ? +1 : -1); DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level); } #define DRAW_CIRCLES_BUTTON_AVAILABLE 0 #if DRAW_CIRCLES_BUTTON_AVAILABLE static void DrawCircle(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int to_x2 = to_x + (to_x < from_x ? -1 : +1); int to_y2 = to_y + (to_y > from_y ? +1 : -1); int mirror_to_x2 = from_x - (to_x2 - from_x); int mirror_to_y2 = from_y - (to_y2 - from_y); DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level); DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level); DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level); DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level); } #endif 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; DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy); DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy); DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy); DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy); 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) DrawBox(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_CURSOR 1 #define CB_BRUSH_TO_LEVEL 2 #define CB_DELETE_OLD_CURSOR 3 #define CB_DUMP_BRUSH 4 #define CB_DUMP_BRUSH_SMALL 5 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int button, int mode) { #if 1 static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; #else static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY]; #endif static int brush_width, brush_height; static int last_cursor_x = -1, last_cursor_y = -1; static boolean delete_old_brush; int new_element = BUTTON_ELEMENT(button); int x, y; if (mode == CB_DUMP_BRUSH || mode == CB_DUMP_BRUSH_SMALL) { if (!draw_with_brush) { Error(ERR_WARN, "no brush selected"); return; } for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { int element = brush_buffer[x][y]; int element_mapped = element; if (IS_CUSTOM_ELEMENT(element)) element_mapped = EL_CUSTOM_START; else if (IS_GROUP_ELEMENT(element)) element_mapped = EL_GROUP_START; else if (element >= NUM_FILE_ELEMENTS) element_mapped = EL_UNKNOWN; printf("%c%03d", (mode == CB_DUMP_BRUSH ? '`' : '¸'), element_mapped); } printf("\n"); } return; } if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush) return; if (mode == CB_AREA_TO_BRUSH) { int from_lx, from_ly; if (from_x > to_x) swap_numbers(&from_x, &to_x); if (from_y > to_y) swap_numbers(&from_y, &to_y); brush_width = to_x - from_x + 1; brush_height = to_y - from_y + 1; from_lx = from_x + level_xpos; from_ly = from_y + level_ypos; for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { brush_buffer[x][y] = Feld[from_lx + x][from_ly + y]; if (button != 1) DrawLineElement(from_x + x, from_y + y, new_element, TRUE); } } if (button != 1) CopyLevelToUndoBuffer(UNDO_IMMEDIATE); delete_old_brush = FALSE; } else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR || mode == CB_BRUSH_TO_LEVEL) { int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x); int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y); int cursor_from_x = cursor_x - brush_width / 2; int cursor_from_y = cursor_y - brush_height / 2; int border_from_x = cursor_x, border_from_y = cursor_y; int border_to_x = cursor_x, border_to_y = cursor_y; if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush) CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR); if (!IN_ED_FIELD(cursor_x, cursor_y) || !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos)) { delete_old_brush = FALSE; return; } for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { int sx = cursor_from_x + x; int sy = cursor_from_y + y; int lx = sx + level_xpos; int ly = sy + level_ypos; boolean change_level = (mode == CB_BRUSH_TO_LEVEL); int element = (mode == CB_DELETE_OLD_CURSOR ? -1 : mode == CB_BRUSH_TO_CURSOR || button == 1 ? brush_buffer[x][y] : new_element); if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) { if (sx < border_from_x) border_from_x = sx; else if (sx > border_to_x) border_to_x = sx; if (sy < border_from_y) border_from_y = sy; else if (sy > border_to_y) border_to_y = sy; DrawLineElement(sx, sy, element, change_level); } } } if (mode != CB_DELETE_OLD_CURSOR) DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y); last_cursor_x = cursor_x; last_cursor_y = cursor_y; delete_old_brush = TRUE; } } static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y, int button) { CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH); } static void CopyBrushToLevel(int x, int y, int button) { CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL); } static void CopyBrushToCursor(int x, int y) { CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR); } static void DeleteBrushFromCursor() { CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR); } void DumpBrush() { CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH); } void DumpBrush_Small() { CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL); } static void FloodFill(int from_x, int from_y, int fill_element) { FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy); } /* 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 #define TEXT_QUERY_TYPING 6 static int 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 = 0, ly = 0; /* map lower case letters to upper case and convert special characters */ if (letter >= 'a' && letter <= 'z') letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a'); else if (letter == 'ä' || letter == 'Ä') letter_element = EL_CHAR_AUMLAUT; else if (letter == 'ö' || letter == 'Ö') letter_element = EL_CHAR_OUMLAUT; else if (letter == 'ü' || letter == 'Ü') letter_element = EL_CHAR_UUMLAUT; else if (letter == '^') letter_element = EL_CHAR_COPYRIGHT; else letter_element = EL_CHAR_ASCII0 + letter; if (mode != TEXT_INIT) { if (!typing) return FALSE; 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 < ed_fieldx && lx + 1 < lev_fieldx) DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR); else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy) DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); else DrawLevelText(0, 0, 0, TEXT_END); level.changed = TRUE; } break; case TEXT_BACKSPACE: if (sx > start_sx) { Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1]; DrawMiniElement(sx - 1, sy, Feld[lx - 1][ly]); DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR); } break; case TEXT_NEWLINE: if (sy + 1 < ed_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(UNDO_IMMEDIATE); DrawMiniElement(sx, sy, Feld[lx][ly]); typing = FALSE; break; case TEXT_QUERY_TYPING: break; default: break; } return typing; } static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy, int element, boolean change_level) { int lx = sx + level_xpos; int ly = sy + level_ypos; if (element == -1) DrawMiniElement(sx, sy, Feld[lx][ly]); else DrawAreaBorder(sx, sy, sx, sy); } static void CheckLevelBorderElement(boolean redraw_playfield) { int last_border_element = BorderElement; SetBorderElement(); if (redraw_playfield && BorderElement != last_border_element) DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); } static void CopyLevelToUndoBuffer(int mode) { static boolean accumulated_undo = FALSE; boolean new_undo_buffer_position = TRUE; int x, y; switch (mode) { case UNDO_IMMEDIATE: accumulated_undo = FALSE; break; case UNDO_ACCUMULATE: if (accumulated_undo) new_undo_buffer_position = FALSE; accumulated_undo = TRUE; break; default: break; } if (new_undo_buffer_position) { /* new position in undo buffer ring */ 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 < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) UndoBuffer[undo_buffer_position][x][y] = Feld[x][y]; /* check if drawing operation forces change of border style */ CheckLevelBorderElement(TRUE); level.changed = TRUE; } static void RandomPlacement(int new_element) { static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int num_free_positions = 0; int num_percentage, num_elements; int x, y; #if 1 ResetIntelliDraw(); #endif /* determine number of free positions for randomly placing the new element */ for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) { free_position[x][y] = (random_placement_background_restricted ? Feld[x][y] == random_placement_background_element : Feld[x][y] != new_element); if (free_position[x][y]) num_free_positions++; } /* determine number of new elements to place there */ num_percentage = num_free_positions * random_placement_value / 100; num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ? num_percentage : random_placement_value); /* if less free positions than elements to place, fill all these positions */ if (num_free_positions < num_elements) { for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) if (free_position[x][y]) #if 1 SetElement(x, y, new_element); #else Feld[x][y] = new_element; #endif } else { while (num_elements > 0) { x = GetSimpleRandom(lev_fieldx); y = GetSimpleRandom(lev_fieldy); /* don't place element at the same position twice */ if (free_position[x][y]) { free_position[x][y] = FALSE; #if 1 SetElement(x, y, new_element); #else Feld[x][y] = new_element; #endif num_elements--; } } } DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } void WrapLevel(int dx, int dy) { int wrap_dx = lev_fieldx - dx; int wrap_dy = lev_fieldy - dy; int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) FieldBackup[x][y] = Feld[x][y]; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) Feld[x][y] = FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy]; DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_ACCUMULATE); } static void HandleDrawingAreas(struct GadgetInfo *gi) { static boolean started_inside_drawing_area = FALSE; int id = gi->custom_id; boolean button_press_event; boolean button_release_event; boolean inside_drawing_area = !gi->event.off_borders; boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL); int actual_drawing_function; int button = gi->event.button; int new_element = BUTTON_ELEMENT(button); int sx = gi->event.x, sy = gi->event.y; int min_sx = 0, min_sy = 0; int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1; int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize; int lx = 0, ly = 0; int min_lx = 0, min_ly = 0; int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1; int x, y; /* handle info callback for each invocation of action callback */ gi->callback_info(gi); button_press_event = (gi->event.type == GD_EVENT_PRESSED); button_release_event = (gi->event.type == GD_EVENT_RELEASED); /* make sure to stay inside drawing area boundaries */ sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx); sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy); if (draw_level) { /* get positions inside level field */ lx = sx + level_xpos; ly = sy + level_ypos; if (!IN_LEV_FIELD(lx, ly)) inside_drawing_area = FALSE; /* make sure to stay inside level field boundaries */ lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx); ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly); /* correct drawing area positions accordingly */ sx = lx - level_xpos; sy = ly - level_ypos; } if (button_press_event) started_inside_drawing_area = inside_drawing_area; if (!started_inside_drawing_area) return; if (!IS_VALID_BUTTON(button)) return; if (!button && !button_release_event) return; /* automatically switch to 'single item' drawing mode, if needed */ actual_drawing_function = (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ? drawing_function : GADGET_ID_SINGLE_ITEMS); /* clicking into drawing area with pressed Control key picks element */ if (GetKeyModState() & KMOD_Control) { last_drawing_function = drawing_function; actual_drawing_function = GADGET_ID_PICK_ELEMENT; } if (GetKeyModState() & KMOD_Shift) { if (button_press_event || button_release_event) ResetIntelliDraw(); } switch (actual_drawing_function) { case GADGET_ID_SINGLE_ITEMS: if (draw_level) { if (button_release_event) { CopyLevelToUndoBuffer(UNDO_IMMEDIATE); if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !inside_drawing_area) DeleteBrushFromCursor(); #if 0 ResetIntelliDraw(); #endif } if (!button || button_release_event) break; if (draw_with_brush) { #if 0 if (!button_release_event) #endif CopyBrushToLevel(sx, sy, button); } #if 1 else #else else if (new_element != Feld[lx][ly]) #endif { if (new_element == EL_PLAYER_1) { /* remove player at old position */ for (y = 0; y < lev_fieldy; y++) { for (x = 0; x < lev_fieldx; x++) { if (Feld[x][y] == EL_PLAYER_1) { #if 1 SetElement(x, y, EL_EMPTY); #else Feld[x][y] = EL_EMPTY; #if 1 if (IN_ED_FIELD(x - level_xpos, y - level_ypos)) DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY); #else if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx && y - level_ypos >= 0 && y - level_ypos < ed_fieldy) DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY); #endif #endif } } } } #if 1 SetElementButton(lx, ly, new_element, button); #else Feld[lx][ly] = new_element; DrawMiniElement(sx, sy, new_element); #endif } } else { int type_id = gi->custom_type_id; int pos = sx * drawingarea_info[type_id].area_ysize + sy; if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY) DrawMiniGraphicExt(drawto, gi->x + sx * MINI_TILEX, gi->y + sy * MINI_TILEY, el2edimg(new_element)); else DrawGraphicExt(drawto, gi->x + sx * TILEX, gi->y + sy * TILEY, el2img(new_element), 0); if (id == GADGET_ID_CUSTOM_GRAPHIC) new_element = GFX_ELEMENT(new_element); drawingarea_info[type_id].value[pos] = new_element; CopyElementPropertiesToGame(properties_element); if (id == GADGET_ID_CUSTOM_GRAPHIC) { UpdateCustomElementGraphicGadgets(); FrameCounter = 0; /* restart animation frame counter */ } } break; case GADGET_ID_CONNECTED_ITEMS: { static int last_sx = -1; static int last_sy = -1; if (button_release_event) CopyLevelToUndoBuffer(UNDO_IMMEDIATE); if (button) { if (!button_press_event) DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE); last_sx = sx; last_sy = sy; } } break; case GADGET_ID_LINE: case GADGET_ID_ARC: case GADGET_ID_RECTANGLE: case GADGET_ID_FILLED_BOX: case GADGET_ID_GRAB_BRUSH: case GADGET_ID_TEXT: { 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 == GADGET_ID_LINE) draw_func = DrawLine; else if (drawing_function == GADGET_ID_ARC) draw_func = DrawArc; else if (drawing_function == GADGET_ID_RECTANGLE) draw_func = DrawBox; else if (drawing_function == GADGET_ID_FILLED_BOX) draw_func = DrawFilledBox; else if (drawing_function == GADGET_ID_GRAB_BRUSH) draw_func = SelectArea; else /* (drawing_function == GADGET_ID_TEXT) */ draw_func = SetTextCursor; if (button_press_event) { draw_func(sx, sy, sx, sy, new_element, FALSE); start_sx = last_sx = sx; start_sy = last_sy = sy; if (drawing_function == GADGET_ID_TEXT) DrawLevelText(0, 0, 0, TEXT_END); } else if (button_release_event) { draw_func(start_sx, start_sy, sx, sy, new_element, TRUE); if (drawing_function == GADGET_ID_GRAB_BRUSH) { CopyAreaToBrush(start_sx, start_sy, sx, sy, button); CopyBrushToCursor(sx, sy); ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON); draw_with_brush = TRUE; } else if (drawing_function == GADGET_ID_TEXT) DrawLevelText(sx, sy, 0, TEXT_INIT); else CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } 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 GADGET_ID_FLOOD_FILL: if (button_press_event && Feld[lx][ly] != new_element) { FloodFill(lx, ly, new_element); DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } break; case GADGET_ID_PICK_ELEMENT: if (button_release_event) ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); else if (draw_level) PickDrawingElement(button, Feld[lx][ly]); else { int type_id = gi->custom_type_id; int pos = sx * drawingarea_info[type_id].area_ysize + sy; PickDrawingElement(button, drawingarea_info[type_id].value[pos]); } break; default: break; } } static void HandleCounterButtons(struct GadgetInfo *gi) { int gadget_id = gi->custom_id; int counter_id = gi->custom_type_id; int button = gi->event.button; int *counter_value = counterbutton_info[counter_id].value; int step = BUTTON_STEPSIZE(button) * (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1); if (counter_id == ED_COUNTER_ID_SELECT_LEVEL) { boolean pressed = (gi->event.type == GD_EVENT_PRESSED); boolean released = (gi->event.type == GD_EVENT_RELEASED); boolean level_changed = LevelChanged(); if ((level_changed && pressed) || (!level_changed && released)) return; if (level_changed && !Request("Level has changed ! Discard changes ?", REQ_ASK)) { if (gadget_id == counterbutton_info[counter_id].gadget_id_text) ModifyEditorCounterValue(counter_id, *counter_value); return; } } if (gadget_id == counterbutton_info[counter_id].gadget_id_text) *counter_value = gi->textinput.number_value; else ModifyEditorCounterValue(counter_id, *counter_value + step); if (counter_id == ED_COUNTER_ID_SELECT_LEVEL) { LoadLevel(level_nr); LoadScore(level_nr); TapeErase(); ResetUndoBuffer(); DrawEditModeWindow(); return; } switch (counter_id) { case ED_COUNTER_ID_YAMYAM_CONTENT: DrawYamYamContentAreas(); break; case ED_COUNTER_ID_BALL_CONTENT: DrawMagicBallContentAreas(); break; case ED_COUNTER_ID_ANDROID_CONTENT: DrawAndroidElementArea(properties_element); break; case ED_COUNTER_ID_GROUP_CONTENT: DrawGroupElementArea(properties_element); CopyGroupElementPropertiesToGame(properties_element); break; case ED_COUNTER_ID_INVENTORY_SIZE: DrawPlayerInitialInventoryArea(properties_element); break; case ED_COUNTER_ID_ENVELOPE_XSIZE: case ED_COUNTER_ID_ENVELOPE_YSIZE: DrawEnvelopeTextArea(-1); break; case ED_COUNTER_ID_LEVEL_XSIZE: case ED_COUNTER_ID_LEVEL_YSIZE: lev_fieldx = level.fieldx; lev_fieldy = level.fieldy; break; default: break; } if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST && counter_id <= ED_COUNTER_ID_CUSTOM_LAST) || (counter_id >= ED_COUNTER_ID_CHANGE_FIRST && counter_id <= ED_COUNTER_ID_CHANGE_LAST)) CopyElementPropertiesToGame(properties_element); level.changed = TRUE; } static void HandleTextInputGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; strcpy(textinput_info[type_id].value, gi->textinput.value); if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME) { CopyElementPropertiesToGame(properties_element); ModifyEditorElementList(); /* update changed button info text */ } level.changed = TRUE; } static void HandleTextAreaGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; #if 1 strncpy(textarea_info[type_id].value, gi->textarea.value, MAX_ENVELOPE_TEXT_LEN); textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0'; #else /* !!! BUGGY !!! MAX_ENVELOPE_TEXT_LEN != MAX_GADGET_TEXTSIZE !!! */ strcpy(textarea_info[type_id].value, gi->textarea.value); #endif level.changed = TRUE; } static void HandleSelectboxGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; int value_old = *selectbox_info[type_id].value; int value_new = selectbox_info[type_id].options[gi->selectbox.index].value; *selectbox_info[type_id].value = value_new; if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE) { element_info[properties_element].current_change_page = gi->selectbox.index; DrawPropertiesWindow(); } else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST && type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) || (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST && type_id <= ED_SELECTBOX_ID_CHANGE_LAST) || (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE)) { if (type_id == ED_SELECTBOX_ID_ACTION_TYPE) { /* when changing action type, also check action mode and action arg */ if (value_old != value_new) setSelectboxSpecialActionVariablesIfNeeded(); DrawPropertiesChange(); } CopyElementPropertiesToGame(properties_element); level.changed = TRUE; } } static void HandleTextbuttonGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; int i; if (type_id >= ED_TEXTBUTTON_ID_LEVELINFO_FIRST && type_id <= ED_TEXTBUTTON_ID_LEVELINFO_LAST) { edit_mode_levelinfo = gi->custom_type_id; DrawLevelInfoWindow(); } else if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST && type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST) { edit_mode_properties = gi->custom_type_id; DrawPropertiesWindow(); } else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE) { char *template_filename = getDefaultLevelFilename(-1); boolean new_template = !fileExists(template_filename); /* backup original "level.field" (needed to track playfield changes) */ CopyPlayfield(level.field, FieldBackup); /* "SaveLevelTemplate()" uses "level.field", so copy editor playfield */ CopyPlayfield(Feld, level.field); if (new_template || Request("Save this template and kill the old ?", REQ_ASK)) SaveLevelTemplate(); if (new_template) Request("Template saved !", REQ_CONFIRM); /* restore original "level.field" (needed to track playfield changes) */ CopyPlayfield(FieldBackup, level.field); } else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE && custom_element.num_change_pages < MAX_CHANGE_PAGES) { struct ElementInfo *ei = &element_info[properties_element]; setElementChangePages(ei, ei->num_change_pages + 1); /* set new change page to be new current change page */ ei->current_change_page = ei->num_change_pages - 1; ei->change = &ei->change_page[ei->current_change_page]; setElementChangeInfoToDefaults(ei->change); DrawPropertiesWindow(); level.changed = TRUE; } else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && custom_element.num_change_pages > MIN_CHANGE_PAGES) { struct ElementInfo *ei = &element_info[properties_element]; /* copy all change pages after change page to be deleted */ for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++) ei->change_page[i] = ei->change_page[i + 1]; setElementChangePages(ei, ei->num_change_pages - 1); DrawPropertiesWindow(); level.changed = TRUE; } } static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE || type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE) { struct ElementInfo *ei = &element_info[properties_element]; int step = BUTTON_STEPSIZE(gi->event.button); step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1); ei->current_change_page += step; if (ei->current_change_page < 0) ei->current_change_page = 0; else if (ei->current_change_page >= ei->num_change_pages) ei->current_change_page = ei->num_change_pages - 1; DrawPropertiesWindow(); } else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE || type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) { struct ElementInfo *ei = &element_info[properties_element]; int current_change_page = ei->current_change_page; if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE) element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] = ei->change_page[current_change_page]; else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) { ei->change_page[current_change_page] = element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0]; level.changed = TRUE; } DrawPropertiesWindow(); } } static void HandleRadiobuttons(struct GadgetInfo *gi) { *radiobutton_info[gi->custom_type_id].value = radiobutton_info[gi->custom_type_id].checked_value; level.changed = TRUE; } static void HandleCheckbuttons(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; *checkbutton_info[type_id].value ^= TRUE; if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID || type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID || type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH || (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST && type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) || (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST && type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) && type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)) { CopyElementPropertiesToGame(properties_element); } if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC) { UpdateCustomElementGraphicGadgets(); } else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE) { char *template_filename = getDefaultLevelFilename(-1); if (level.use_custom_template && !fileExists(template_filename)) { Request("No level template found !", REQ_CONFIRM); level.use_custom_template = FALSE; ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END); return; } LoadLevelTemplate(level.use_custom_template ? -1 : level_nr); DrawEditModeWindow(); } level.changed = TRUE; } static void HandleControlButtons(struct GadgetInfo *gi) { static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS; static int last_edit_mode = ED_MODE_DRAWING; static int last_custom_copy_mode = -1; int id = gi->custom_id; int button = gi->event.button; int step = BUTTON_STEPSIZE(button); int new_element = BUTTON_ELEMENT(button); int x, y; if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT) DrawLevelText(0, 0, 0, TEXT_END); if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_SINGLE_ITEMS && id != GADGET_ID_PROPERTIES && id != GADGET_ID_PICK_ELEMENT && edit_mode != ED_MODE_DRAWING && drawing_function != GADGET_ID_PICK_ELEMENT && !(GetKeyModState() & KMOD_Control)) { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; } /* element copy mode active, but no element button pressed => deactivate */ if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS) last_custom_copy_mode = -1; switch (id) { case GADGET_ID_SCROLL_LEFT: if (level_xpos >= 0) { if (lev_fieldx < ed_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(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END); } break; case GADGET_ID_SCROLL_RIGHT: if (level_xpos <= lev_fieldx - ed_fieldx) { if (lev_fieldx < ed_fieldx - 2) break; level_xpos += step; if (level_xpos > lev_fieldx - ed_fieldx + 1) level_xpos = lev_fieldx - ed_fieldx + 1; if (button == 1) ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT); else DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END); } break; case GADGET_ID_SCROLL_UP: if (level_ypos >= 0) { if (lev_fieldy < ed_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(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END); } break; case GADGET_ID_SCROLL_DOWN: if (level_ypos <= lev_fieldy - ed_fieldy) { if (lev_fieldy < ed_fieldy - 2) break; level_ypos += step; if (level_ypos > lev_fieldy - ed_fieldy + 1) level_ypos = lev_fieldy - ed_fieldy + 1; if (button == 1) ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP); else DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END); } break; case GADGET_ID_SCROLL_HORIZONTAL: level_xpos = gi->event.item_position - 1; DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_SCROLL_VERTICAL: level_ypos = gi->event.item_position - 1; DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_SCROLL_LIST_UP: case GADGET_ID_SCROLL_LIST_DOWN: case GADGET_ID_SCROLL_LIST_VERTICAL: if (id == GADGET_ID_SCROLL_LIST_VERTICAL) element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ; else { step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1); element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ; if (element_shift < 0) element_shift = 0; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); } ModifyEditorElementList(); break; case GADGET_ID_WRAP_LEFT: WrapLevel(-step, 0); break; case GADGET_ID_WRAP_RIGHT: WrapLevel(step, 0); break; case GADGET_ID_WRAP_UP: WrapLevel(0, -step); break; case GADGET_ID_WRAP_DOWN: WrapLevel(0, step); break; case GADGET_ID_SINGLE_ITEMS: case GADGET_ID_CONNECTED_ITEMS: case GADGET_ID_LINE: case GADGET_ID_ARC: case GADGET_ID_TEXT: case GADGET_ID_RECTANGLE: case GADGET_ID_FILLED_BOX: case GADGET_ID_FLOOD_FILL: case GADGET_ID_GRAB_BRUSH: case GADGET_ID_PICK_ELEMENT: if (drawing_function != GADGET_ID_PICK_ELEMENT) last_drawing_function = drawing_function; drawing_function = id; draw_with_brush = FALSE; break; case GADGET_ID_RANDOM_PLACEMENT: RandomPlacement(new_element); break; case GADGET_ID_PROPERTIES: if (edit_mode != ED_MODE_PROPERTIES) { properties_element = new_element; DrawPropertiesWindow(); edit_mode = ED_MODE_PROPERTIES; last_level_drawing_function = drawing_function; ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON); } else { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; ClickOnGadget(level_editor_gadget[last_level_drawing_function], MB_LEFTBUTTON); } break; case GADGET_ID_CUSTOM_COPY_FROM: case GADGET_ID_CUSTOM_COPY_TO: case GADGET_ID_CUSTOM_EXCHANGE: last_custom_copy_mode = id; last_drawing_function = drawing_function; break; case GADGET_ID_CUSTOM_COPY: CopyCustomElement(properties_element, -1, id); break; case GADGET_ID_CUSTOM_PASTE: CopyCustomElement(-1, properties_element, id); break; case GADGET_ID_UNDO: if (undo_buffer_steps == 0) { Request("Undo buffer empty !", REQ_CONFIRM); break; } if (edit_mode != ED_MODE_DRAWING) { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; } undo_buffer_position = (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS; undo_buffer_steps--; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) Feld[x][y] = UndoBuffer[undo_buffer_position][x][y]; /* check if undo operation forces change of border style */ CheckLevelBorderElement(FALSE); DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_INFO: if (edit_mode != ED_MODE_INFO) { last_edit_mode = edit_mode; edit_mode = ED_MODE_INFO; DrawLevelInfoWindow(); } else { edit_mode = last_edit_mode; DrawEditModeWindow(); } break; case GADGET_ID_CLEAR: if (edit_mode != ED_MODE_DRAWING) { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; } for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) Feld[x][y] = (button == 1 ? EL_EMPTY : new_element); CopyLevelToUndoBuffer(GADGET_ID_CLEAR); DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_SAVE: { /* saving read-only levels into personal level set modifies global vars "leveldir_current" and "level_nr"; restore them after saving level */ LevelDirTree *leveldir_former = leveldir_current; int level_nr_former = level_nr; char *level_filename; boolean new_level; if (leveldir_current->readonly && !PrepareSavingIntoPersonalLevelSet()) break; level_filename = getDefaultLevelFilename(level_nr); new_level = !fileExists(level_filename); if (new_level || Request("Save this level and kill the old ?", REQ_ASK)) { if (leveldir_former->readonly) ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name); CopyPlayfield(Feld, level.field); SaveLevel(level_nr); level.changed = FALSE; if (new_level) { char level_saved_msg[64]; if (leveldir_former->readonly) sprintf(level_saved_msg, "Level saved as level %d into personal level set !", level_nr); else strcpy(level_saved_msg, "Level saved !"); Request(level_saved_msg, REQ_CONFIRM); } } /* "cd" back to copied-from levelset (in case of saved read-only level) */ leveldir_current = leveldir_former; level_nr = level_nr_former; break; } case GADGET_ID_TEST: if (LevelChanged()) level.game_version = GAME_VERSION_ACTUAL; CopyPlayfield(level.field, FieldBackup); CopyPlayfield(Feld, level.field); CopyNativeLevel_RND_to_Native(&level); UnmapLevelEditorGadgets(); UndrawSpecialEditorDoor(); CloseDoor(DOOR_CLOSE_ALL); BackToFront(); /* force redraw of undrawn special door */ #if 0 DrawCompleteVideoDisplay(); #endif level_editor_test_game = TRUE; StartGameActions(FALSE, setup.autorecord, level.random_seed); break; case GADGET_ID_EXIT: RequestExitLevelEditor(TRUE, FALSE); /* if level has changed, ask user */ break; default: if (id >= GADGET_ID_ELEMENTLIST_FIRST && id <= GADGET_ID_ELEMENTLIST_LAST) { int element_position = id - GADGET_ID_ELEMENTLIST_FIRST; int new_element = editor_elements[element_position + element_shift]; if (IS_EDITOR_CASCADE(new_element)) { int i; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { int *cascade_element= &(*editor_elements_info[i].headline_list)[0]; boolean *cascade_value=editor_elements_info[i].setup_cascade_value; if (*cascade_element == new_element) { *cascade_element = EL_CASCADE_TOGGLE(*cascade_element); *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element); /* update element selection list */ ReinitializeElementList(); ModifyEditorElementList(); /* update cascading gadget info text */ PrintEditorGadgetInfoText(level_editor_gadget[id]); /* save current editor cascading state */ SaveSetup_EditorCascade(); break; } } break; } if (last_custom_copy_mode != -1) { if (CopyCustomElement(properties_element, new_element, last_custom_copy_mode)) { ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); last_custom_copy_mode = -1; } break; } PickDrawingElement(button, new_element); if (!stick_element_properties_window && drawing_function != GADGET_ID_PICK_ELEMENT && !(GetKeyModState() & KMOD_Control)) { properties_element = new_element; if (edit_mode == ED_MODE_PROPERTIES) DrawPropertiesWindow(); } if (drawing_function == GADGET_ID_PICK_ELEMENT) ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); } #ifdef DEBUG else if (gi->event.type == GD_EVENT_PRESSED) printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id); else if (gi->event.type == GD_EVENT_RELEASED) printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id); else if (gi->event.type == GD_EVENT_MOVING) printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id); else printf("default: HandleControlButtons: ? (id == %d)\n", id); #endif break; } } void HandleLevelEditorKeyInput(Key key) { char letter = getCharFromKey(key); int button = MB_LEFTBUTTON; if (drawing_function == GADGET_ID_TEXT && DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE) { if (letter) DrawLevelText(0, 0, letter, TEXT_WRITECHAR); else if (key == KSYM_Delete || key == KSYM_BackSpace) DrawLevelText(0, 0, 0, TEXT_BACKSPACE); else if (key == KSYM_Return) DrawLevelText(0, 0, 0, TEXT_NEWLINE); else if (key == KSYM_Escape) DrawLevelText(0, 0, 0, TEXT_END); } else if (button_status == MB_RELEASED) { int id = GADGET_ID_NONE; int new_element_shift = element_shift; int i; switch (key) { case KSYM_Left: id = GADGET_ID_SCROLL_LEFT; break; case KSYM_Right: id = GADGET_ID_SCROLL_RIGHT; break; case KSYM_Up: id = GADGET_ID_SCROLL_UP; break; case KSYM_Down: id = GADGET_ID_SCROLL_DOWN; break; case KSYM_Page_Up: id = GADGET_ID_SCROLL_LIST_UP; button = MB_RIGHTBUTTON; break; case KSYM_Page_Down: id = GADGET_ID_SCROLL_LIST_DOWN; button = MB_RIGHTBUTTON; break; case KSYM_Home: case KSYM_End: element_shift = (key == KSYM_Home ? 0 : num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); ModifyEditorElementList(); break; case KSYM_Insert: case KSYM_Delete: /* this is needed to prevent interference with running "True X-Mouse" */ if (GetKeyModStateFromEvents() & KMOD_Control) break; /* check for last or next editor cascade block in element list */ for (i = 0; i < num_editor_elements; i++) { if ((key == KSYM_Insert && i == element_shift) || (key == KSYM_Delete && new_element_shift > element_shift)) break; /* jump to next cascade block (or to start of element list) */ if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i])) new_element_shift = i; } if (i < num_editor_elements) element_shift = new_element_shift; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); ModifyEditorElementList(); break; case KSYM_Escape: if (edit_mode == ED_MODE_DRAWING) { RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE); } else if (edit_mode == ED_MODE_INFO) { HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]); } else if (edit_mode == ED_MODE_PROPERTIES) { HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]); } else /* should never happen */ { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; } break; default: break; } if (id != GADGET_ID_NONE) ClickOnGadget(level_editor_gadget[id], button); else if (letter == '.') ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button); else if (key == KSYM_Return || key == KSYM_space || key == setup.shortcut.toggle_pause) ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button); else for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) if (letter && letter == control_info[i].shortcut) if (!anyTextGadgetActive()) ClickOnGadget(level_editor_gadget[i], button); } } void HandleLevelEditorIdle() { static unsigned long action_delay = 0; unsigned long action_delay_value = GameFrameDelay; int xpos = 1, ypos = 2; int i; if (edit_mode != ED_MODE_PROPERTIES) return; if (!DelayReached(&action_delay, action_delay_value)) return; for (i = 0; i < ED_NUM_SELECTBOX; i++) { struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id]; if (gi->mapped && gi->active && gi->selectbox.open) return; } DrawEditorElementAnimation(SX + xpos * TILEX, SY + ypos * TILEY + MINI_TILEY / 2); MarkTileDirty(xpos, ypos); MarkTileDirty(xpos, ypos + 1); FrameCounter++; /* increase animation frame counter */ } void ClearEditorGadgetInfoText() { DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE); } void PrintEditorGadgetInfoText(struct GadgetInfo *gi) { char infotext[MAX_OUTPUT_LINESIZE + 1]; char shortcut[MAX_OUTPUT_LINESIZE + 1]; int max_infotext_len = getMaxInfoTextLength(); if (gi == NULL || gi->info_text == NULL) return; strncpy(infotext, gi->info_text, max_infotext_len); infotext[max_infotext_len] = '\0'; if (gi->custom_id < ED_NUM_CTRL_BUTTONS) { int key = control_info[gi->custom_id].shortcut; if (key) { if (gi->custom_id == GADGET_ID_SINGLE_ITEMS) /* special case 1 */ sprintf(shortcut, " ('.' or '%c')", key); else if (gi->custom_id == GADGET_ID_PICK_ELEMENT) /* special case 2 */ sprintf(shortcut, " ('%c' or 'Ctrl')", key); else if (gi->custom_id == GADGET_ID_TEST) /* special case 3 */ sprintf(shortcut, " ('Enter' or 'Shift-%c')", key); else /* normal case */ sprintf(shortcut, " ('%s%c')", (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key); if (strlen(infotext) + strlen(shortcut) <= max_infotext_len) strcat(infotext, shortcut); } } DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2); } void HandleEditorGadgetInfoText(void *ptr) { struct GadgetInfo *gi = (struct GadgetInfo *)ptr; if (game_status != GAME_MODE_EDITOR) return; ClearEditorGadgetInfoText(); if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING) return; /* misuse this function to delete brush cursor, if needed */ if (edit_mode == ED_MODE_DRAWING && draw_with_brush) DeleteBrushFromCursor(); PrintEditorGadgetInfoText(gi); } static void HandleDrawingAreaInfo(struct GadgetInfo *gi) { static int start_lx, start_ly; int id = gi->custom_id; int type_id = gi->custom_type_id; int sx = gi->event.x; int sy = gi->event.y; int lx = sx + level_xpos; int ly = sy + level_ypos; int min_sx = 0, min_sy = 0; int max_sx = gi->drawing.area_xsize - 1; int max_sy = gi->drawing.area_ysize - 1; int actual_drawing_function = drawing_function; int max_infotext_len = getMaxInfoTextLength(); char infotext[MAX_OUTPUT_LINESIZE + 1]; char *text; infotext[0] = '\0'; /* start with empty info text */ /* pressed Control key: simulate picking element */ if (GetKeyModState() & KMOD_Control) actual_drawing_function = GADGET_ID_PICK_ELEMENT; ClearEditorGadgetInfoText(); if (gi->event.type == GD_EVENT_INFO_LEAVING) return; /* make sure to stay inside drawing area boundaries */ sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx); sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy); if (id == GADGET_ID_DRAWING_LEVEL) { if (button_status) { int min_lx = 0, min_ly = 0; int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1; /* get positions inside level field */ lx = sx + level_xpos; ly = sy + level_ypos; /* make sure to stay inside level field boundaries */ lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx); ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly); /* correct drawing area positions accordingly */ sx = lx - level_xpos; sy = ly - level_ypos; } if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly)) { if (button_status) /* if (gi->state == GD_BUTTON_PRESSED) */ { if (gi->event.type == GD_EVENT_PRESSED) { start_lx = lx; start_ly = ly; } switch (actual_drawing_function) { case GADGET_ID_SINGLE_ITEMS: text = "Drawing single items"; break; case GADGET_ID_CONNECTED_ITEMS: text = "Drawing connected items"; break; case GADGET_ID_LINE: text = "Drawing line"; break; case GADGET_ID_ARC: text = "Drawing arc"; break; case GADGET_ID_TEXT: text = "Setting text cursor"; break; case GADGET_ID_RECTANGLE: text = "Drawing rectangle"; break; case GADGET_ID_FILLED_BOX: text = "Drawing filled box"; break; case GADGET_ID_FLOOD_FILL: text = "Flood fill"; break; case GADGET_ID_GRAB_BRUSH: text = "Grabbing brush"; break; case GADGET_ID_PICK_ELEMENT: text = "Picking element"; break; default: text = "Drawing position"; break; } if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) sprintf(infotext, "%s: %d, %d", text, lx, ly); else sprintf(infotext, "%s: %d, %d", text, ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1); } else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len); else sprintf(infotext, "Level position: %d, %d", lx, ly); } /* misuse this function to draw brush cursor, if needed */ if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status) { if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) CopyBrushToCursor(sx, sy); else DeleteBrushFromCursor(); } } else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) { int pos = sx * drawingarea_info[type_id].area_ysize + sy; int element = drawingarea_info[type_id].value[pos]; strncpy(infotext, getElementInfoText(element), max_infotext_len); } else { if (id == GADGET_ID_CUSTOM_CONTENT) sprintf(infotext, "custom element content position: %d, %d", sx, sy); else if (id == GADGET_ID_GROUP_CONTENT) sprintf(infotext, "group element position: %d", sx + 1); else if (id >= GADGET_ID_YAMYAM_CONTENT_0 && id <= GADGET_ID_YAMYAM_CONTENT_7) sprintf(infotext, "content area %d position: %d, %d", id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy); else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 && id <= GADGET_ID_MAGIC_BALL_CONTENT_7) sprintf(infotext, "content area %d position: %d, %d", id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy); else if (id == GADGET_ID_ANDROID_CONTENT) sprintf(infotext, "android element position: %d", sx + 1); else if (drawingarea_info[type_id].infotext != NULL) strcpy(infotext, drawingarea_info[type_id].infotext); } infotext[max_infotext_len] = '\0'; if (strlen(infotext) > 0) DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, infotext); } void RequestExitLevelEditor(boolean ask_if_level_has_changed, boolean quick_quit) { if (!ask_if_level_has_changed || !LevelChanged() || Request("Level has changed ! Exit without saving ?", REQ_ASK | REQ_STAY_OPEN)) { CloseDoor(DOOR_CLOSE_1); SetDoorState(DOOR_CLOSE_2); #if 1 if (quick_quit) FadeSkipNextFadeIn(); #else if (quick_quit) fading = fading_none; #endif game_status = GAME_MODE_MAIN; #if 1 DrawAndFadeInMainMenu(REDRAW_FIELD); #else DrawMainMenu(); #endif } else { CloseDoor(DOOR_CLOSE_1); OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); } } rocksndiamonds-3.3.0.1+dfsg1/src/cartoons.h0000644000175000017500000000144210471547362017430 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * cartoons.h * ***********************************************************/ #ifndef CARTOONS_H #define CARTOONS_H void InitToons(void); #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_g2s.c0000644000175000017500000000300111375255512017261 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_g2s.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_G2S_C #define CONF_G2S_C /* values for gamemode/sound mapping configuration */ static struct { int gamemode; int sound; } gamemode_to_sound[] = { { GFX_SPECIAL_ARG_TITLE_INITIAL, SND_BACKGROUND_TITLE_INITIAL }, { GFX_SPECIAL_ARG_TITLE, SND_BACKGROUND_TITLE }, { GFX_SPECIAL_ARG_MAIN, SND_BACKGROUND_MAIN }, { GFX_SPECIAL_ARG_LEVELS, SND_BACKGROUND_LEVELS }, { GFX_SPECIAL_ARG_SCORES, SND_BACKGROUND_SCORES }, { GFX_SPECIAL_ARG_EDITOR, SND_BACKGROUND_EDITOR }, { GFX_SPECIAL_ARG_INFO, SND_BACKGROUND_INFO }, { GFX_SPECIAL_ARG_SETUP, SND_BACKGROUND_SETUP }, { -1, -1 }, }; #endif /* CONF_G2S_C */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_chr.c0000644000175000017500000005764211375255512017366 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_chr.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CHR_C #define CONF_CHR_C /* values for graphics configuration (character elements) */ { "char_space", "RocksFontEM.pcx" }, { "char_space.xpos", "0" }, { "char_space.ypos", "0" }, { "char_space.frames", "1" }, { "char_space.EDITOR", "RocksFontEM.pcx" }, { "char_space.EDITOR.xpos", "7" }, { "char_space.EDITOR.ypos", "4" }, { "char_space.EDITOR.frames", "1" }, { "char_exclam", "RocksFontEM.pcx" }, { "char_exclam.xpos", "1" }, { "char_exclam.ypos", "0" }, { "char_exclam.frames", "1" }, { "char_quotedbl", "RocksFontEM.pcx" }, { "char_quotedbl.xpos", "2" }, { "char_quotedbl.ypos", "0" }, { "char_quotedbl.frames", "1" }, { "char_numbersign", "RocksFontEM.pcx" }, { "char_numbersign.xpos", "3" }, { "char_numbersign.ypos", "0" }, { "char_numbersign.frames", "1" }, { "char_dollar", "RocksFontEM.pcx" }, { "char_dollar.xpos", "4" }, { "char_dollar.ypos", "0" }, { "char_dollar.frames", "1" }, { "char_percent", "RocksFontEM.pcx" }, { "char_percent.xpos", "5" }, { "char_percent.ypos", "0" }, { "char_percent.frames", "1" }, { "char_ampersand", "RocksFontEM.pcx" }, { "char_ampersand.xpos", "6" }, { "char_ampersand.ypos", "0" }, { "char_ampersand.frames", "1" }, { "char_apostrophe", "RocksFontEM.pcx" }, { "char_apostrophe.xpos", "7" }, { "char_apostrophe.ypos", "0" }, { "char_apostrophe.frames", "1" }, { "char_parenleft", "RocksFontEM.pcx" }, { "char_parenleft.xpos", "8" }, { "char_parenleft.ypos", "0" }, { "char_parenleft.frames", "1" }, { "char_parenright", "RocksFontEM.pcx" }, { "char_parenright.xpos", "9" }, { "char_parenright.ypos", "0" }, { "char_parenright.frames", "1" }, { "char_asterisk", "RocksFontEM.pcx" }, { "char_asterisk.xpos", "10" }, { "char_asterisk.ypos", "0" }, { "char_asterisk.frames", "1" }, { "char_plus", "RocksFontEM.pcx" }, { "char_plus.xpos", "11" }, { "char_plus.ypos", "0" }, { "char_plus.frames", "1" }, { "char_comma", "RocksFontEM.pcx" }, { "char_comma.xpos", "12" }, { "char_comma.ypos", "0" }, { "char_comma.frames", "1" }, { "char_minus", "RocksFontEM.pcx" }, { "char_minus.xpos", "13" }, { "char_minus.ypos", "0" }, { "char_minus.frames", "1" }, { "char_period", "RocksFontEM.pcx" }, { "char_period.xpos", "14" }, { "char_period.ypos", "0" }, { "char_period.frames", "1" }, { "char_slash", "RocksFontEM.pcx" }, { "char_slash.xpos", "15" }, { "char_slash.ypos", "0" }, { "char_slash.frames", "1" }, { "char_0", "RocksFontEM.pcx" }, { "char_0.xpos", "0" }, { "char_0.ypos", "1" }, { "char_0.frames", "1" }, { "char_1", "RocksFontEM.pcx" }, { "char_1.xpos", "1" }, { "char_1.ypos", "1" }, { "char_1.frames", "1" }, { "char_2", "RocksFontEM.pcx" }, { "char_2.xpos", "2" }, { "char_2.ypos", "1" }, { "char_2.frames", "1" }, { "char_3", "RocksFontEM.pcx" }, { "char_3.xpos", "3" }, { "char_3.ypos", "1" }, { "char_3.frames", "1" }, { "char_4", "RocksFontEM.pcx" }, { "char_4.xpos", "4" }, { "char_4.ypos", "1" }, { "char_4.frames", "1" }, { "char_5", "RocksFontEM.pcx" }, { "char_5.xpos", "5" }, { "char_5.ypos", "1" }, { "char_5.frames", "1" }, { "char_6", "RocksFontEM.pcx" }, { "char_6.xpos", "6" }, { "char_6.ypos", "1" }, { "char_6.frames", "1" }, { "char_7", "RocksFontEM.pcx" }, { "char_7.xpos", "7" }, { "char_7.ypos", "1" }, { "char_7.frames", "1" }, { "char_8", "RocksFontEM.pcx" }, { "char_8.xpos", "8" }, { "char_8.ypos", "1" }, { "char_8.frames", "1" }, { "char_9", "RocksFontEM.pcx" }, { "char_9.xpos", "9" }, { "char_9.ypos", "1" }, { "char_9.frames", "1" }, { "char_colon", "RocksFontEM.pcx" }, { "char_colon.xpos", "10" }, { "char_colon.ypos", "1" }, { "char_colon.frames", "1" }, { "char_semicolon", "RocksFontEM.pcx" }, { "char_semicolon.xpos", "11" }, { "char_semicolon.ypos", "1" }, { "char_semicolon.frames", "1" }, { "char_less", "RocksFontEM.pcx" }, { "char_less.xpos", "12" }, { "char_less.ypos", "1" }, { "char_less.frames", "1" }, { "char_equal", "RocksFontEM.pcx" }, { "char_equal.xpos", "13" }, { "char_equal.ypos", "1" }, { "char_equal.frames", "1" }, { "char_greater", "RocksFontEM.pcx" }, { "char_greater.xpos", "14" }, { "char_greater.ypos", "1" }, { "char_greater.frames", "1" }, { "char_question", "RocksFontEM.pcx" }, { "char_question.xpos", "15" }, { "char_question.ypos", "1" }, { "char_question.frames", "1" }, { "char_at", "RocksFontEM.pcx" }, { "char_at.xpos", "0" }, { "char_at.ypos", "2" }, { "char_at.frames", "1" }, { "char_a", "RocksFontEM.pcx" }, { "char_a.xpos", "1" }, { "char_a.ypos", "2" }, { "char_a.frames", "1" }, { "char_b", "RocksFontEM.pcx" }, { "char_b.xpos", "2" }, { "char_b.ypos", "2" }, { "char_b.frames", "1" }, { "char_c", "RocksFontEM.pcx" }, { "char_c.xpos", "3" }, { "char_c.ypos", "2" }, { "char_c.frames", "1" }, { "char_d", "RocksFontEM.pcx" }, { "char_d.xpos", "4" }, { "char_d.ypos", "2" }, { "char_d.frames", "1" }, { "char_e", "RocksFontEM.pcx" }, { "char_e.xpos", "5" }, { "char_e.ypos", "2" }, { "char_e.frames", "1" }, { "char_f", "RocksFontEM.pcx" }, { "char_f.xpos", "6" }, { "char_f.ypos", "2" }, { "char_f.frames", "1" }, { "char_g", "RocksFontEM.pcx" }, { "char_g.xpos", "7" }, { "char_g.ypos", "2" }, { "char_g.frames", "1" }, { "char_h", "RocksFontEM.pcx" }, { "char_h.xpos", "8" }, { "char_h.ypos", "2" }, { "char_h.frames", "1" }, { "char_i", "RocksFontEM.pcx" }, { "char_i.xpos", "9" }, { "char_i.ypos", "2" }, { "char_i.frames", "1" }, { "char_j", "RocksFontEM.pcx" }, { "char_j.xpos", "10" }, { "char_j.ypos", "2" }, { "char_j.frames", "1" }, { "char_k", "RocksFontEM.pcx" }, { "char_k.xpos", "11" }, { "char_k.ypos", "2" }, { "char_k.frames", "1" }, { "char_l", "RocksFontEM.pcx" }, { "char_l.xpos", "12" }, { "char_l.ypos", "2" }, { "char_l.frames", "1" }, { "char_m", "RocksFontEM.pcx" }, { "char_m.xpos", "13" }, { "char_m.ypos", "2" }, { "char_m.frames", "1" }, { "char_n", "RocksFontEM.pcx" }, { "char_n.xpos", "14" }, { "char_n.ypos", "2" }, { "char_n.frames", "1" }, { "char_o", "RocksFontEM.pcx" }, { "char_o.xpos", "15" }, { "char_o.ypos", "2" }, { "char_o.frames", "1" }, { "char_p", "RocksFontEM.pcx" }, { "char_p.xpos", "0" }, { "char_p.ypos", "3" }, { "char_p.frames", "1" }, { "char_q", "RocksFontEM.pcx" }, { "char_q.xpos", "1" }, { "char_q.ypos", "3" }, { "char_q.frames", "1" }, { "char_r", "RocksFontEM.pcx" }, { "char_r.xpos", "2" }, { "char_r.ypos", "3" }, { "char_r.frames", "1" }, { "char_s", "RocksFontEM.pcx" }, { "char_s.xpos", "3" }, { "char_s.ypos", "3" }, { "char_s.frames", "1" }, { "char_t", "RocksFontEM.pcx" }, { "char_t.xpos", "4" }, { "char_t.ypos", "3" }, { "char_t.frames", "1" }, { "char_u", "RocksFontEM.pcx" }, { "char_u.xpos", "5" }, { "char_u.ypos", "3" }, { "char_u.frames", "1" }, { "char_v", "RocksFontEM.pcx" }, { "char_v.xpos", "6" }, { "char_v.ypos", "3" }, { "char_v.frames", "1" }, { "char_w", "RocksFontEM.pcx" }, { "char_w.xpos", "7" }, { "char_w.ypos", "3" }, { "char_w.frames", "1" }, { "char_x", "RocksFontEM.pcx" }, { "char_x.xpos", "8" }, { "char_x.ypos", "3" }, { "char_x.frames", "1" }, { "char_y", "RocksFontEM.pcx" }, { "char_y.xpos", "9" }, { "char_y.ypos", "3" }, { "char_y.frames", "1" }, { "char_z", "RocksFontEM.pcx" }, { "char_z.xpos", "10" }, { "char_z.ypos", "3" }, { "char_z.frames", "1" }, { "char_bracketleft", "RocksFontEM.pcx" }, { "char_bracketleft.xpos", "11" }, { "char_bracketleft.ypos", "3" }, { "char_bracketleft.frames", "1" }, { "char_backslash", "RocksFontEM.pcx" }, { "char_backslash.xpos", "12" }, { "char_backslash.ypos", "3" }, { "char_backslash.frames", "1" }, { "char_bracketright", "RocksFontEM.pcx" }, { "char_bracketright.xpos", "13" }, { "char_bracketright.ypos", "3" }, { "char_bracketright.frames", "1" }, { "char_asciicircum", "RocksFontEM.pcx" }, { "char_asciicircum.xpos", "14" }, { "char_asciicircum.ypos", "3" }, { "char_asciicircum.frames", "1" }, { "char_underscore", "RocksFontEM.pcx" }, { "char_underscore.xpos", "15" }, { "char_underscore.ypos", "3" }, { "char_underscore.frames", "1" }, { "char_copyright", "RocksFontEM.pcx" }, { "char_copyright.xpos", "0" }, { "char_copyright.ypos", "4" }, { "char_copyright.frames", "1" }, { "char_aumlaut", "RocksFontEM.pcx" }, { "char_aumlaut.xpos", "1" }, { "char_aumlaut.ypos", "4" }, { "char_aumlaut.frames", "1" }, { "char_oumlaut", "RocksFontEM.pcx" }, { "char_oumlaut.xpos", "2" }, { "char_oumlaut.ypos", "4" }, { "char_oumlaut.frames", "1" }, { "char_uumlaut", "RocksFontEM.pcx" }, { "char_uumlaut.xpos", "3" }, { "char_uumlaut.ypos", "4" }, { "char_uumlaut.frames", "1" }, { "char_degree", "RocksFontEM.pcx" }, { "char_degree.xpos", "4" }, { "char_degree.ypos", "4" }, { "char_degree.frames", "1" }, { "char_trademark", "RocksFontEM.pcx" }, { "char_trademark.xpos", "5" }, { "char_trademark.ypos", "4" }, { "char_trademark.frames", "1" }, { "char_cursor", "RocksFontEM.pcx" }, { "char_cursor.xpos", "6" }, { "char_cursor.ypos", "4" }, { "char_cursor.frames", "1" }, { "char_button", "RocksFontEM.pcx" }, { "char_button.xpos", "13" }, { "char_button.ypos", "4" }, { "char_button.frames", "1" }, { "char_up", "RocksFontEM.pcx" }, { "char_up.xpos", "14" }, { "char_up.ypos", "4" }, { "char_up.frames", "1" }, { "char_down", "RocksFontEM.pcx" }, { "char_down.xpos", "15" }, { "char_down.ypos", "4" }, { "char_down.frames", "1" }, { "steel_char_space", "RocksFontDC.pcx" }, { "steel_char_space.xpos", "0" }, { "steel_char_space.ypos", "0" }, { "steel_char_space.frames", "1" }, { "steel_char_space.EDITOR", "RocksFontDC.pcx" }, { "steel_char_space.EDITOR.xpos", "7" }, { "steel_char_space.EDITOR.ypos", "4" }, { "steel_char_space.EDITOR.frames", "1" }, { "steel_char_exclam", "RocksFontDC.pcx" }, { "steel_char_exclam.xpos", "1" }, { "steel_char_exclam.ypos", "0" }, { "steel_char_exclam.frames", "1" }, { "steel_char_quotedbl", "RocksFontDC.pcx" }, { "steel_char_quotedbl.xpos", "2" }, { "steel_char_quotedbl.ypos", "0" }, { "steel_char_quotedbl.frames", "1" }, { "steel_char_numbersign", "RocksFontDC.pcx" }, { "steel_char_numbersign.xpos", "3" }, { "steel_char_numbersign.ypos", "0" }, { "steel_char_numbersign.frames", "1" }, { "steel_char_dollar", "RocksFontDC.pcx" }, { "steel_char_dollar.xpos", "4" }, { "steel_char_dollar.ypos", "0" }, { "steel_char_dollar.frames", "1" }, { "steel_char_percent", "RocksFontDC.pcx" }, { "steel_char_percent.xpos", "5" }, { "steel_char_percent.ypos", "0" }, { "steel_char_percent.frames", "1" }, { "steel_char_ampersand", "RocksFontDC.pcx" }, { "steel_char_ampersand.xpos", "6" }, { "steel_char_ampersand.ypos", "0" }, { "steel_char_ampersand.frames", "1" }, { "steel_char_apostrophe", "RocksFontDC.pcx" }, { "steel_char_apostrophe.xpos", "7" }, { "steel_char_apostrophe.ypos", "0" }, { "steel_char_apostrophe.frames", "1" }, { "steel_char_parenleft", "RocksFontDC.pcx" }, { "steel_char_parenleft.xpos", "8" }, { "steel_char_parenleft.ypos", "0" }, { "steel_char_parenleft.frames", "1" }, { "steel_char_parenright", "RocksFontDC.pcx" }, { "steel_char_parenright.xpos", "9" }, { "steel_char_parenright.ypos", "0" }, { "steel_char_parenright.frames", "1" }, { "steel_char_asterisk", "RocksFontDC.pcx" }, { "steel_char_asterisk.xpos", "10" }, { "steel_char_asterisk.ypos", "0" }, { "steel_char_asterisk.frames", "1" }, { "steel_char_plus", "RocksFontDC.pcx" }, { "steel_char_plus.xpos", "11" }, { "steel_char_plus.ypos", "0" }, { "steel_char_plus.frames", "1" }, { "steel_char_comma", "RocksFontDC.pcx" }, { "steel_char_comma.xpos", "12" }, { "steel_char_comma.ypos", "0" }, { "steel_char_comma.frames", "1" }, { "steel_char_minus", "RocksFontDC.pcx" }, { "steel_char_minus.xpos", "13" }, { "steel_char_minus.ypos", "0" }, { "steel_char_minus.frames", "1" }, { "steel_char_period", "RocksFontDC.pcx" }, { "steel_char_period.xpos", "14" }, { "steel_char_period.ypos", "0" }, { "steel_char_period.frames", "1" }, { "steel_char_slash", "RocksFontDC.pcx" }, { "steel_char_slash.xpos", "15" }, { "steel_char_slash.ypos", "0" }, { "steel_char_slash.frames", "1" }, { "steel_char_0", "RocksFontDC.pcx" }, { "steel_char_0.xpos", "0" }, { "steel_char_0.ypos", "1" }, { "steel_char_0.frames", "1" }, { "steel_char_1", "RocksFontDC.pcx" }, { "steel_char_1.xpos", "1" }, { "steel_char_1.ypos", "1" }, { "steel_char_1.frames", "1" }, { "steel_char_2", "RocksFontDC.pcx" }, { "steel_char_2.xpos", "2" }, { "steel_char_2.ypos", "1" }, { "steel_char_2.frames", "1" }, { "steel_char_3", "RocksFontDC.pcx" }, { "steel_char_3.xpos", "3" }, { "steel_char_3.ypos", "1" }, { "steel_char_3.frames", "1" }, { "steel_char_4", "RocksFontDC.pcx" }, { "steel_char_4.xpos", "4" }, { "steel_char_4.ypos", "1" }, { "steel_char_4.frames", "1" }, { "steel_char_5", "RocksFontDC.pcx" }, { "steel_char_5.xpos", "5" }, { "steel_char_5.ypos", "1" }, { "steel_char_5.frames", "1" }, { "steel_char_6", "RocksFontDC.pcx" }, { "steel_char_6.xpos", "6" }, { "steel_char_6.ypos", "1" }, { "steel_char_6.frames", "1" }, { "steel_char_7", "RocksFontDC.pcx" }, { "steel_char_7.xpos", "7" }, { "steel_char_7.ypos", "1" }, { "steel_char_7.frames", "1" }, { "steel_char_8", "RocksFontDC.pcx" }, { "steel_char_8.xpos", "8" }, { "steel_char_8.ypos", "1" }, { "steel_char_8.frames", "1" }, { "steel_char_9", "RocksFontDC.pcx" }, { "steel_char_9.xpos", "9" }, { "steel_char_9.ypos", "1" }, { "steel_char_9.frames", "1" }, { "steel_char_colon", "RocksFontDC.pcx" }, { "steel_char_colon.xpos", "10" }, { "steel_char_colon.ypos", "1" }, { "steel_char_colon.frames", "1" }, { "steel_char_semicolon", "RocksFontDC.pcx" }, { "steel_char_semicolon.xpos", "11" }, { "steel_char_semicolon.ypos", "1" }, { "steel_char_semicolon.frames", "1" }, { "steel_char_less", "RocksFontDC.pcx" }, { "steel_char_less.xpos", "12" }, { "steel_char_less.ypos", "1" }, { "steel_char_less.frames", "1" }, { "steel_char_equal", "RocksFontDC.pcx" }, { "steel_char_equal.xpos", "13" }, { "steel_char_equal.ypos", "1" }, { "steel_char_equal.frames", "1" }, { "steel_char_greater", "RocksFontDC.pcx" }, { "steel_char_greater.xpos", "14" }, { "steel_char_greater.ypos", "1" }, { "steel_char_greater.frames", "1" }, { "steel_char_question", "RocksFontDC.pcx" }, { "steel_char_question.xpos", "15" }, { "steel_char_question.ypos", "1" }, { "steel_char_question.frames", "1" }, { "steel_char_at", "RocksFontDC.pcx" }, { "steel_char_at.xpos", "0" }, { "steel_char_at.ypos", "2" }, { "steel_char_at.frames", "1" }, { "steel_char_a", "RocksFontDC.pcx" }, { "steel_char_a.xpos", "1" }, { "steel_char_a.ypos", "2" }, { "steel_char_a.frames", "1" }, { "steel_char_b", "RocksFontDC.pcx" }, { "steel_char_b.xpos", "2" }, { "steel_char_b.ypos", "2" }, { "steel_char_b.frames", "1" }, { "steel_char_c", "RocksFontDC.pcx" }, { "steel_char_c.xpos", "3" }, { "steel_char_c.ypos", "2" }, { "steel_char_c.frames", "1" }, { "steel_char_d", "RocksFontDC.pcx" }, { "steel_char_d.xpos", "4" }, { "steel_char_d.ypos", "2" }, { "steel_char_d.frames", "1" }, { "steel_char_e", "RocksFontDC.pcx" }, { "steel_char_e.xpos", "5" }, { "steel_char_e.ypos", "2" }, { "steel_char_e.frames", "1" }, { "steel_char_f", "RocksFontDC.pcx" }, { "steel_char_f.xpos", "6" }, { "steel_char_f.ypos", "2" }, { "steel_char_f.frames", "1" }, { "steel_char_g", "RocksFontDC.pcx" }, { "steel_char_g.xpos", "7" }, { "steel_char_g.ypos", "2" }, { "steel_char_g.frames", "1" }, { "steel_char_h", "RocksFontDC.pcx" }, { "steel_char_h.xpos", "8" }, { "steel_char_h.ypos", "2" }, { "steel_char_h.frames", "1" }, { "steel_char_i", "RocksFontDC.pcx" }, { "steel_char_i.xpos", "9" }, { "steel_char_i.ypos", "2" }, { "steel_char_i.frames", "1" }, { "steel_char_j", "RocksFontDC.pcx" }, { "steel_char_j.xpos", "10" }, { "steel_char_j.ypos", "2" }, { "steel_char_j.frames", "1" }, { "steel_char_k", "RocksFontDC.pcx" }, { "steel_char_k.xpos", "11" }, { "steel_char_k.ypos", "2" }, { "steel_char_k.frames", "1" }, { "steel_char_l", "RocksFontDC.pcx" }, { "steel_char_l.xpos", "12" }, { "steel_char_l.ypos", "2" }, { "steel_char_l.frames", "1" }, { "steel_char_m", "RocksFontDC.pcx" }, { "steel_char_m.xpos", "13" }, { "steel_char_m.ypos", "2" }, { "steel_char_m.frames", "1" }, { "steel_char_n", "RocksFontDC.pcx" }, { "steel_char_n.xpos", "14" }, { "steel_char_n.ypos", "2" }, { "steel_char_n.frames", "1" }, { "steel_char_o", "RocksFontDC.pcx" }, { "steel_char_o.xpos", "15" }, { "steel_char_o.ypos", "2" }, { "steel_char_o.frames", "1" }, { "steel_char_p", "RocksFontDC.pcx" }, { "steel_char_p.xpos", "0" }, { "steel_char_p.ypos", "3" }, { "steel_char_p.frames", "1" }, { "steel_char_q", "RocksFontDC.pcx" }, { "steel_char_q.xpos", "1" }, { "steel_char_q.ypos", "3" }, { "steel_char_q.frames", "1" }, { "steel_char_r", "RocksFontDC.pcx" }, { "steel_char_r.xpos", "2" }, { "steel_char_r.ypos", "3" }, { "steel_char_r.frames", "1" }, { "steel_char_s", "RocksFontDC.pcx" }, { "steel_char_s.xpos", "3" }, { "steel_char_s.ypos", "3" }, { "steel_char_s.frames", "1" }, { "steel_char_t", "RocksFontDC.pcx" }, { "steel_char_t.xpos", "4" }, { "steel_char_t.ypos", "3" }, { "steel_char_t.frames", "1" }, { "steel_char_u", "RocksFontDC.pcx" }, { "steel_char_u.xpos", "5" }, { "steel_char_u.ypos", "3" }, { "steel_char_u.frames", "1" }, { "steel_char_v", "RocksFontDC.pcx" }, { "steel_char_v.xpos", "6" }, { "steel_char_v.ypos", "3" }, { "steel_char_v.frames", "1" }, { "steel_char_w", "RocksFontDC.pcx" }, { "steel_char_w.xpos", "7" }, { "steel_char_w.ypos", "3" }, { "steel_char_w.frames", "1" }, { "steel_char_x", "RocksFontDC.pcx" }, { "steel_char_x.xpos", "8" }, { "steel_char_x.ypos", "3" }, { "steel_char_x.frames", "1" }, { "steel_char_y", "RocksFontDC.pcx" }, { "steel_char_y.xpos", "9" }, { "steel_char_y.ypos", "3" }, { "steel_char_y.frames", "1" }, { "steel_char_z", "RocksFontDC.pcx" }, { "steel_char_z.xpos", "10" }, { "steel_char_z.ypos", "3" }, { "steel_char_z.frames", "1" }, { "steel_char_bracketleft", "RocksFontDC.pcx" }, { "steel_char_bracketleft.xpos", "11" }, { "steel_char_bracketleft.ypos", "3" }, { "steel_char_bracketleft.frames", "1" }, { "steel_char_backslash", "RocksFontDC.pcx" }, { "steel_char_backslash.xpos", "12" }, { "steel_char_backslash.ypos", "3" }, { "steel_char_backslash.frames", "1" }, { "steel_char_bracketright", "RocksFontDC.pcx" }, { "steel_char_bracketright.xpos", "13" }, { "steel_char_bracketright.ypos", "3" }, { "steel_char_bracketright.frames", "1" }, { "steel_char_asciicircum", "RocksFontDC.pcx" }, { "steel_char_asciicircum.xpos", "14" }, { "steel_char_asciicircum.ypos", "3" }, { "steel_char_asciicircum.frames", "1" }, { "steel_char_underscore", "RocksFontDC.pcx" }, { "steel_char_underscore.xpos", "15" }, { "steel_char_underscore.ypos", "3" }, { "steel_char_underscore.frames", "1" }, { "steel_char_copyright", "RocksFontDC.pcx" }, { "steel_char_copyright.xpos", "0" }, { "steel_char_copyright.ypos", "4" }, { "steel_char_copyright.frames", "1" }, { "steel_char_aumlaut", "RocksFontDC.pcx" }, { "steel_char_aumlaut.xpos", "1" }, { "steel_char_aumlaut.ypos", "4" }, { "steel_char_aumlaut.frames", "1" }, { "steel_char_oumlaut", "RocksFontDC.pcx" }, { "steel_char_oumlaut.xpos", "2" }, { "steel_char_oumlaut.ypos", "4" }, { "steel_char_oumlaut.frames", "1" }, { "steel_char_uumlaut", "RocksFontDC.pcx" }, { "steel_char_uumlaut.xpos", "3" }, { "steel_char_uumlaut.ypos", "4" }, { "steel_char_uumlaut.frames", "1" }, { "steel_char_degree", "RocksFontDC.pcx" }, { "steel_char_degree.xpos", "4" }, { "steel_char_degree.ypos", "4" }, { "steel_char_degree.frames", "1" }, { "steel_char_trademark", "RocksFontDC.pcx" }, { "steel_char_trademark.xpos", "5" }, { "steel_char_trademark.ypos", "4" }, { "steel_char_trademark.frames", "1" }, { "steel_char_cursor", "RocksFontDC.pcx" }, { "steel_char_cursor.xpos", "6" }, { "steel_char_cursor.ypos", "4" }, { "steel_char_cursor.frames", "1" }, { "steel_char_button", "RocksFontDC.pcx" }, { "steel_char_button.xpos", "13" }, { "steel_char_button.ypos", "4" }, { "steel_char_button.frames", "1" }, { "steel_char_up", "RocksFontDC.pcx" }, { "steel_char_up.xpos", "14" }, { "steel_char_up.ypos", "4" }, { "steel_char_up.frames", "1" }, { "steel_char_down", "RocksFontDC.pcx" }, { "steel_char_down.xpos", "15" }, { "steel_char_down.ypos", "4" }, { "steel_char_down.frames", "1" }, #endif /* CONF_CHR_C */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_hlp.c0000644000175000017500000003750410471574037017372 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_hlp.c * ***********************************************************/ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is GFX_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigInfo helpanim_config[] = { { "player_1.moving.down", "16" }, { "player_1.moving.up", "16" }, { "player_1.moving.left", "16" }, { "player_1.moving.right", "16" }, { "player_1.pushing.left", "16" }, { "player_1.pushing.right", "16" }, { "end", "" }, { "sand", "50" }, { "sand.digging.left", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.right", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.up", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.down", "8" }, { "empty_space", "10" }, { "end", "" }, { "empty_space", "-1" }, { "end", "" }, { "quicksand_empty", "-1" }, { "end", "" }, { "steelwall", "-1" }, { "end", "" }, { "wall", "-1" }, { "end", "" }, { "expandable_wall.growing.left", "20" }, { "wall", "50" }, { "expandable_wall.growing.right", "20" }, { "wall", "50" }, { "expandable_wall.growing.up", "20" }, { "wall", "50" }, { "expandable_wall.growing.down", "20" }, { "wall", "50" }, { "empty_space", "20" }, { "end", "" }, { "invisible_wall", "-1" }, { "end", "" }, { "wall_slippery", "-1" }, { "end", "" }, { "char_space", "10" }, { "char_exclam", "10" }, { "char_quotedbl", "10" }, { "char_numbersign", "10" }, { "char_dollar", "10" }, { "char_percent", "10" }, { "char_ampersand", "10" }, { "char_apostrophe", "10" }, { "char_parenleft", "10" }, { "char_parenright", "10" }, { "char_asterisk", "10" }, { "char_plus", "10" }, { "char_comma", "10" }, { "char_minus", "10" }, { "char_period", "10" }, { "char_slash", "10" }, { "char_0", "10" }, { "char_1", "10" }, { "char_2", "10" }, { "char_3", "10" }, { "char_4", "10" }, { "char_5", "10" }, { "char_6", "10" }, { "char_7", "10" }, { "char_8", "10" }, { "char_9", "10" }, { "char_colon", "10" }, { "char_semicolon", "10" }, { "char_less", "10" }, { "char_equal", "10" }, { "char_greater", "10" }, { "char_question", "10" }, { "char_at", "10" }, { "char_a", "10" }, { "char_b", "10" }, { "char_c", "10" }, { "char_d", "10" }, { "char_e", "10" }, { "char_f", "10" }, { "char_g", "10" }, { "char_h", "10" }, { "char_i", "10" }, { "char_j", "10" }, { "char_k", "10" }, { "char_l", "10" }, { "char_m", "10" }, { "char_n", "10" }, { "char_o", "10" }, { "char_p", "10" }, { "char_q", "10" }, { "char_r", "10" }, { "char_s", "10" }, { "char_t", "10" }, { "char_u", "10" }, { "char_v", "10" }, { "char_w", "10" }, { "char_x", "10" }, { "char_y", "10" }, { "char_z", "10" }, { "char_bracketleft", "10" }, { "char_backslash", "10" }, { "char_bracketright", "10" }, { "char_asciicircum", "10" }, { "char_underscore", "10" }, { "char_copyright", "10" }, { "char_aumlaut", "10" }, { "char_oumlaut", "10" }, { "char_uumlaut", "10" }, { "char_degree", "10" }, { "char_trademark", "10" }, { "char_cursor", "10" }, { "end", "" }, { "emerald", "50" }, { "emerald.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "diamond", "50" }, { "diamond.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "bd_diamond", "50" }, { "bd_diamond.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "emerald_yellow", "50" }, { "emerald_yellow.collecting", "8" }, { "empty_space", "10" }, { "emerald_red", "50" }, { "emerald_red.collecting", "8" }, { "empty_space", "10" }, { "emerald_purple", "50" }, { "emerald_purple.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "bd_rock", "-1" }, { "end", "" }, { "bomb", "100" }, { "bomb.exploding", "16" }, { "empty_space", "10" }, { "end", "" }, { "nut", "100" }, { "nut.breaking", "6" }, { "emerald", "20" }, { "end", "" }, { "wall_emerald", "100" }, { "wall_emerald.exploding", "16" }, { "emerald", "20" }, { "end", "" }, { "wall_diamond", "100" }, { "wall_diamond.exploding", "16" }, { "diamond", "20" }, { "end", "" }, { "wall_bd_diamond", "100" }, { "wall_bd_diamond.exploding", "16" }, { "bd_diamond", "20" }, { "end", "" }, { "wall_emerald_yellow", "100" }, { "wall_emerald_yellow.exploding", "16" }, { "emerald_yellow", "20" }, { "wall_emerald_red", "100" }, { "wall_emerald_red.exploding", "16" }, { "emerald_red", "20" }, { "wall_emerald_purple", "100" }, { "wall_emerald_purple.exploding", "16" }, { "emerald_purple", "20" }, { "end", "" }, { "acid", "-1" }, { "end", "" }, { "key_1", "50" }, { "key_2", "50" }, { "key_3", "50" }, { "key_4", "50" }, { "end", "" }, { "gate_1", "50" }, { "gate_2", "50" }, { "gate_3", "50" }, { "gate_4", "50" }, { "end", "" }, { "gate_1_gray", "50" }, { "gate_2_gray", "50" }, { "gate_3_gray", "50" }, { "gate_4_gray", "50" }, { "end", "" }, { "dynamite", "-1" }, { "end", "" }, { "dynamite.active", "96" }, { "dynamite.exploding", "16" }, { "empty_space", "20" }, { "end", "" }, { "dynabomb.active", "100" }, { "dynabomb.exploding", "16" }, { "empty_space", "20" }, { "end", "" }, { "dynabomb_increase_number", "-1" }, { "end", "" }, { "dynabomb_increase_size", "-1" }, { "end", "" }, { "dynabomb_increase_power", "-1" }, { "end", "" }, { "spaceship.turning_from_right.up", "8" }, { "spaceship.turning_from_up.left", "8" }, { "spaceship.turning_from_left.down", "8" }, { "spaceship.turning_from_down.right", "8" }, { "end", "" }, { "bug.turning_from_right.up", "8" }, { "bug.turning_from_up.left", "8" }, { "bug.turning_from_left.down", "8" }, { "bug.turning_from_down.right", "8" }, { "end", "" }, { "bd_butterfly", "-1" }, { "end", "" }, { "bd_firefly", "-1" }, { "end", "" }, { "pacman.right", "16" }, { "pacman.up", "16" }, { "pacman.left", "16" }, { "pacman.down", "16" }, { "end", "" }, { "yamyam", "-1" }, { "end", "" }, { "dark_yamyam", "-1" }, { "end", "" }, { "robot", "-1" }, { "end", "" }, { "mole.moving.right", "16" }, { "mole.moving.up", "16" }, { "mole.moving.left", "16" }, { "mole.moving.down", "16" }, { "end", "" }, { "penguin.moving.right", "16" }, { "penguin.moving.up", "16" }, { "penguin.moving.left", "16" }, { "penguin.moving.down", "16" }, { "end", "" }, { "pig.moving.right", "16" }, { "pig.moving.up", "16" }, { "pig.moving.left", "16" }, { "pig.moving.down", "16" }, { "end", "" }, { "dragon.moving.right", "16" }, { "dragon.moving.up", "16" }, { "dragon.moving.left", "16" }, { "dragon.moving.down", "16" }, { "end", "" }, { "satellite", "-1" }, { "end", "" }, { "robot_wheel", "50" }, { "robot_wheel.active", "100" }, { "end", "" }, { "lamp", "50" }, { "lamp.active", "50" }, { "end", "" }, { "time_orb_full", "50" }, { "time_orb_empty", "50" }, { "end", "" }, { "amoeba_drop", "50" }, { "amoeba.growing", "6" }, { "amoeba_wet", "20" }, { "end", "" }, { "amoeba_dead", "-1" }, { "end", "" }, { "amoeba_wet", "-1" }, { "end", "" }, { "amoeba_wet", "100" }, { "amoeba.growing", "6" }, { "end", "" }, { "amoeba_full", "50" }, { "amoeba_dead", "50" }, { "amoeba.exploding", "16" }, { "diamond", "20" }, { "end", "" }, { "game_of_life", "-1" }, { "end", "" }, { "biomaze", "-1" }, { "end", "" }, { "magic_wall.active", "-1" }, { "end", "" }, { "bd_magic_wall.active", "-1" }, { "end", "" }, { "exit_closed", "200" }, { "exit.opening", "30" }, { "exit_open", "100" }, { "exit.closing", "30" }, { "end", "" }, { "exit_open", "-1" }, { "end", "" }, { "sokoban_object", "-1" }, { "end", "" }, { "sokoban_field_empty", "-1" }, { "end", "" }, { "sokoban_field_full", "-1" }, { "end", "" }, { "speed_pill", "-1" }, { "end", "" }, { NULL, NULL } }; struct ConfigInfo helptext_config[] = { { "player_1", "THE HERO: (Is _this_ guy good old Rockford?)" }, { "sand", "Normal sand: You can dig through it" }, { "empty_space", "Empty field: You can walk through it" }, { "quicksand_empty", "Quicksand: You cannot pass it, but rocks can fall through it" }, { "steelwall", "Massive Wall: Nothing can go through it" }, { "wall", "Normal Wall: You can't go through it, but you can bomb it away" }, { "expandable_wall", "Growing Wall: Grows in several directions if there is an empty field" }, { "invisible_wall", "Invisible Wall: Behaves like normal wall, but is invisible" }, { "wall_slippery", "Old Wall: Like normal wall, but some things can fall down from it" }, { "char_space", "Letter Wall: Looks like a letter, behaves like a normal wall" }, { "emerald", "Emerald: You must collect enough of them to finish a level" }, { "diamond", "Diamond: Counts as 3 emeralds, but can be destroyed by rocks" }, { "bd_diamond", "Diamond (BD style): Counts like one emerald and behaves a bit different" }, { "emerald_yellow", "Colorful Gems: Seem to behave like Emeralds" }, { "bd_rock", "Rock: Smashes several things; Can be moved by the player" }, { "bomb", "Bomb: You can move it, but be careful when dropping it" }, { "nut", "Nut: Throw a rock on it to open it; Each nut contains an emerald" }, { "wall_emerald", "Wall with an emerald inside: Bomb the wall away to get it" }, { "wall_diamond", "Wall with a diamond inside: Bomb the wall away to get it" }, { "wall_bd_diamond", "Wall with BD style diamond inside: Bomb the wall away to get it" }, { "wall_emerald_yellow", "Wall with colorful gem inside: Bomb the wall away to get it" }, { "acid", "Acid: Things that fall in are gone forever (including our hero)" }, { "key_1", "Key: Opens the door that has the same color (red/yellow/green/blue)" }, { "gate_1", "Door: Can be opened by the key with the same color" }, { "gate_1_gray", "Door: You have to find out the right color of the key for it" }, { "dynamite", "Dynamite: Collect it and use it to destroy walls or kill enemies" }, { "dynamite.active", "Dynamite: This one explodes after a few seconds" }, { "dynabomb", "Dyna Bomb: Explodes in 4 directions with variable explosion size" }, { "dynabomb_increase_number", "Dyna Bomb: Increases the number of dyna bombs available at a time" }, { "dynabomb_increase_size", "Dyna Bomb: Increases the size of explosion of dyna bombs" }, { "dynabomb_increase_power", "Dyna Bomb: Increases the power of explosion of dyna bombs" }, { "spaceship", "Spaceship: Moves at the left side of walls; don't touch it!" }, { "bug", "Bug: Moves at the right side of walls; don't touch it!" }, { "bd_butterfly", "Butterfly: Moves at the right side of walls; don't touch it!" }, { "bd_firefly", "Firefly: Moves at the left side of walls; don't touch it!" }, { "pacman", "Pacman: Eats the amoeba and you, if you're not careful" }, { "yamyam", "Yam Yam: Eats diamonds and you, if you're not careful" }, { "dark_yamyam", "Dark Yam Yam: Eats almost everything" }, { "robot", "Robot: Tries to kill the player" }, { "mole", "The mole: Eats the amoeba and turns empty space into normal sand" }, { "penguin", "The penguin: Guide him to the exit, but keep him away from monsters!" }, { "pig", "The Pig: Harmless, but eats all gems it can get" }, { "dragon", "The Dragon: Breathes fire, especially to some monsters" }, { "satellite", "Sonde: Follows you everywhere; harmless, but may block your way" }, { "robot_wheel", "Magic Wheel: Touch it to get rid of the robots for some seconds" }, { "lamp", "Light Bulb: All of them must be switched on to finish a level" }, { "time_orb_full", "Extra Time Orb: Adds some seconds to the time available for the level" }, { "amoeba_drop", "Amoeba Drop: Grows to an amoeba on the ground - don't touch it" }, { "amoeba_dead", "Dead Amoeba: Does not grow, but can still kill bugs and spaceships" }, { "amoeba_wet", "Normal Amoeba: Grows through empty fields, sand and quicksand" }, { "amoeba_wet", "Dropping Amoeba: This one makes drops that grow to a new amoeba" }, { "amoeba_full", "Living Amoeba (BD style): Contains other element, when surrounded" }, { "game_of_life", "Game Of Life: Behaves like the well known 'Game Of Life' (2333 style)" }, { "biomaze", "Biomaze: A bit like the 'Game Of Life', but builds crazy mazes" }, { "magic_wall", "Magic Wall: Changes rocks, emeralds and diamonds when they pass it" }, { "bd_magic_wall", "Magic Wall (BD style): Changes rocks and BD style diamonds" }, { "exit_closed", "Exit door: Opens if you have enough emeralds to finish the level" }, { "exit_open", "Open exit door: Enter here to leave the level and exit the actual game" }, { "sokoban_object", "Sokoban element: Object which must be pushed to an empty field" }, { "sokoban_field_empty", "Sokoban element: Empty field where a Sokoban object can be placed on" }, { "sokoban_field_full", "Sokoban element: Field with object which can be pushed away" }, { "speed_pill", "Speed pill: Lets the player run twice as fast as normally" }, { NULL, NULL } }; rocksndiamonds-3.3.0.1+dfsg1/src/tape.h0000644000175000017500000001334011345714042016521 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tape.h * ***********************************************************/ #ifndef TAPE_H #define TAPE_H /* values for TapeTogglePause() */ #define TAPE_TOGGLE_MANUAL TRUE #define TAPE_TOGGLE_AUTOMATIC FALSE /* values for tape properties */ #define MAX_TAPE_LEN (1000 * FRAMES_PER_SECOND) /* max.time x fps */ /* some positions in the video tape control window */ #define VIDEO_DISPLAY1_XPOS 5 #define VIDEO_DISPLAY1_YPOS 5 #define VIDEO_DISPLAY2_XPOS 5 #define VIDEO_DISPLAY2_YPOS 41 #define VIDEO_DISPLAY_XSIZE 90 #define VIDEO_DISPLAY_YSIZE 31 #define VIDEO_BUTTON_XSIZE 18 #define VIDEO_BUTTON_YSIZE 18 #define VIDEO_CONTROL_XPOS 5 #define VIDEO_CONTROL_YPOS 77 #define VIDEO_CONTROL_XSIZE VIDEO_DISPLAY_XSIZE #define VIDEO_CONTROL_YSIZE VIDEO_BUTTON_YSIZE /* values for video tape control */ #define VIDEO_STATE_PLAY_OFF (1 << 0) #define VIDEO_STATE_PLAY_ON (1 << 1) #define VIDEO_STATE_PLAY (VIDEO_STATE_PLAY_OFF | VIDEO_STATE_PLAY_ON) #define VIDEO_STATE_REC_OFF (1 << 2) #define VIDEO_STATE_REC_ON (1 << 3) #define VIDEO_STATE_REC (VIDEO_STATE_REC_OFF | VIDEO_STATE_REC_ON) #define VIDEO_STATE_PAUSE_OFF (1 << 4) #define VIDEO_STATE_PAUSE_ON (1 << 5) #define VIDEO_STATE_PAUSE (VIDEO_STATE_PAUSE_OFF | VIDEO_STATE_PAUSE_ON) #define VIDEO_STATE_DATE_OFF (1 << 6) #define VIDEO_STATE_DATE_ON (1 << 7) #define VIDEO_STATE_DATE (VIDEO_STATE_DATE_OFF | VIDEO_STATE_DATE_ON) #define VIDEO_STATE_TIME_OFF (1 << 8) #define VIDEO_STATE_TIME_ON (1 << 9) #define VIDEO_STATE_TIME (VIDEO_STATE_TIME_OFF | VIDEO_STATE_TIME_ON) #define VIDEO_STATE_FFWD_OFF (1 << 10) #define VIDEO_STATE_FFWD_ON (1 << 11) #define VIDEO_STATE_FFWD (VIDEO_STATE_FFWD_OFF | VIDEO_STATE_FFWD_ON) #define VIDEO_STATE_PBEND_OFF (1 << 12) #define VIDEO_STATE_PBEND_ON (1 << 13) #define VIDEO_STATE_PBEND (VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PBEND_ON) #define VIDEO_STATE_WARP_OFF (1 << 14) #define VIDEO_STATE_WARP_ON (1 << 15) #define VIDEO_STATE_WARP (VIDEO_STATE_WARP_OFF | VIDEO_STATE_WARP_ON) #define VIDEO_STATE_WARP2_OFF (1 << 16) #define VIDEO_STATE_WARP2_ON (1 << 17) #define VIDEO_STATE_WARP2 (VIDEO_STATE_WARP_OFF | VIDEO_STATE_WARP_ON) #define VIDEO_STATE_1STEP_OFF (1 << 18) #define VIDEO_STATE_1STEP_ON (1 << 19) #define VIDEO_STATE_1STEP (VIDEO_STATE_1STEP_OFF | VIDEO_STATE_1STEP_ON) #define VIDEO_PRESS_PLAY_ON (1 << 20) #define VIDEO_PRESS_PLAY_OFF (1 << 21) #define VIDEO_PRESS_PLAY (VIDEO_PRESS_PLAY_OFF | VIDEO_PRESS_PLAY_ON) #define VIDEO_PRESS_REC_ON (1 << 22) #define VIDEO_PRESS_REC_OFF (1 << 23) #define VIDEO_PRESS_REC (VIDEO_PRESS_REC_OFF | VIDEO_PRESS_REC_ON) #define VIDEO_PRESS_PAUSE_ON (1 << 24) #define VIDEO_PRESS_PAUSE_OFF (1 << 25) #define VIDEO_PRESS_PAUSE (VIDEO_PRESS_PAUSE_OFF | VIDEO_PRESS_PAUSE_ON) #define VIDEO_PRESS_STOP_ON (1 << 26) #define VIDEO_PRESS_STOP_OFF (1 << 27) #define VIDEO_PRESS_STOP (VIDEO_PRESS_STOP_OFF | VIDEO_PRESS_STOP_ON) #define VIDEO_PRESS_EJECT_ON (1 << 28) #define VIDEO_PRESS_EJECT_OFF (1 << 29) #define VIDEO_PRESS_EJECT (VIDEO_PRESS_EJECT_OFF | VIDEO_PRESS_EJECT_ON) /* tags to draw video display labels or symbols only */ /* (negative values to prevent misinterpretation in DrawVideoDisplay(), where the variable "value" is also used for tape length -- better fix this) */ #define VIDEO_DISPLAY_DEFAULT 0 #define VIDEO_DISPLAY_LABEL_ONLY -1 #define VIDEO_DISPLAY_SYMBOL_ONLY -2 struct TapeInfo { int file_version; /* file format version the tape is stored with */ int game_version; /* game release version the tape was created with */ int engine_version; /* game engine version the tape was recorded with */ char *level_identifier; int level_nr; unsigned long random_seed; unsigned long date; unsigned long counter; unsigned long length; unsigned long length_seconds; unsigned int delay_played; boolean pause_before_death; boolean recording, playing, pausing; boolean fast_forward; boolean warp_forward; boolean deactivate_display; boolean auto_play; boolean auto_play_level_solved; boolean quick_resume; boolean single_step; boolean changed; boolean player_participates[MAX_PLAYERS]; int num_participating_players; int centered_player_nr_next; boolean set_centered_player; struct { byte action[MAX_PLAYERS]; byte delay; } pos[MAX_TAPE_LEN]; boolean no_valid_file; /* set when tape file missing or invalid */ }; void DrawVideoDisplay(unsigned long, unsigned long); void DrawCompleteVideoDisplay(void); void TapeDeactivateDisplayOn(); void TapeDeactivateDisplayOff(boolean); void TapeSetDateFromEpochSeconds(time_t); void TapeSetDateFromNow(); void TapeStartRecording(long); void TapeHaltRecording(void); void TapeStopRecording(void); void TapeRecordAction(byte *); void TapeTogglePause(boolean); void TapeStartPlaying(void); void TapeStopPlaying(void); byte *TapePlayAction(void); void TapeStop(void); void TapeErase(void); unsigned int GetTapeLength(void); void TapeQuickSave(void); void TapeQuickLoad(void); void InsertSolutionTape(void); void AutoPlayTape(void); void CreateTapeButtons(); void FreeTapeButtons(); void MapTapeEjectButton(); void MapTapeWarpButton(); void MapTapeButtons(); void UnmapTapeButtons(); void HandleTapeButtonKeys(Key); #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_cus.c0000644000175000017500000021224311375255512017372 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_cus.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CUS_C #define CONF_CUS_C /* values for graphics configuration (custom elements) */ { "custom_1", "RocksCE.pcx" }, { "custom_1.xpos", "0" }, { "custom_1.ypos", "0" }, { "custom_1.frames", "1" }, { "custom_1.EDITOR", "RocksCE.pcx" }, { "custom_1.EDITOR.xpos", "16" }, { "custom_1.EDITOR.ypos", "0" }, { "custom_2", "RocksCE.pcx" }, { "custom_2.xpos", "1" }, { "custom_2.ypos", "0" }, { "custom_2.frames", "1" }, { "custom_2.EDITOR", "RocksCE.pcx" }, { "custom_2.EDITOR.xpos", "17" }, { "custom_2.EDITOR.ypos", "0" }, { "custom_3", "RocksCE.pcx" }, { "custom_3.xpos", "2" }, { "custom_3.ypos", "0" }, { "custom_3.frames", "1" }, { "custom_3.EDITOR", "RocksCE.pcx" }, { "custom_3.EDITOR.xpos", "18" }, { "custom_3.EDITOR.ypos", "0" }, { "custom_4", "RocksCE.pcx" }, { "custom_4.xpos", "3" }, { "custom_4.ypos", "0" }, { "custom_4.frames", "1" }, { "custom_4.EDITOR", "RocksCE.pcx" }, { "custom_4.EDITOR.xpos", "19" }, { "custom_4.EDITOR.ypos", "0" }, { "custom_5", "RocksCE.pcx" }, { "custom_5.xpos", "4" }, { "custom_5.ypos", "0" }, { "custom_5.frames", "1" }, { "custom_5.EDITOR", "RocksCE.pcx" }, { "custom_5.EDITOR.xpos", "20" }, { "custom_5.EDITOR.ypos", "0" }, { "custom_6", "RocksCE.pcx" }, { "custom_6.xpos", "5" }, { "custom_6.ypos", "0" }, { "custom_6.frames", "1" }, { "custom_6.EDITOR", "RocksCE.pcx" }, { "custom_6.EDITOR.xpos", "21" }, { "custom_6.EDITOR.ypos", "0" }, { "custom_7", "RocksCE.pcx" }, { "custom_7.xpos", "6" }, { "custom_7.ypos", "0" }, { "custom_7.frames", "1" }, { "custom_7.EDITOR", "RocksCE.pcx" }, { "custom_7.EDITOR.xpos", "22" }, { "custom_7.EDITOR.ypos", "0" }, { "custom_8", "RocksCE.pcx" }, { "custom_8.xpos", "7" }, { "custom_8.ypos", "0" }, { "custom_8.frames", "1" }, { "custom_8.EDITOR", "RocksCE.pcx" }, { "custom_8.EDITOR.xpos", "23" }, { "custom_8.EDITOR.ypos", "0" }, { "custom_9", "RocksCE.pcx" }, { "custom_9.xpos", "8" }, { "custom_9.ypos", "0" }, { "custom_9.frames", "1" }, { "custom_9.EDITOR", "RocksCE.pcx" }, { "custom_9.EDITOR.xpos", "24" }, { "custom_9.EDITOR.ypos", "0" }, { "custom_10", "RocksCE.pcx" }, { "custom_10.xpos", "9" }, { "custom_10.ypos", "0" }, { "custom_10.frames", "1" }, { "custom_10.EDITOR", "RocksCE.pcx" }, { "custom_10.EDITOR.xpos", "25" }, { "custom_10.EDITOR.ypos", "0" }, { "custom_11", "RocksCE.pcx" }, { "custom_11.xpos", "10" }, { "custom_11.ypos", "0" }, { "custom_11.frames", "1" }, { "custom_11.EDITOR", "RocksCE.pcx" }, { "custom_11.EDITOR.xpos", "26" }, { "custom_11.EDITOR.ypos", "0" }, { "custom_12", "RocksCE.pcx" }, { "custom_12.xpos", "11" }, { "custom_12.ypos", "0" }, { "custom_12.frames", "1" }, { "custom_12.EDITOR", "RocksCE.pcx" }, { "custom_12.EDITOR.xpos", "27" }, { "custom_12.EDITOR.ypos", "0" }, { "custom_13", "RocksCE.pcx" }, { "custom_13.xpos", "12" }, { "custom_13.ypos", "0" }, { "custom_13.frames", "1" }, { "custom_13.EDITOR", "RocksCE.pcx" }, { "custom_13.EDITOR.xpos", "28" }, { "custom_13.EDITOR.ypos", "0" }, { "custom_14", "RocksCE.pcx" }, { "custom_14.xpos", "13" }, { "custom_14.ypos", "0" }, { "custom_14.frames", "1" }, { "custom_14.EDITOR", "RocksCE.pcx" }, { "custom_14.EDITOR.xpos", "29" }, { "custom_14.EDITOR.ypos", "0" }, { "custom_15", "RocksCE.pcx" }, { "custom_15.xpos", "14" }, { "custom_15.ypos", "0" }, { "custom_15.frames", "1" }, { "custom_15.EDITOR", "RocksCE.pcx" }, { "custom_15.EDITOR.xpos", "30" }, { "custom_15.EDITOR.ypos", "0" }, { "custom_16", "RocksCE.pcx" }, { "custom_16.xpos", "15" }, { "custom_16.ypos", "0" }, { "custom_16.frames", "1" }, { "custom_16.EDITOR", "RocksCE.pcx" }, { "custom_16.EDITOR.xpos", "31" }, { "custom_16.EDITOR.ypos", "0" }, { "custom_17", "RocksCE.pcx" }, { "custom_17.xpos", "0" }, { "custom_17.ypos", "1" }, { "custom_17.frames", "1" }, { "custom_17.EDITOR", "RocksCE.pcx" }, { "custom_17.EDITOR.xpos", "16" }, { "custom_17.EDITOR.ypos", "1" }, { "custom_18", "RocksCE.pcx" }, { "custom_18.xpos", "1" }, { "custom_18.ypos", "1" }, { "custom_18.frames", "1" }, { "custom_18.EDITOR", "RocksCE.pcx" }, { "custom_18.EDITOR.xpos", "17" }, { "custom_18.EDITOR.ypos", "1" }, { "custom_19", "RocksCE.pcx" }, { "custom_19.xpos", "2" }, { "custom_19.ypos", "1" }, { "custom_19.frames", "1" }, { "custom_19.EDITOR", "RocksCE.pcx" }, { "custom_19.EDITOR.xpos", "18" }, { "custom_19.EDITOR.ypos", "1" }, { "custom_20", "RocksCE.pcx" }, { "custom_20.xpos", "3" }, { "custom_20.ypos", "1" }, { "custom_20.frames", "1" }, { "custom_20.EDITOR", "RocksCE.pcx" }, { "custom_20.EDITOR.xpos", "19" }, { "custom_20.EDITOR.ypos", "1" }, { "custom_21", "RocksCE.pcx" }, { "custom_21.xpos", "4" }, { "custom_21.ypos", "1" }, { "custom_21.frames", "1" }, { "custom_21.EDITOR", "RocksCE.pcx" }, { "custom_21.EDITOR.xpos", "20" }, { "custom_21.EDITOR.ypos", "1" }, { "custom_22", "RocksCE.pcx" }, { "custom_22.xpos", "5" }, { "custom_22.ypos", "1" }, { "custom_22.frames", "1" }, { "custom_22.EDITOR", "RocksCE.pcx" }, { "custom_22.EDITOR.xpos", "21" }, { "custom_22.EDITOR.ypos", "1" }, { "custom_23", "RocksCE.pcx" }, { "custom_23.xpos", "6" }, { "custom_23.ypos", "1" }, { "custom_23.frames", "1" }, { "custom_23.EDITOR", "RocksCE.pcx" }, { "custom_23.EDITOR.xpos", "22" }, { "custom_23.EDITOR.ypos", "1" }, { "custom_24", "RocksCE.pcx" }, { "custom_24.xpos", "7" }, { "custom_24.ypos", "1" }, { "custom_24.frames", "1" }, { "custom_24.EDITOR", "RocksCE.pcx" }, { "custom_24.EDITOR.xpos", "23" }, { "custom_24.EDITOR.ypos", "1" }, { "custom_25", "RocksCE.pcx" }, { "custom_25.xpos", "8" }, { "custom_25.ypos", "1" }, { "custom_25.frames", "1" }, { "custom_25.EDITOR", "RocksCE.pcx" }, { "custom_25.EDITOR.xpos", "24" }, { "custom_25.EDITOR.ypos", "1" }, { "custom_26", "RocksCE.pcx" }, { "custom_26.xpos", "9" }, { "custom_26.ypos", "1" }, { "custom_26.frames", "1" }, { "custom_26.EDITOR", "RocksCE.pcx" }, { "custom_26.EDITOR.xpos", "25" }, { "custom_26.EDITOR.ypos", "1" }, { "custom_27", "RocksCE.pcx" }, { "custom_27.xpos", "10" }, { "custom_27.ypos", "1" }, { "custom_27.frames", "1" }, { "custom_27.EDITOR", "RocksCE.pcx" }, { "custom_27.EDITOR.xpos", "26" }, { "custom_27.EDITOR.ypos", "1" }, { "custom_28", "RocksCE.pcx" }, { "custom_28.xpos", "11" }, { "custom_28.ypos", "1" }, { "custom_28.frames", "1" }, { "custom_28.EDITOR", "RocksCE.pcx" }, { "custom_28.EDITOR.xpos", "27" }, { "custom_28.EDITOR.ypos", "1" }, { "custom_29", "RocksCE.pcx" }, { "custom_29.xpos", "12" }, { "custom_29.ypos", "1" }, { "custom_29.frames", "1" }, { "custom_29.EDITOR", "RocksCE.pcx" }, { "custom_29.EDITOR.xpos", "28" }, { "custom_29.EDITOR.ypos", "1" }, { "custom_30", "RocksCE.pcx" }, { "custom_30.xpos", "13" }, { "custom_30.ypos", "1" }, { "custom_30.frames", "1" }, { "custom_30.EDITOR", "RocksCE.pcx" }, { "custom_30.EDITOR.xpos", "29" }, { "custom_30.EDITOR.ypos", "1" }, { "custom_31", "RocksCE.pcx" }, { "custom_31.xpos", "14" }, { "custom_31.ypos", "1" }, { "custom_31.frames", "1" }, { "custom_31.EDITOR", "RocksCE.pcx" }, { "custom_31.EDITOR.xpos", "30" }, { "custom_31.EDITOR.ypos", "1" }, { "custom_32", "RocksCE.pcx" }, { "custom_32.xpos", "15" }, { "custom_32.ypos", "1" }, { "custom_32.frames", "1" }, { "custom_32.EDITOR", "RocksCE.pcx" }, { "custom_32.EDITOR.xpos", "31" }, { "custom_32.EDITOR.ypos", "1" }, { "custom_33", "RocksCE.pcx" }, { "custom_33.xpos", "0" }, { "custom_33.ypos", "2" }, { "custom_33.frames", "1" }, { "custom_33.EDITOR", "RocksCE.pcx" }, { "custom_33.EDITOR.xpos", "16" }, { "custom_33.EDITOR.ypos", "2" }, { "custom_34", "RocksCE.pcx" }, { "custom_34.xpos", "1" }, { "custom_34.ypos", "2" }, { "custom_34.frames", "1" }, { "custom_34.EDITOR", "RocksCE.pcx" }, { "custom_34.EDITOR.xpos", "17" }, { "custom_34.EDITOR.ypos", "2" }, { "custom_35", "RocksCE.pcx" }, { "custom_35.xpos", "2" }, { "custom_35.ypos", "2" }, { "custom_35.frames", "1" }, { "custom_35.EDITOR", "RocksCE.pcx" }, { "custom_35.EDITOR.xpos", "18" }, { "custom_35.EDITOR.ypos", "2" }, { "custom_36", "RocksCE.pcx" }, { "custom_36.xpos", "3" }, { "custom_36.ypos", "2" }, { "custom_36.frames", "1" }, { "custom_36.EDITOR", "RocksCE.pcx" }, { "custom_36.EDITOR.xpos", "19" }, { "custom_36.EDITOR.ypos", "2" }, { "custom_37", "RocksCE.pcx" }, { "custom_37.xpos", "4" }, { "custom_37.ypos", "2" }, { "custom_37.frames", "1" }, { "custom_37.EDITOR", "RocksCE.pcx" }, { "custom_37.EDITOR.xpos", "20" }, { "custom_37.EDITOR.ypos", "2" }, { "custom_38", "RocksCE.pcx" }, { "custom_38.xpos", "5" }, { "custom_38.ypos", "2" }, { "custom_38.frames", "1" }, { "custom_38.EDITOR", "RocksCE.pcx" }, { "custom_38.EDITOR.xpos", "21" }, { "custom_38.EDITOR.ypos", "2" }, { "custom_39", "RocksCE.pcx" }, { "custom_39.xpos", "6" }, { "custom_39.ypos", "2" }, { "custom_39.frames", "1" }, { "custom_39.EDITOR", "RocksCE.pcx" }, { "custom_39.EDITOR.xpos", "22" }, { "custom_39.EDITOR.ypos", "2" }, { "custom_40", "RocksCE.pcx" }, { "custom_40.xpos", "7" }, { "custom_40.ypos", "2" }, { "custom_40.frames", "1" }, { "custom_40.EDITOR", "RocksCE.pcx" }, { "custom_40.EDITOR.xpos", "23" }, { "custom_40.EDITOR.ypos", "2" }, { "custom_41", "RocksCE.pcx" }, { "custom_41.xpos", "8" }, { "custom_41.ypos", "2" }, { "custom_41.frames", "1" }, { "custom_41.EDITOR", "RocksCE.pcx" }, { "custom_41.EDITOR.xpos", "24" }, { "custom_41.EDITOR.ypos", "2" }, { "custom_42", "RocksCE.pcx" }, { "custom_42.xpos", "9" }, { "custom_42.ypos", "2" }, { "custom_42.frames", "1" }, { "custom_42.EDITOR", "RocksCE.pcx" }, { "custom_42.EDITOR.xpos", "25" }, { "custom_42.EDITOR.ypos", "2" }, { "custom_43", "RocksCE.pcx" }, { "custom_43.xpos", "10" }, { "custom_43.ypos", "2" }, { "custom_43.frames", "1" }, { "custom_43.EDITOR", "RocksCE.pcx" }, { "custom_43.EDITOR.xpos", "26" }, { "custom_43.EDITOR.ypos", "2" }, { "custom_44", "RocksCE.pcx" }, { "custom_44.xpos", "11" }, { "custom_44.ypos", "2" }, { "custom_44.frames", "1" }, { "custom_44.EDITOR", "RocksCE.pcx" }, { "custom_44.EDITOR.xpos", "27" }, { "custom_44.EDITOR.ypos", "2" }, { "custom_45", "RocksCE.pcx" }, { "custom_45.xpos", "12" }, { "custom_45.ypos", "2" }, { "custom_45.frames", "1" }, { "custom_45.EDITOR", "RocksCE.pcx" }, { "custom_45.EDITOR.xpos", "28" }, { "custom_45.EDITOR.ypos", "2" }, { "custom_46", "RocksCE.pcx" }, { "custom_46.xpos", "13" }, { "custom_46.ypos", "2" }, { "custom_46.frames", "1" }, { "custom_46.EDITOR", "RocksCE.pcx" }, { "custom_46.EDITOR.xpos", "29" }, { "custom_46.EDITOR.ypos", "2" }, { "custom_47", "RocksCE.pcx" }, { "custom_47.xpos", "14" }, { "custom_47.ypos", "2" }, { "custom_47.frames", "1" }, { "custom_47.EDITOR", "RocksCE.pcx" }, { "custom_47.EDITOR.xpos", "30" }, { "custom_47.EDITOR.ypos", "2" }, { "custom_48", "RocksCE.pcx" }, { "custom_48.xpos", "15" }, { "custom_48.ypos", "2" }, { "custom_48.frames", "1" }, { "custom_48.EDITOR", "RocksCE.pcx" }, { "custom_48.EDITOR.xpos", "31" }, { "custom_48.EDITOR.ypos", "2" }, { "custom_49", "RocksCE.pcx" }, { "custom_49.xpos", "0" }, { "custom_49.ypos", "3" }, { "custom_49.frames", "1" }, { "custom_49.EDITOR", "RocksCE.pcx" }, { "custom_49.EDITOR.xpos", "16" }, { "custom_49.EDITOR.ypos", "3" }, { "custom_50", "RocksCE.pcx" }, { "custom_50.xpos", "1" }, { "custom_50.ypos", "3" }, { "custom_50.frames", "1" }, { "custom_50.EDITOR", "RocksCE.pcx" }, { "custom_50.EDITOR.xpos", "17" }, { "custom_50.EDITOR.ypos", "3" }, { "custom_51", "RocksCE.pcx" }, { "custom_51.xpos", "2" }, { "custom_51.ypos", "3" }, { "custom_51.frames", "1" }, { "custom_51.EDITOR", "RocksCE.pcx" }, { "custom_51.EDITOR.xpos", "18" }, { "custom_51.EDITOR.ypos", "3" }, { "custom_52", "RocksCE.pcx" }, { "custom_52.xpos", "3" }, { "custom_52.ypos", "3" }, { "custom_52.frames", "1" }, { "custom_52.EDITOR", "RocksCE.pcx" }, { "custom_52.EDITOR.xpos", "19" }, { "custom_52.EDITOR.ypos", "3" }, { "custom_53", "RocksCE.pcx" }, { "custom_53.xpos", "4" }, { "custom_53.ypos", "3" }, { "custom_53.frames", "1" }, { "custom_53.EDITOR", "RocksCE.pcx" }, { "custom_53.EDITOR.xpos", "20" }, { "custom_53.EDITOR.ypos", "3" }, { "custom_54", "RocksCE.pcx" }, { "custom_54.xpos", "5" }, { "custom_54.ypos", "3" }, { "custom_54.frames", "1" }, { "custom_54.EDITOR", "RocksCE.pcx" }, { "custom_54.EDITOR.xpos", "21" }, { "custom_54.EDITOR.ypos", "3" }, { "custom_55", "RocksCE.pcx" }, { "custom_55.xpos", "6" }, { "custom_55.ypos", "3" }, { "custom_55.frames", "1" }, { "custom_55.EDITOR", "RocksCE.pcx" }, { "custom_55.EDITOR.xpos", "22" }, { "custom_55.EDITOR.ypos", "3" }, { "custom_56", "RocksCE.pcx" }, { "custom_56.xpos", "7" }, { "custom_56.ypos", "3" }, { "custom_56.frames", "1" }, { "custom_56.EDITOR", "RocksCE.pcx" }, { "custom_56.EDITOR.xpos", "23" }, { "custom_56.EDITOR.ypos", "3" }, { "custom_57", "RocksCE.pcx" }, { "custom_57.xpos", "8" }, { "custom_57.ypos", "3" }, { "custom_57.frames", "1" }, { "custom_57.EDITOR", "RocksCE.pcx" }, { "custom_57.EDITOR.xpos", "24" }, { "custom_57.EDITOR.ypos", "3" }, { "custom_58", "RocksCE.pcx" }, { "custom_58.xpos", "9" }, { "custom_58.ypos", "3" }, { "custom_58.frames", "1" }, { "custom_58.EDITOR", "RocksCE.pcx" }, { "custom_58.EDITOR.xpos", "25" }, { "custom_58.EDITOR.ypos", "3" }, { "custom_59", "RocksCE.pcx" }, { "custom_59.xpos", "10" }, { "custom_59.ypos", "3" }, { "custom_59.frames", "1" }, { "custom_59.EDITOR", "RocksCE.pcx" }, { "custom_59.EDITOR.xpos", "26" }, { "custom_59.EDITOR.ypos", "3" }, { "custom_60", "RocksCE.pcx" }, { "custom_60.xpos", "11" }, { "custom_60.ypos", "3" }, { "custom_60.frames", "1" }, { "custom_60.EDITOR", "RocksCE.pcx" }, { "custom_60.EDITOR.xpos", "27" }, { "custom_60.EDITOR.ypos", "3" }, { "custom_61", "RocksCE.pcx" }, { "custom_61.xpos", "12" }, { "custom_61.ypos", "3" }, { "custom_61.frames", "1" }, { "custom_61.EDITOR", "RocksCE.pcx" }, { "custom_61.EDITOR.xpos", "28" }, { "custom_61.EDITOR.ypos", "3" }, { "custom_62", "RocksCE.pcx" }, { "custom_62.xpos", "13" }, { "custom_62.ypos", "3" }, { "custom_62.frames", "1" }, { "custom_62.EDITOR", "RocksCE.pcx" }, { "custom_62.EDITOR.xpos", "29" }, { "custom_62.EDITOR.ypos", "3" }, { "custom_63", "RocksCE.pcx" }, { "custom_63.xpos", "14" }, { "custom_63.ypos", "3" }, { "custom_63.frames", "1" }, { "custom_63.EDITOR", "RocksCE.pcx" }, { "custom_63.EDITOR.xpos", "30" }, { "custom_63.EDITOR.ypos", "3" }, { "custom_64", "RocksCE.pcx" }, { "custom_64.xpos", "15" }, { "custom_64.ypos", "3" }, { "custom_64.frames", "1" }, { "custom_64.EDITOR", "RocksCE.pcx" }, { "custom_64.EDITOR.xpos", "31" }, { "custom_64.EDITOR.ypos", "3" }, { "custom_65", "RocksCE.pcx" }, { "custom_65.xpos", "0" }, { "custom_65.ypos", "4" }, { "custom_65.frames", "1" }, { "custom_65.EDITOR", "RocksCE.pcx" }, { "custom_65.EDITOR.xpos", "16" }, { "custom_65.EDITOR.ypos", "4" }, { "custom_66", "RocksCE.pcx" }, { "custom_66.xpos", "1" }, { "custom_66.ypos", "4" }, { "custom_66.frames", "1" }, { "custom_66.EDITOR", "RocksCE.pcx" }, { "custom_66.EDITOR.xpos", "17" }, { "custom_66.EDITOR.ypos", "4" }, { "custom_67", "RocksCE.pcx" }, { "custom_67.xpos", "2" }, { "custom_67.ypos", "4" }, { "custom_67.frames", "1" }, { "custom_67.EDITOR", "RocksCE.pcx" }, { "custom_67.EDITOR.xpos", "18" }, { "custom_67.EDITOR.ypos", "4" }, { "custom_68", "RocksCE.pcx" }, { "custom_68.xpos", "3" }, { "custom_68.ypos", "4" }, { "custom_68.frames", "1" }, { "custom_68.EDITOR", "RocksCE.pcx" }, { "custom_68.EDITOR.xpos", "19" }, { "custom_68.EDITOR.ypos", "4" }, { "custom_69", "RocksCE.pcx" }, { "custom_69.xpos", "4" }, { "custom_69.ypos", "4" }, { "custom_69.frames", "1" }, { "custom_69.EDITOR", "RocksCE.pcx" }, { "custom_69.EDITOR.xpos", "20" }, { "custom_69.EDITOR.ypos", "4" }, { "custom_70", "RocksCE.pcx" }, { "custom_70.xpos", "5" }, { "custom_70.ypos", "4" }, { "custom_70.frames", "1" }, { "custom_70.EDITOR", "RocksCE.pcx" }, { "custom_70.EDITOR.xpos", "21" }, { "custom_70.EDITOR.ypos", "4" }, { "custom_71", "RocksCE.pcx" }, { "custom_71.xpos", "6" }, { "custom_71.ypos", "4" }, { "custom_71.frames", "1" }, { "custom_71.EDITOR", "RocksCE.pcx" }, { "custom_71.EDITOR.xpos", "22" }, { "custom_71.EDITOR.ypos", "4" }, { "custom_72", "RocksCE.pcx" }, { "custom_72.xpos", "7" }, { "custom_72.ypos", "4" }, { "custom_72.frames", "1" }, { "custom_72.EDITOR", "RocksCE.pcx" }, { "custom_72.EDITOR.xpos", "23" }, { "custom_72.EDITOR.ypos", "4" }, { "custom_73", "RocksCE.pcx" }, { "custom_73.xpos", "8" }, { "custom_73.ypos", "4" }, { "custom_73.frames", "1" }, { "custom_73.EDITOR", "RocksCE.pcx" }, { "custom_73.EDITOR.xpos", "24" }, { "custom_73.EDITOR.ypos", "4" }, { "custom_74", "RocksCE.pcx" }, { "custom_74.xpos", "9" }, { "custom_74.ypos", "4" }, { "custom_74.frames", "1" }, { "custom_74.EDITOR", "RocksCE.pcx" }, { "custom_74.EDITOR.xpos", "25" }, { "custom_74.EDITOR.ypos", "4" }, { "custom_75", "RocksCE.pcx" }, { "custom_75.xpos", "10" }, { "custom_75.ypos", "4" }, { "custom_75.frames", "1" }, { "custom_75.EDITOR", "RocksCE.pcx" }, { "custom_75.EDITOR.xpos", "26" }, { "custom_75.EDITOR.ypos", "4" }, { "custom_76", "RocksCE.pcx" }, { "custom_76.xpos", "11" }, { "custom_76.ypos", "4" }, { "custom_76.frames", "1" }, { "custom_76.EDITOR", "RocksCE.pcx" }, { "custom_76.EDITOR.xpos", "27" }, { "custom_76.EDITOR.ypos", "4" }, { "custom_77", "RocksCE.pcx" }, { "custom_77.xpos", "12" }, { "custom_77.ypos", "4" }, { "custom_77.frames", "1" }, { "custom_77.EDITOR", "RocksCE.pcx" }, { "custom_77.EDITOR.xpos", "28" }, { "custom_77.EDITOR.ypos", "4" }, { "custom_78", "RocksCE.pcx" }, { "custom_78.xpos", "13" }, { "custom_78.ypos", "4" }, { "custom_78.frames", "1" }, { "custom_78.EDITOR", "RocksCE.pcx" }, { "custom_78.EDITOR.xpos", "29" }, { "custom_78.EDITOR.ypos", "4" }, { "custom_79", "RocksCE.pcx" }, { "custom_79.xpos", "14" }, { "custom_79.ypos", "4" }, { "custom_79.frames", "1" }, { "custom_79.EDITOR", "RocksCE.pcx" }, { "custom_79.EDITOR.xpos", "30" }, { "custom_79.EDITOR.ypos", "4" }, { "custom_80", "RocksCE.pcx" }, { "custom_80.xpos", "15" }, { "custom_80.ypos", "4" }, { "custom_80.frames", "1" }, { "custom_80.EDITOR", "RocksCE.pcx" }, { "custom_80.EDITOR.xpos", "31" }, { "custom_80.EDITOR.ypos", "4" }, { "custom_81", "RocksCE.pcx" }, { "custom_81.xpos", "0" }, { "custom_81.ypos", "5" }, { "custom_81.frames", "1" }, { "custom_81.EDITOR", "RocksCE.pcx" }, { "custom_81.EDITOR.xpos", "16" }, { "custom_81.EDITOR.ypos", "5" }, { "custom_82", "RocksCE.pcx" }, { "custom_82.xpos", "1" }, { "custom_82.ypos", "5" }, { "custom_82.frames", "1" }, { "custom_82.EDITOR", "RocksCE.pcx" }, { "custom_82.EDITOR.xpos", "17" }, { "custom_82.EDITOR.ypos", "5" }, { "custom_83", "RocksCE.pcx" }, { "custom_83.xpos", "2" }, { "custom_83.ypos", "5" }, { "custom_83.frames", "1" }, { "custom_83.EDITOR", "RocksCE.pcx" }, { "custom_83.EDITOR.xpos", "18" }, { "custom_83.EDITOR.ypos", "5" }, { "custom_84", "RocksCE.pcx" }, { "custom_84.xpos", "3" }, { "custom_84.ypos", "5" }, { "custom_84.frames", "1" }, { "custom_84.EDITOR", "RocksCE.pcx" }, { "custom_84.EDITOR.xpos", "19" }, { "custom_84.EDITOR.ypos", "5" }, { "custom_85", "RocksCE.pcx" }, { "custom_85.xpos", "4" }, { "custom_85.ypos", "5" }, { "custom_85.frames", "1" }, { "custom_85.EDITOR", "RocksCE.pcx" }, { "custom_85.EDITOR.xpos", "20" }, { "custom_85.EDITOR.ypos", "5" }, { "custom_86", "RocksCE.pcx" }, { "custom_86.xpos", "5" }, { "custom_86.ypos", "5" }, { "custom_86.frames", "1" }, { "custom_86.EDITOR", "RocksCE.pcx" }, { "custom_86.EDITOR.xpos", "21" }, { "custom_86.EDITOR.ypos", "5" }, { "custom_87", "RocksCE.pcx" }, { "custom_87.xpos", "6" }, { "custom_87.ypos", "5" }, { "custom_87.frames", "1" }, { "custom_87.EDITOR", "RocksCE.pcx" }, { "custom_87.EDITOR.xpos", "22" }, { "custom_87.EDITOR.ypos", "5" }, { "custom_88", "RocksCE.pcx" }, { "custom_88.xpos", "7" }, { "custom_88.ypos", "5" }, { "custom_88.frames", "1" }, { "custom_88.EDITOR", "RocksCE.pcx" }, { "custom_88.EDITOR.xpos", "23" }, { "custom_88.EDITOR.ypos", "5" }, { "custom_89", "RocksCE.pcx" }, { "custom_89.xpos", "8" }, { "custom_89.ypos", "5" }, { "custom_89.frames", "1" }, { "custom_89.EDITOR", "RocksCE.pcx" }, { "custom_89.EDITOR.xpos", "24" }, { "custom_89.EDITOR.ypos", "5" }, { "custom_90", "RocksCE.pcx" }, { "custom_90.xpos", "9" }, { "custom_90.ypos", "5" }, { "custom_90.frames", "1" }, { "custom_90.EDITOR", "RocksCE.pcx" }, { "custom_90.EDITOR.xpos", "25" }, { "custom_90.EDITOR.ypos", "5" }, { "custom_91", "RocksCE.pcx" }, { "custom_91.xpos", "10" }, { "custom_91.ypos", "5" }, { "custom_91.frames", "1" }, { "custom_91.EDITOR", "RocksCE.pcx" }, { "custom_91.EDITOR.xpos", "26" }, { "custom_91.EDITOR.ypos", "5" }, { "custom_92", "RocksCE.pcx" }, { "custom_92.xpos", "11" }, { "custom_92.ypos", "5" }, { "custom_92.frames", "1" }, { "custom_92.EDITOR", "RocksCE.pcx" }, { "custom_92.EDITOR.xpos", "27" }, { "custom_92.EDITOR.ypos", "5" }, { "custom_93", "RocksCE.pcx" }, { "custom_93.xpos", "12" }, { "custom_93.ypos", "5" }, { "custom_93.frames", "1" }, { "custom_93.EDITOR", "RocksCE.pcx" }, { "custom_93.EDITOR.xpos", "28" }, { "custom_93.EDITOR.ypos", "5" }, { "custom_94", "RocksCE.pcx" }, { "custom_94.xpos", "13" }, { "custom_94.ypos", "5" }, { "custom_94.frames", "1" }, { "custom_94.EDITOR", "RocksCE.pcx" }, { "custom_94.EDITOR.xpos", "29" }, { "custom_94.EDITOR.ypos", "5" }, { "custom_95", "RocksCE.pcx" }, { "custom_95.xpos", "14" }, { "custom_95.ypos", "5" }, { "custom_95.frames", "1" }, { "custom_95.EDITOR", "RocksCE.pcx" }, { "custom_95.EDITOR.xpos", "30" }, { "custom_95.EDITOR.ypos", "5" }, { "custom_96", "RocksCE.pcx" }, { "custom_96.xpos", "15" }, { "custom_96.ypos", "5" }, { "custom_96.frames", "1" }, { "custom_96.EDITOR", "RocksCE.pcx" }, { "custom_96.EDITOR.xpos", "31" }, { "custom_96.EDITOR.ypos", "5" }, { "custom_97", "RocksCE.pcx" }, { "custom_97.xpos", "0" }, { "custom_97.ypos", "6" }, { "custom_97.frames", "1" }, { "custom_97.EDITOR", "RocksCE.pcx" }, { "custom_97.EDITOR.xpos", "16" }, { "custom_97.EDITOR.ypos", "6" }, { "custom_98", "RocksCE.pcx" }, { "custom_98.xpos", "1" }, { "custom_98.ypos", "6" }, { "custom_98.frames", "1" }, { "custom_98.EDITOR", "RocksCE.pcx" }, { "custom_98.EDITOR.xpos", "17" }, { "custom_98.EDITOR.ypos", "6" }, { "custom_99", "RocksCE.pcx" }, { "custom_99.xpos", "2" }, { "custom_99.ypos", "6" }, { "custom_99.frames", "1" }, { "custom_99.EDITOR", "RocksCE.pcx" }, { "custom_99.EDITOR.xpos", "18" }, { "custom_99.EDITOR.ypos", "6" }, { "custom_100", "RocksCE.pcx" }, { "custom_100.xpos", "3" }, { "custom_100.ypos", "6" }, { "custom_100.frames", "1" }, { "custom_100.EDITOR", "RocksCE.pcx" }, { "custom_100.EDITOR.xpos", "19" }, { "custom_100.EDITOR.ypos", "6" }, { "custom_101", "RocksCE.pcx" }, { "custom_101.xpos", "4" }, { "custom_101.ypos", "6" }, { "custom_101.frames", "1" }, { "custom_101.EDITOR", "RocksCE.pcx" }, { "custom_101.EDITOR.xpos", "20" }, { "custom_101.EDITOR.ypos", "6" }, { "custom_102", "RocksCE.pcx" }, { "custom_102.xpos", "5" }, { "custom_102.ypos", "6" }, { "custom_102.frames", "1" }, { "custom_102.EDITOR", "RocksCE.pcx" }, { "custom_102.EDITOR.xpos", "21" }, { "custom_102.EDITOR.ypos", "6" }, { "custom_103", "RocksCE.pcx" }, { "custom_103.xpos", "6" }, { "custom_103.ypos", "6" }, { "custom_103.frames", "1" }, { "custom_103.EDITOR", "RocksCE.pcx" }, { "custom_103.EDITOR.xpos", "22" }, { "custom_103.EDITOR.ypos", "6" }, { "custom_104", "RocksCE.pcx" }, { "custom_104.xpos", "7" }, { "custom_104.ypos", "6" }, { "custom_104.frames", "1" }, { "custom_104.EDITOR", "RocksCE.pcx" }, { "custom_104.EDITOR.xpos", "23" }, { "custom_104.EDITOR.ypos", "6" }, { "custom_105", "RocksCE.pcx" }, { "custom_105.xpos", "8" }, { "custom_105.ypos", "6" }, { "custom_105.frames", "1" }, { "custom_105.EDITOR", "RocksCE.pcx" }, { "custom_105.EDITOR.xpos", "24" }, { "custom_105.EDITOR.ypos", "6" }, { "custom_106", "RocksCE.pcx" }, { "custom_106.xpos", "9" }, { "custom_106.ypos", "6" }, { "custom_106.frames", "1" }, { "custom_106.EDITOR", "RocksCE.pcx" }, { "custom_106.EDITOR.xpos", "25" }, { "custom_106.EDITOR.ypos", "6" }, { "custom_107", "RocksCE.pcx" }, { "custom_107.xpos", "10" }, { "custom_107.ypos", "6" }, { "custom_107.frames", "1" }, { "custom_107.EDITOR", "RocksCE.pcx" }, { "custom_107.EDITOR.xpos", "26" }, { "custom_107.EDITOR.ypos", "6" }, { "custom_108", "RocksCE.pcx" }, { "custom_108.xpos", "11" }, { "custom_108.ypos", "6" }, { "custom_108.frames", "1" }, { "custom_108.EDITOR", "RocksCE.pcx" }, { "custom_108.EDITOR.xpos", "27" }, { "custom_108.EDITOR.ypos", "6" }, { "custom_109", "RocksCE.pcx" }, { "custom_109.xpos", "12" }, { "custom_109.ypos", "6" }, { "custom_109.frames", "1" }, { "custom_109.EDITOR", "RocksCE.pcx" }, { "custom_109.EDITOR.xpos", "28" }, { "custom_109.EDITOR.ypos", "6" }, { "custom_110", "RocksCE.pcx" }, { "custom_110.xpos", "13" }, { "custom_110.ypos", "6" }, { "custom_110.frames", "1" }, { "custom_110.EDITOR", "RocksCE.pcx" }, { "custom_110.EDITOR.xpos", "29" }, { "custom_110.EDITOR.ypos", "6" }, { "custom_111", "RocksCE.pcx" }, { "custom_111.xpos", "14" }, { "custom_111.ypos", "6" }, { "custom_111.frames", "1" }, { "custom_111.EDITOR", "RocksCE.pcx" }, { "custom_111.EDITOR.xpos", "30" }, { "custom_111.EDITOR.ypos", "6" }, { "custom_112", "RocksCE.pcx" }, { "custom_112.xpos", "15" }, { "custom_112.ypos", "6" }, { "custom_112.frames", "1" }, { "custom_112.EDITOR", "RocksCE.pcx" }, { "custom_112.EDITOR.xpos", "31" }, { "custom_112.EDITOR.ypos", "6" }, { "custom_113", "RocksCE.pcx" }, { "custom_113.xpos", "0" }, { "custom_113.ypos", "7" }, { "custom_113.frames", "1" }, { "custom_113.EDITOR", "RocksCE.pcx" }, { "custom_113.EDITOR.xpos", "16" }, { "custom_113.EDITOR.ypos", "7" }, { "custom_114", "RocksCE.pcx" }, { "custom_114.xpos", "1" }, { "custom_114.ypos", "7" }, { "custom_114.frames", "1" }, { "custom_114.EDITOR", "RocksCE.pcx" }, { "custom_114.EDITOR.xpos", "17" }, { "custom_114.EDITOR.ypos", "7" }, { "custom_115", "RocksCE.pcx" }, { "custom_115.xpos", "2" }, { "custom_115.ypos", "7" }, { "custom_115.frames", "1" }, { "custom_115.EDITOR", "RocksCE.pcx" }, { "custom_115.EDITOR.xpos", "18" }, { "custom_115.EDITOR.ypos", "7" }, { "custom_116", "RocksCE.pcx" }, { "custom_116.xpos", "3" }, { "custom_116.ypos", "7" }, { "custom_116.frames", "1" }, { "custom_116.EDITOR", "RocksCE.pcx" }, { "custom_116.EDITOR.xpos", "19" }, { "custom_116.EDITOR.ypos", "7" }, { "custom_117", "RocksCE.pcx" }, { "custom_117.xpos", "4" }, { "custom_117.ypos", "7" }, { "custom_117.frames", "1" }, { "custom_117.EDITOR", "RocksCE.pcx" }, { "custom_117.EDITOR.xpos", "20" }, { "custom_117.EDITOR.ypos", "7" }, { "custom_118", "RocksCE.pcx" }, { "custom_118.xpos", "5" }, { "custom_118.ypos", "7" }, { "custom_118.frames", "1" }, { "custom_118.EDITOR", "RocksCE.pcx" }, { "custom_118.EDITOR.xpos", "21" }, { "custom_118.EDITOR.ypos", "7" }, { "custom_119", "RocksCE.pcx" }, { "custom_119.xpos", "6" }, { "custom_119.ypos", "7" }, { "custom_119.frames", "1" }, { "custom_119.EDITOR", "RocksCE.pcx" }, { "custom_119.EDITOR.xpos", "22" }, { "custom_119.EDITOR.ypos", "7" }, { "custom_120", "RocksCE.pcx" }, { "custom_120.xpos", "7" }, { "custom_120.ypos", "7" }, { "custom_120.frames", "1" }, { "custom_120.EDITOR", "RocksCE.pcx" }, { "custom_120.EDITOR.xpos", "23" }, { "custom_120.EDITOR.ypos", "7" }, { "custom_121", "RocksCE.pcx" }, { "custom_121.xpos", "8" }, { "custom_121.ypos", "7" }, { "custom_121.frames", "1" }, { "custom_121.EDITOR", "RocksCE.pcx" }, { "custom_121.EDITOR.xpos", "24" }, { "custom_121.EDITOR.ypos", "7" }, { "custom_122", "RocksCE.pcx" }, { "custom_122.xpos", "9" }, { "custom_122.ypos", "7" }, { "custom_122.frames", "1" }, { "custom_122.EDITOR", "RocksCE.pcx" }, { "custom_122.EDITOR.xpos", "25" }, { "custom_122.EDITOR.ypos", "7" }, { "custom_123", "RocksCE.pcx" }, { "custom_123.xpos", "10" }, { "custom_123.ypos", "7" }, { "custom_123.frames", "1" }, { "custom_123.EDITOR", "RocksCE.pcx" }, { "custom_123.EDITOR.xpos", "26" }, { "custom_123.EDITOR.ypos", "7" }, { "custom_124", "RocksCE.pcx" }, { "custom_124.xpos", "11" }, { "custom_124.ypos", "7" }, { "custom_124.frames", "1" }, { "custom_124.EDITOR", "RocksCE.pcx" }, { "custom_124.EDITOR.xpos", "27" }, { "custom_124.EDITOR.ypos", "7" }, { "custom_125", "RocksCE.pcx" }, { "custom_125.xpos", "12" }, { "custom_125.ypos", "7" }, { "custom_125.frames", "1" }, { "custom_125.EDITOR", "RocksCE.pcx" }, { "custom_125.EDITOR.xpos", "28" }, { "custom_125.EDITOR.ypos", "7" }, { "custom_126", "RocksCE.pcx" }, { "custom_126.xpos", "13" }, { "custom_126.ypos", "7" }, { "custom_126.frames", "1" }, { "custom_126.EDITOR", "RocksCE.pcx" }, { "custom_126.EDITOR.xpos", "29" }, { "custom_126.EDITOR.ypos", "7" }, { "custom_127", "RocksCE.pcx" }, { "custom_127.xpos", "14" }, { "custom_127.ypos", "7" }, { "custom_127.frames", "1" }, { "custom_127.EDITOR", "RocksCE.pcx" }, { "custom_127.EDITOR.xpos", "30" }, { "custom_127.EDITOR.ypos", "7" }, { "custom_128", "RocksCE.pcx" }, { "custom_128.xpos", "15" }, { "custom_128.ypos", "7" }, { "custom_128.frames", "1" }, { "custom_128.EDITOR", "RocksCE.pcx" }, { "custom_128.EDITOR.xpos", "31" }, { "custom_128.EDITOR.ypos", "7" }, { "custom_129", "RocksCE.pcx" }, { "custom_129.xpos", "0" }, { "custom_129.ypos", "8" }, { "custom_129.frames", "1" }, { "custom_129.EDITOR", "RocksCE.pcx" }, { "custom_129.EDITOR.xpos", "16" }, { "custom_129.EDITOR.ypos", "8" }, { "custom_130", "RocksCE.pcx" }, { "custom_130.xpos", "1" }, { "custom_130.ypos", "8" }, { "custom_130.frames", "1" }, { "custom_130.EDITOR", "RocksCE.pcx" }, { "custom_130.EDITOR.xpos", "17" }, { "custom_130.EDITOR.ypos", "8" }, { "custom_131", "RocksCE.pcx" }, { "custom_131.xpos", "2" }, { "custom_131.ypos", "8" }, { "custom_131.frames", "1" }, { "custom_131.EDITOR", "RocksCE.pcx" }, { "custom_131.EDITOR.xpos", "18" }, { "custom_131.EDITOR.ypos", "8" }, { "custom_132", "RocksCE.pcx" }, { "custom_132.xpos", "3" }, { "custom_132.ypos", "8" }, { "custom_132.frames", "1" }, { "custom_132.EDITOR", "RocksCE.pcx" }, { "custom_132.EDITOR.xpos", "19" }, { "custom_132.EDITOR.ypos", "8" }, { "custom_133", "RocksCE.pcx" }, { "custom_133.xpos", "4" }, { "custom_133.ypos", "8" }, { "custom_133.frames", "1" }, { "custom_133.EDITOR", "RocksCE.pcx" }, { "custom_133.EDITOR.xpos", "20" }, { "custom_133.EDITOR.ypos", "8" }, { "custom_134", "RocksCE.pcx" }, { "custom_134.xpos", "5" }, { "custom_134.ypos", "8" }, { "custom_134.frames", "1" }, { "custom_134.EDITOR", "RocksCE.pcx" }, { "custom_134.EDITOR.xpos", "21" }, { "custom_134.EDITOR.ypos", "8" }, { "custom_135", "RocksCE.pcx" }, { "custom_135.xpos", "6" }, { "custom_135.ypos", "8" }, { "custom_135.frames", "1" }, { "custom_135.EDITOR", "RocksCE.pcx" }, { "custom_135.EDITOR.xpos", "22" }, { "custom_135.EDITOR.ypos", "8" }, { "custom_136", "RocksCE.pcx" }, { "custom_136.xpos", "7" }, { "custom_136.ypos", "8" }, { "custom_136.frames", "1" }, { "custom_136.EDITOR", "RocksCE.pcx" }, { "custom_136.EDITOR.xpos", "23" }, { "custom_136.EDITOR.ypos", "8" }, { "custom_137", "RocksCE.pcx" }, { "custom_137.xpos", "8" }, { "custom_137.ypos", "8" }, { "custom_137.frames", "1" }, { "custom_137.EDITOR", "RocksCE.pcx" }, { "custom_137.EDITOR.xpos", "24" }, { "custom_137.EDITOR.ypos", "8" }, { "custom_138", "RocksCE.pcx" }, { "custom_138.xpos", "9" }, { "custom_138.ypos", "8" }, { "custom_138.frames", "1" }, { "custom_138.EDITOR", "RocksCE.pcx" }, { "custom_138.EDITOR.xpos", "25" }, { "custom_138.EDITOR.ypos", "8" }, { "custom_139", "RocksCE.pcx" }, { "custom_139.xpos", "10" }, { "custom_139.ypos", "8" }, { "custom_139.frames", "1" }, { "custom_139.EDITOR", "RocksCE.pcx" }, { "custom_139.EDITOR.xpos", "26" }, { "custom_139.EDITOR.ypos", "8" }, { "custom_140", "RocksCE.pcx" }, { "custom_140.xpos", "11" }, { "custom_140.ypos", "8" }, { "custom_140.frames", "1" }, { "custom_140.EDITOR", "RocksCE.pcx" }, { "custom_140.EDITOR.xpos", "27" }, { "custom_140.EDITOR.ypos", "8" }, { "custom_141", "RocksCE.pcx" }, { "custom_141.xpos", "12" }, { "custom_141.ypos", "8" }, { "custom_141.frames", "1" }, { "custom_141.EDITOR", "RocksCE.pcx" }, { "custom_141.EDITOR.xpos", "28" }, { "custom_141.EDITOR.ypos", "8" }, { "custom_142", "RocksCE.pcx" }, { "custom_142.xpos", "13" }, { "custom_142.ypos", "8" }, { "custom_142.frames", "1" }, { "custom_142.EDITOR", "RocksCE.pcx" }, { "custom_142.EDITOR.xpos", "29" }, { "custom_142.EDITOR.ypos", "8" }, { "custom_143", "RocksCE.pcx" }, { "custom_143.xpos", "14" }, { "custom_143.ypos", "8" }, { "custom_143.frames", "1" }, { "custom_143.EDITOR", "RocksCE.pcx" }, { "custom_143.EDITOR.xpos", "30" }, { "custom_143.EDITOR.ypos", "8" }, { "custom_144", "RocksCE.pcx" }, { "custom_144.xpos", "15" }, { "custom_144.ypos", "8" }, { "custom_144.frames", "1" }, { "custom_144.EDITOR", "RocksCE.pcx" }, { "custom_144.EDITOR.xpos", "31" }, { "custom_144.EDITOR.ypos", "8" }, { "custom_145", "RocksCE.pcx" }, { "custom_145.xpos", "0" }, { "custom_145.ypos", "9" }, { "custom_145.frames", "1" }, { "custom_145.EDITOR", "RocksCE.pcx" }, { "custom_145.EDITOR.xpos", "16" }, { "custom_145.EDITOR.ypos", "9" }, { "custom_146", "RocksCE.pcx" }, { "custom_146.xpos", "1" }, { "custom_146.ypos", "9" }, { "custom_146.frames", "1" }, { "custom_146.EDITOR", "RocksCE.pcx" }, { "custom_146.EDITOR.xpos", "17" }, { "custom_146.EDITOR.ypos", "9" }, { "custom_147", "RocksCE.pcx" }, { "custom_147.xpos", "2" }, { "custom_147.ypos", "9" }, { "custom_147.frames", "1" }, { "custom_147.EDITOR", "RocksCE.pcx" }, { "custom_147.EDITOR.xpos", "18" }, { "custom_147.EDITOR.ypos", "9" }, { "custom_148", "RocksCE.pcx" }, { "custom_148.xpos", "3" }, { "custom_148.ypos", "9" }, { "custom_148.frames", "1" }, { "custom_148.EDITOR", "RocksCE.pcx" }, { "custom_148.EDITOR.xpos", "19" }, { "custom_148.EDITOR.ypos", "9" }, { "custom_149", "RocksCE.pcx" }, { "custom_149.xpos", "4" }, { "custom_149.ypos", "9" }, { "custom_149.frames", "1" }, { "custom_149.EDITOR", "RocksCE.pcx" }, { "custom_149.EDITOR.xpos", "20" }, { "custom_149.EDITOR.ypos", "9" }, { "custom_150", "RocksCE.pcx" }, { "custom_150.xpos", "5" }, { "custom_150.ypos", "9" }, { "custom_150.frames", "1" }, { "custom_150.EDITOR", "RocksCE.pcx" }, { "custom_150.EDITOR.xpos", "21" }, { "custom_150.EDITOR.ypos", "9" }, { "custom_151", "RocksCE.pcx" }, { "custom_151.xpos", "6" }, { "custom_151.ypos", "9" }, { "custom_151.frames", "1" }, { "custom_151.EDITOR", "RocksCE.pcx" }, { "custom_151.EDITOR.xpos", "22" }, { "custom_151.EDITOR.ypos", "9" }, { "custom_152", "RocksCE.pcx" }, { "custom_152.xpos", "7" }, { "custom_152.ypos", "9" }, { "custom_152.frames", "1" }, { "custom_152.EDITOR", "RocksCE.pcx" }, { "custom_152.EDITOR.xpos", "23" }, { "custom_152.EDITOR.ypos", "9" }, { "custom_153", "RocksCE.pcx" }, { "custom_153.xpos", "8" }, { "custom_153.ypos", "9" }, { "custom_153.frames", "1" }, { "custom_153.EDITOR", "RocksCE.pcx" }, { "custom_153.EDITOR.xpos", "24" }, { "custom_153.EDITOR.ypos", "9" }, { "custom_154", "RocksCE.pcx" }, { "custom_154.xpos", "9" }, { "custom_154.ypos", "9" }, { "custom_154.frames", "1" }, { "custom_154.EDITOR", "RocksCE.pcx" }, { "custom_154.EDITOR.xpos", "25" }, { "custom_154.EDITOR.ypos", "9" }, { "custom_155", "RocksCE.pcx" }, { "custom_155.xpos", "10" }, { "custom_155.ypos", "9" }, { "custom_155.frames", "1" }, { "custom_155.EDITOR", "RocksCE.pcx" }, { "custom_155.EDITOR.xpos", "26" }, { "custom_155.EDITOR.ypos", "9" }, { "custom_156", "RocksCE.pcx" }, { "custom_156.xpos", "11" }, { "custom_156.ypos", "9" }, { "custom_156.frames", "1" }, { "custom_156.EDITOR", "RocksCE.pcx" }, { "custom_156.EDITOR.xpos", "27" }, { "custom_156.EDITOR.ypos", "9" }, { "custom_157", "RocksCE.pcx" }, { "custom_157.xpos", "12" }, { "custom_157.ypos", "9" }, { "custom_157.frames", "1" }, { "custom_157.EDITOR", "RocksCE.pcx" }, { "custom_157.EDITOR.xpos", "28" }, { "custom_157.EDITOR.ypos", "9" }, { "custom_158", "RocksCE.pcx" }, { "custom_158.xpos", "13" }, { "custom_158.ypos", "9" }, { "custom_158.frames", "1" }, { "custom_158.EDITOR", "RocksCE.pcx" }, { "custom_158.EDITOR.xpos", "29" }, { "custom_158.EDITOR.ypos", "9" }, { "custom_159", "RocksCE.pcx" }, { "custom_159.xpos", "14" }, { "custom_159.ypos", "9" }, { "custom_159.frames", "1" }, { "custom_159.EDITOR", "RocksCE.pcx" }, { "custom_159.EDITOR.xpos", "30" }, { "custom_159.EDITOR.ypos", "9" }, { "custom_160", "RocksCE.pcx" }, { "custom_160.xpos", "15" }, { "custom_160.ypos", "9" }, { "custom_160.frames", "1" }, { "custom_160.EDITOR", "RocksCE.pcx" }, { "custom_160.EDITOR.xpos", "31" }, { "custom_160.EDITOR.ypos", "9" }, { "custom_161", "RocksCE.pcx" }, { "custom_161.xpos", "0" }, { "custom_161.ypos", "10" }, { "custom_161.frames", "1" }, { "custom_161.EDITOR", "RocksCE.pcx" }, { "custom_161.EDITOR.xpos", "16" }, { "custom_161.EDITOR.ypos", "10" }, { "custom_162", "RocksCE.pcx" }, { "custom_162.xpos", "1" }, { "custom_162.ypos", "10" }, { "custom_162.frames", "1" }, { "custom_162.EDITOR", "RocksCE.pcx" }, { "custom_162.EDITOR.xpos", "17" }, { "custom_162.EDITOR.ypos", "10" }, { "custom_163", "RocksCE.pcx" }, { "custom_163.xpos", "2" }, { "custom_163.ypos", "10" }, { "custom_163.frames", "1" }, { "custom_163.EDITOR", "RocksCE.pcx" }, { "custom_163.EDITOR.xpos", "18" }, { "custom_163.EDITOR.ypos", "10" }, { "custom_164", "RocksCE.pcx" }, { "custom_164.xpos", "3" }, { "custom_164.ypos", "10" }, { "custom_164.frames", "1" }, { "custom_164.EDITOR", "RocksCE.pcx" }, { "custom_164.EDITOR.xpos", "19" }, { "custom_164.EDITOR.ypos", "10" }, { "custom_165", "RocksCE.pcx" }, { "custom_165.xpos", "4" }, { "custom_165.ypos", "10" }, { "custom_165.frames", "1" }, { "custom_165.EDITOR", "RocksCE.pcx" }, { "custom_165.EDITOR.xpos", "20" }, { "custom_165.EDITOR.ypos", "10" }, { "custom_166", "RocksCE.pcx" }, { "custom_166.xpos", "5" }, { "custom_166.ypos", "10" }, { "custom_166.frames", "1" }, { "custom_166.EDITOR", "RocksCE.pcx" }, { "custom_166.EDITOR.xpos", "21" }, { "custom_166.EDITOR.ypos", "10" }, { "custom_167", "RocksCE.pcx" }, { "custom_167.xpos", "6" }, { "custom_167.ypos", "10" }, { "custom_167.frames", "1" }, { "custom_167.EDITOR", "RocksCE.pcx" }, { "custom_167.EDITOR.xpos", "22" }, { "custom_167.EDITOR.ypos", "10" }, { "custom_168", "RocksCE.pcx" }, { "custom_168.xpos", "7" }, { "custom_168.ypos", "10" }, { "custom_168.frames", "1" }, { "custom_168.EDITOR", "RocksCE.pcx" }, { "custom_168.EDITOR.xpos", "23" }, { "custom_168.EDITOR.ypos", "10" }, { "custom_169", "RocksCE.pcx" }, { "custom_169.xpos", "8" }, { "custom_169.ypos", "10" }, { "custom_169.frames", "1" }, { "custom_169.EDITOR", "RocksCE.pcx" }, { "custom_169.EDITOR.xpos", "24" }, { "custom_169.EDITOR.ypos", "10" }, { "custom_170", "RocksCE.pcx" }, { "custom_170.xpos", "9" }, { "custom_170.ypos", "10" }, { "custom_170.frames", "1" }, { "custom_170.EDITOR", "RocksCE.pcx" }, { "custom_170.EDITOR.xpos", "25" }, { "custom_170.EDITOR.ypos", "10" }, { "custom_171", "RocksCE.pcx" }, { "custom_171.xpos", "10" }, { "custom_171.ypos", "10" }, { "custom_171.frames", "1" }, { "custom_171.EDITOR", "RocksCE.pcx" }, { "custom_171.EDITOR.xpos", "26" }, { "custom_171.EDITOR.ypos", "10" }, { "custom_172", "RocksCE.pcx" }, { "custom_172.xpos", "11" }, { "custom_172.ypos", "10" }, { "custom_172.frames", "1" }, { "custom_172.EDITOR", "RocksCE.pcx" }, { "custom_172.EDITOR.xpos", "27" }, { "custom_172.EDITOR.ypos", "10" }, { "custom_173", "RocksCE.pcx" }, { "custom_173.xpos", "12" }, { "custom_173.ypos", "10" }, { "custom_173.frames", "1" }, { "custom_173.EDITOR", "RocksCE.pcx" }, { "custom_173.EDITOR.xpos", "28" }, { "custom_173.EDITOR.ypos", "10" }, { "custom_174", "RocksCE.pcx" }, { "custom_174.xpos", "13" }, { "custom_174.ypos", "10" }, { "custom_174.frames", "1" }, { "custom_174.EDITOR", "RocksCE.pcx" }, { "custom_174.EDITOR.xpos", "29" }, { "custom_174.EDITOR.ypos", "10" }, { "custom_175", "RocksCE.pcx" }, { "custom_175.xpos", "14" }, { "custom_175.ypos", "10" }, { "custom_175.frames", "1" }, { "custom_175.EDITOR", "RocksCE.pcx" }, { "custom_175.EDITOR.xpos", "30" }, { "custom_175.EDITOR.ypos", "10" }, { "custom_176", "RocksCE.pcx" }, { "custom_176.xpos", "15" }, { "custom_176.ypos", "10" }, { "custom_176.frames", "1" }, { "custom_176.EDITOR", "RocksCE.pcx" }, { "custom_176.EDITOR.xpos", "31" }, { "custom_176.EDITOR.ypos", "10" }, { "custom_177", "RocksCE.pcx" }, { "custom_177.xpos", "0" }, { "custom_177.ypos", "11" }, { "custom_177.frames", "1" }, { "custom_177.EDITOR", "RocksCE.pcx" }, { "custom_177.EDITOR.xpos", "16" }, { "custom_177.EDITOR.ypos", "11" }, { "custom_178", "RocksCE.pcx" }, { "custom_178.xpos", "1" }, { "custom_178.ypos", "11" }, { "custom_178.frames", "1" }, { "custom_178.EDITOR", "RocksCE.pcx" }, { "custom_178.EDITOR.xpos", "17" }, { "custom_178.EDITOR.ypos", "11" }, { "custom_179", "RocksCE.pcx" }, { "custom_179.xpos", "2" }, { "custom_179.ypos", "11" }, { "custom_179.frames", "1" }, { "custom_179.EDITOR", "RocksCE.pcx" }, { "custom_179.EDITOR.xpos", "18" }, { "custom_179.EDITOR.ypos", "11" }, { "custom_180", "RocksCE.pcx" }, { "custom_180.xpos", "3" }, { "custom_180.ypos", "11" }, { "custom_180.frames", "1" }, { "custom_180.EDITOR", "RocksCE.pcx" }, { "custom_180.EDITOR.xpos", "19" }, { "custom_180.EDITOR.ypos", "11" }, { "custom_181", "RocksCE.pcx" }, { "custom_181.xpos", "4" }, { "custom_181.ypos", "11" }, { "custom_181.frames", "1" }, { "custom_181.EDITOR", "RocksCE.pcx" }, { "custom_181.EDITOR.xpos", "20" }, { "custom_181.EDITOR.ypos", "11" }, { "custom_182", "RocksCE.pcx" }, { "custom_182.xpos", "5" }, { "custom_182.ypos", "11" }, { "custom_182.frames", "1" }, { "custom_182.EDITOR", "RocksCE.pcx" }, { "custom_182.EDITOR.xpos", "21" }, { "custom_182.EDITOR.ypos", "11" }, { "custom_183", "RocksCE.pcx" }, { "custom_183.xpos", "6" }, { "custom_183.ypos", "11" }, { "custom_183.frames", "1" }, { "custom_183.EDITOR", "RocksCE.pcx" }, { "custom_183.EDITOR.xpos", "22" }, { "custom_183.EDITOR.ypos", "11" }, { "custom_184", "RocksCE.pcx" }, { "custom_184.xpos", "7" }, { "custom_184.ypos", "11" }, { "custom_184.frames", "1" }, { "custom_184.EDITOR", "RocksCE.pcx" }, { "custom_184.EDITOR.xpos", "23" }, { "custom_184.EDITOR.ypos", "11" }, { "custom_185", "RocksCE.pcx" }, { "custom_185.xpos", "8" }, { "custom_185.ypos", "11" }, { "custom_185.frames", "1" }, { "custom_185.EDITOR", "RocksCE.pcx" }, { "custom_185.EDITOR.xpos", "24" }, { "custom_185.EDITOR.ypos", "11" }, { "custom_186", "RocksCE.pcx" }, { "custom_186.xpos", "9" }, { "custom_186.ypos", "11" }, { "custom_186.frames", "1" }, { "custom_186.EDITOR", "RocksCE.pcx" }, { "custom_186.EDITOR.xpos", "25" }, { "custom_186.EDITOR.ypos", "11" }, { "custom_187", "RocksCE.pcx" }, { "custom_187.xpos", "10" }, { "custom_187.ypos", "11" }, { "custom_187.frames", "1" }, { "custom_187.EDITOR", "RocksCE.pcx" }, { "custom_187.EDITOR.xpos", "26" }, { "custom_187.EDITOR.ypos", "11" }, { "custom_188", "RocksCE.pcx" }, { "custom_188.xpos", "11" }, { "custom_188.ypos", "11" }, { "custom_188.frames", "1" }, { "custom_188.EDITOR", "RocksCE.pcx" }, { "custom_188.EDITOR.xpos", "27" }, { "custom_188.EDITOR.ypos", "11" }, { "custom_189", "RocksCE.pcx" }, { "custom_189.xpos", "12" }, { "custom_189.ypos", "11" }, { "custom_189.frames", "1" }, { "custom_189.EDITOR", "RocksCE.pcx" }, { "custom_189.EDITOR.xpos", "28" }, { "custom_189.EDITOR.ypos", "11" }, { "custom_190", "RocksCE.pcx" }, { "custom_190.xpos", "13" }, { "custom_190.ypos", "11" }, { "custom_190.frames", "1" }, { "custom_190.EDITOR", "RocksCE.pcx" }, { "custom_190.EDITOR.xpos", "29" }, { "custom_190.EDITOR.ypos", "11" }, { "custom_191", "RocksCE.pcx" }, { "custom_191.xpos", "14" }, { "custom_191.ypos", "11" }, { "custom_191.frames", "1" }, { "custom_191.EDITOR", "RocksCE.pcx" }, { "custom_191.EDITOR.xpos", "30" }, { "custom_191.EDITOR.ypos", "11" }, { "custom_192", "RocksCE.pcx" }, { "custom_192.xpos", "15" }, { "custom_192.ypos", "11" }, { "custom_192.frames", "1" }, { "custom_192.EDITOR", "RocksCE.pcx" }, { "custom_192.EDITOR.xpos", "31" }, { "custom_192.EDITOR.ypos", "11" }, { "custom_193", "RocksCE.pcx" }, { "custom_193.xpos", "0" }, { "custom_193.ypos", "12" }, { "custom_193.frames", "1" }, { "custom_193.EDITOR", "RocksCE.pcx" }, { "custom_193.EDITOR.xpos", "16" }, { "custom_193.EDITOR.ypos", "12" }, { "custom_194", "RocksCE.pcx" }, { "custom_194.xpos", "1" }, { "custom_194.ypos", "12" }, { "custom_194.frames", "1" }, { "custom_194.EDITOR", "RocksCE.pcx" }, { "custom_194.EDITOR.xpos", "17" }, { "custom_194.EDITOR.ypos", "12" }, { "custom_195", "RocksCE.pcx" }, { "custom_195.xpos", "2" }, { "custom_195.ypos", "12" }, { "custom_195.frames", "1" }, { "custom_195.EDITOR", "RocksCE.pcx" }, { "custom_195.EDITOR.xpos", "18" }, { "custom_195.EDITOR.ypos", "12" }, { "custom_196", "RocksCE.pcx" }, { "custom_196.xpos", "3" }, { "custom_196.ypos", "12" }, { "custom_196.frames", "1" }, { "custom_196.EDITOR", "RocksCE.pcx" }, { "custom_196.EDITOR.xpos", "19" }, { "custom_196.EDITOR.ypos", "12" }, { "custom_197", "RocksCE.pcx" }, { "custom_197.xpos", "4" }, { "custom_197.ypos", "12" }, { "custom_197.frames", "1" }, { "custom_197.EDITOR", "RocksCE.pcx" }, { "custom_197.EDITOR.xpos", "20" }, { "custom_197.EDITOR.ypos", "12" }, { "custom_198", "RocksCE.pcx" }, { "custom_198.xpos", "5" }, { "custom_198.ypos", "12" }, { "custom_198.frames", "1" }, { "custom_198.EDITOR", "RocksCE.pcx" }, { "custom_198.EDITOR.xpos", "21" }, { "custom_198.EDITOR.ypos", "12" }, { "custom_199", "RocksCE.pcx" }, { "custom_199.xpos", "6" }, { "custom_199.ypos", "12" }, { "custom_199.frames", "1" }, { "custom_199.EDITOR", "RocksCE.pcx" }, { "custom_199.EDITOR.xpos", "22" }, { "custom_199.EDITOR.ypos", "12" }, { "custom_200", "RocksCE.pcx" }, { "custom_200.xpos", "7" }, { "custom_200.ypos", "12" }, { "custom_200.frames", "1" }, { "custom_200.EDITOR", "RocksCE.pcx" }, { "custom_200.EDITOR.xpos", "23" }, { "custom_200.EDITOR.ypos", "12" }, { "custom_201", "RocksCE.pcx" }, { "custom_201.xpos", "8" }, { "custom_201.ypos", "12" }, { "custom_201.frames", "1" }, { "custom_201.EDITOR", "RocksCE.pcx" }, { "custom_201.EDITOR.xpos", "24" }, { "custom_201.EDITOR.ypos", "12" }, { "custom_202", "RocksCE.pcx" }, { "custom_202.xpos", "9" }, { "custom_202.ypos", "12" }, { "custom_202.frames", "1" }, { "custom_202.EDITOR", "RocksCE.pcx" }, { "custom_202.EDITOR.xpos", "25" }, { "custom_202.EDITOR.ypos", "12" }, { "custom_203", "RocksCE.pcx" }, { "custom_203.xpos", "10" }, { "custom_203.ypos", "12" }, { "custom_203.frames", "1" }, { "custom_203.EDITOR", "RocksCE.pcx" }, { "custom_203.EDITOR.xpos", "26" }, { "custom_203.EDITOR.ypos", "12" }, { "custom_204", "RocksCE.pcx" }, { "custom_204.xpos", "11" }, { "custom_204.ypos", "12" }, { "custom_204.frames", "1" }, { "custom_204.EDITOR", "RocksCE.pcx" }, { "custom_204.EDITOR.xpos", "27" }, { "custom_204.EDITOR.ypos", "12" }, { "custom_205", "RocksCE.pcx" }, { "custom_205.xpos", "12" }, { "custom_205.ypos", "12" }, { "custom_205.frames", "1" }, { "custom_205.EDITOR", "RocksCE.pcx" }, { "custom_205.EDITOR.xpos", "28" }, { "custom_205.EDITOR.ypos", "12" }, { "custom_206", "RocksCE.pcx" }, { "custom_206.xpos", "13" }, { "custom_206.ypos", "12" }, { "custom_206.frames", "1" }, { "custom_206.EDITOR", "RocksCE.pcx" }, { "custom_206.EDITOR.xpos", "29" }, { "custom_206.EDITOR.ypos", "12" }, { "custom_207", "RocksCE.pcx" }, { "custom_207.xpos", "14" }, { "custom_207.ypos", "12" }, { "custom_207.frames", "1" }, { "custom_207.EDITOR", "RocksCE.pcx" }, { "custom_207.EDITOR.xpos", "30" }, { "custom_207.EDITOR.ypos", "12" }, { "custom_208", "RocksCE.pcx" }, { "custom_208.xpos", "15" }, { "custom_208.ypos", "12" }, { "custom_208.frames", "1" }, { "custom_208.EDITOR", "RocksCE.pcx" }, { "custom_208.EDITOR.xpos", "31" }, { "custom_208.EDITOR.ypos", "12" }, { "custom_209", "RocksCE.pcx" }, { "custom_209.xpos", "0" }, { "custom_209.ypos", "13" }, { "custom_209.frames", "1" }, { "custom_209.EDITOR", "RocksCE.pcx" }, { "custom_209.EDITOR.xpos", "16" }, { "custom_209.EDITOR.ypos", "13" }, { "custom_210", "RocksCE.pcx" }, { "custom_210.xpos", "1" }, { "custom_210.ypos", "13" }, { "custom_210.frames", "1" }, { "custom_210.EDITOR", "RocksCE.pcx" }, { "custom_210.EDITOR.xpos", "17" }, { "custom_210.EDITOR.ypos", "13" }, { "custom_211", "RocksCE.pcx" }, { "custom_211.xpos", "2" }, { "custom_211.ypos", "13" }, { "custom_211.frames", "1" }, { "custom_211.EDITOR", "RocksCE.pcx" }, { "custom_211.EDITOR.xpos", "18" }, { "custom_211.EDITOR.ypos", "13" }, { "custom_212", "RocksCE.pcx" }, { "custom_212.xpos", "3" }, { "custom_212.ypos", "13" }, { "custom_212.frames", "1" }, { "custom_212.EDITOR", "RocksCE.pcx" }, { "custom_212.EDITOR.xpos", "19" }, { "custom_212.EDITOR.ypos", "13" }, { "custom_213", "RocksCE.pcx" }, { "custom_213.xpos", "4" }, { "custom_213.ypos", "13" }, { "custom_213.frames", "1" }, { "custom_213.EDITOR", "RocksCE.pcx" }, { "custom_213.EDITOR.xpos", "20" }, { "custom_213.EDITOR.ypos", "13" }, { "custom_214", "RocksCE.pcx" }, { "custom_214.xpos", "5" }, { "custom_214.ypos", "13" }, { "custom_214.frames", "1" }, { "custom_214.EDITOR", "RocksCE.pcx" }, { "custom_214.EDITOR.xpos", "21" }, { "custom_214.EDITOR.ypos", "13" }, { "custom_215", "RocksCE.pcx" }, { "custom_215.xpos", "6" }, { "custom_215.ypos", "13" }, { "custom_215.frames", "1" }, { "custom_215.EDITOR", "RocksCE.pcx" }, { "custom_215.EDITOR.xpos", "22" }, { "custom_215.EDITOR.ypos", "13" }, { "custom_216", "RocksCE.pcx" }, { "custom_216.xpos", "7" }, { "custom_216.ypos", "13" }, { "custom_216.frames", "1" }, { "custom_216.EDITOR", "RocksCE.pcx" }, { "custom_216.EDITOR.xpos", "23" }, { "custom_216.EDITOR.ypos", "13" }, { "custom_217", "RocksCE.pcx" }, { "custom_217.xpos", "8" }, { "custom_217.ypos", "13" }, { "custom_217.frames", "1" }, { "custom_217.EDITOR", "RocksCE.pcx" }, { "custom_217.EDITOR.xpos", "24" }, { "custom_217.EDITOR.ypos", "13" }, { "custom_218", "RocksCE.pcx" }, { "custom_218.xpos", "9" }, { "custom_218.ypos", "13" }, { "custom_218.frames", "1" }, { "custom_218.EDITOR", "RocksCE.pcx" }, { "custom_218.EDITOR.xpos", "25" }, { "custom_218.EDITOR.ypos", "13" }, { "custom_219", "RocksCE.pcx" }, { "custom_219.xpos", "10" }, { "custom_219.ypos", "13" }, { "custom_219.frames", "1" }, { "custom_219.EDITOR", "RocksCE.pcx" }, { "custom_219.EDITOR.xpos", "26" }, { "custom_219.EDITOR.ypos", "13" }, { "custom_220", "RocksCE.pcx" }, { "custom_220.xpos", "11" }, { "custom_220.ypos", "13" }, { "custom_220.frames", "1" }, { "custom_220.EDITOR", "RocksCE.pcx" }, { "custom_220.EDITOR.xpos", "27" }, { "custom_220.EDITOR.ypos", "13" }, { "custom_221", "RocksCE.pcx" }, { "custom_221.xpos", "12" }, { "custom_221.ypos", "13" }, { "custom_221.frames", "1" }, { "custom_221.EDITOR", "RocksCE.pcx" }, { "custom_221.EDITOR.xpos", "28" }, { "custom_221.EDITOR.ypos", "13" }, { "custom_222", "RocksCE.pcx" }, { "custom_222.xpos", "13" }, { "custom_222.ypos", "13" }, { "custom_222.frames", "1" }, { "custom_222.EDITOR", "RocksCE.pcx" }, { "custom_222.EDITOR.xpos", "29" }, { "custom_222.EDITOR.ypos", "13" }, { "custom_223", "RocksCE.pcx" }, { "custom_223.xpos", "14" }, { "custom_223.ypos", "13" }, { "custom_223.frames", "1" }, { "custom_223.EDITOR", "RocksCE.pcx" }, { "custom_223.EDITOR.xpos", "30" }, { "custom_223.EDITOR.ypos", "13" }, { "custom_224", "RocksCE.pcx" }, { "custom_224.xpos", "15" }, { "custom_224.ypos", "13" }, { "custom_224.frames", "1" }, { "custom_224.EDITOR", "RocksCE.pcx" }, { "custom_224.EDITOR.xpos", "31" }, { "custom_224.EDITOR.ypos", "13" }, { "custom_225", "RocksCE.pcx" }, { "custom_225.xpos", "0" }, { "custom_225.ypos", "14" }, { "custom_225.frames", "1" }, { "custom_225.EDITOR", "RocksCE.pcx" }, { "custom_225.EDITOR.xpos", "16" }, { "custom_225.EDITOR.ypos", "14" }, { "custom_226", "RocksCE.pcx" }, { "custom_226.xpos", "1" }, { "custom_226.ypos", "14" }, { "custom_226.frames", "1" }, { "custom_226.EDITOR", "RocksCE.pcx" }, { "custom_226.EDITOR.xpos", "17" }, { "custom_226.EDITOR.ypos", "14" }, { "custom_227", "RocksCE.pcx" }, { "custom_227.xpos", "2" }, { "custom_227.ypos", "14" }, { "custom_227.frames", "1" }, { "custom_227.EDITOR", "RocksCE.pcx" }, { "custom_227.EDITOR.xpos", "18" }, { "custom_227.EDITOR.ypos", "14" }, { "custom_228", "RocksCE.pcx" }, { "custom_228.xpos", "3" }, { "custom_228.ypos", "14" }, { "custom_228.frames", "1" }, { "custom_228.EDITOR", "RocksCE.pcx" }, { "custom_228.EDITOR.xpos", "19" }, { "custom_228.EDITOR.ypos", "14" }, { "custom_229", "RocksCE.pcx" }, { "custom_229.xpos", "4" }, { "custom_229.ypos", "14" }, { "custom_229.frames", "1" }, { "custom_229.EDITOR", "RocksCE.pcx" }, { "custom_229.EDITOR.xpos", "20" }, { "custom_229.EDITOR.ypos", "14" }, { "custom_230", "RocksCE.pcx" }, { "custom_230.xpos", "5" }, { "custom_230.ypos", "14" }, { "custom_230.frames", "1" }, { "custom_230.EDITOR", "RocksCE.pcx" }, { "custom_230.EDITOR.xpos", "21" }, { "custom_230.EDITOR.ypos", "14" }, { "custom_231", "RocksCE.pcx" }, { "custom_231.xpos", "6" }, { "custom_231.ypos", "14" }, { "custom_231.frames", "1" }, { "custom_231.EDITOR", "RocksCE.pcx" }, { "custom_231.EDITOR.xpos", "22" }, { "custom_231.EDITOR.ypos", "14" }, { "custom_232", "RocksCE.pcx" }, { "custom_232.xpos", "7" }, { "custom_232.ypos", "14" }, { "custom_232.frames", "1" }, { "custom_232.EDITOR", "RocksCE.pcx" }, { "custom_232.EDITOR.xpos", "23" }, { "custom_232.EDITOR.ypos", "14" }, { "custom_233", "RocksCE.pcx" }, { "custom_233.xpos", "8" }, { "custom_233.ypos", "14" }, { "custom_233.frames", "1" }, { "custom_233.EDITOR", "RocksCE.pcx" }, { "custom_233.EDITOR.xpos", "24" }, { "custom_233.EDITOR.ypos", "14" }, { "custom_234", "RocksCE.pcx" }, { "custom_234.xpos", "9" }, { "custom_234.ypos", "14" }, { "custom_234.frames", "1" }, { "custom_234.EDITOR", "RocksCE.pcx" }, { "custom_234.EDITOR.xpos", "25" }, { "custom_234.EDITOR.ypos", "14" }, { "custom_235", "RocksCE.pcx" }, { "custom_235.xpos", "10" }, { "custom_235.ypos", "14" }, { "custom_235.frames", "1" }, { "custom_235.EDITOR", "RocksCE.pcx" }, { "custom_235.EDITOR.xpos", "26" }, { "custom_235.EDITOR.ypos", "14" }, { "custom_236", "RocksCE.pcx" }, { "custom_236.xpos", "11" }, { "custom_236.ypos", "14" }, { "custom_236.frames", "1" }, { "custom_236.EDITOR", "RocksCE.pcx" }, { "custom_236.EDITOR.xpos", "27" }, { "custom_236.EDITOR.ypos", "14" }, { "custom_237", "RocksCE.pcx" }, { "custom_237.xpos", "12" }, { "custom_237.ypos", "14" }, { "custom_237.frames", "1" }, { "custom_237.EDITOR", "RocksCE.pcx" }, { "custom_237.EDITOR.xpos", "28" }, { "custom_237.EDITOR.ypos", "14" }, { "custom_238", "RocksCE.pcx" }, { "custom_238.xpos", "13" }, { "custom_238.ypos", "14" }, { "custom_238.frames", "1" }, { "custom_238.EDITOR", "RocksCE.pcx" }, { "custom_238.EDITOR.xpos", "29" }, { "custom_238.EDITOR.ypos", "14" }, { "custom_239", "RocksCE.pcx" }, { "custom_239.xpos", "14" }, { "custom_239.ypos", "14" }, { "custom_239.frames", "1" }, { "custom_239.EDITOR", "RocksCE.pcx" }, { "custom_239.EDITOR.xpos", "30" }, { "custom_239.EDITOR.ypos", "14" }, { "custom_240", "RocksCE.pcx" }, { "custom_240.xpos", "15" }, { "custom_240.ypos", "14" }, { "custom_240.frames", "1" }, { "custom_240.EDITOR", "RocksCE.pcx" }, { "custom_240.EDITOR.xpos", "31" }, { "custom_240.EDITOR.ypos", "14" }, { "custom_241", "RocksCE.pcx" }, { "custom_241.xpos", "0" }, { "custom_241.ypos", "15" }, { "custom_241.frames", "1" }, { "custom_241.EDITOR", "RocksCE.pcx" }, { "custom_241.EDITOR.xpos", "16" }, { "custom_241.EDITOR.ypos", "15" }, { "custom_242", "RocksCE.pcx" }, { "custom_242.xpos", "1" }, { "custom_242.ypos", "15" }, { "custom_242.frames", "1" }, { "custom_242.EDITOR", "RocksCE.pcx" }, { "custom_242.EDITOR.xpos", "17" }, { "custom_242.EDITOR.ypos", "15" }, { "custom_243", "RocksCE.pcx" }, { "custom_243.xpos", "2" }, { "custom_243.ypos", "15" }, { "custom_243.frames", "1" }, { "custom_243.EDITOR", "RocksCE.pcx" }, { "custom_243.EDITOR.xpos", "18" }, { "custom_243.EDITOR.ypos", "15" }, { "custom_244", "RocksCE.pcx" }, { "custom_244.xpos", "3" }, { "custom_244.ypos", "15" }, { "custom_244.frames", "1" }, { "custom_244.EDITOR", "RocksCE.pcx" }, { "custom_244.EDITOR.xpos", "19" }, { "custom_244.EDITOR.ypos", "15" }, { "custom_245", "RocksCE.pcx" }, { "custom_245.xpos", "4" }, { "custom_245.ypos", "15" }, { "custom_245.frames", "1" }, { "custom_245.EDITOR", "RocksCE.pcx" }, { "custom_245.EDITOR.xpos", "20" }, { "custom_245.EDITOR.ypos", "15" }, { "custom_246", "RocksCE.pcx" }, { "custom_246.xpos", "5" }, { "custom_246.ypos", "15" }, { "custom_246.frames", "1" }, { "custom_246.EDITOR", "RocksCE.pcx" }, { "custom_246.EDITOR.xpos", "21" }, { "custom_246.EDITOR.ypos", "15" }, { "custom_247", "RocksCE.pcx" }, { "custom_247.xpos", "6" }, { "custom_247.ypos", "15" }, { "custom_247.frames", "1" }, { "custom_247.EDITOR", "RocksCE.pcx" }, { "custom_247.EDITOR.xpos", "22" }, { "custom_247.EDITOR.ypos", "15" }, { "custom_248", "RocksCE.pcx" }, { "custom_248.xpos", "7" }, { "custom_248.ypos", "15" }, { "custom_248.frames", "1" }, { "custom_248.EDITOR", "RocksCE.pcx" }, { "custom_248.EDITOR.xpos", "23" }, { "custom_248.EDITOR.ypos", "15" }, { "custom_249", "RocksCE.pcx" }, { "custom_249.xpos", "8" }, { "custom_249.ypos", "15" }, { "custom_249.frames", "1" }, { "custom_249.EDITOR", "RocksCE.pcx" }, { "custom_249.EDITOR.xpos", "24" }, { "custom_249.EDITOR.ypos", "15" }, { "custom_250", "RocksCE.pcx" }, { "custom_250.xpos", "9" }, { "custom_250.ypos", "15" }, { "custom_250.frames", "1" }, { "custom_250.EDITOR", "RocksCE.pcx" }, { "custom_250.EDITOR.xpos", "25" }, { "custom_250.EDITOR.ypos", "15" }, { "custom_251", "RocksCE.pcx" }, { "custom_251.xpos", "10" }, { "custom_251.ypos", "15" }, { "custom_251.frames", "1" }, { "custom_251.EDITOR", "RocksCE.pcx" }, { "custom_251.EDITOR.xpos", "26" }, { "custom_251.EDITOR.ypos", "15" }, { "custom_252", "RocksCE.pcx" }, { "custom_252.xpos", "11" }, { "custom_252.ypos", "15" }, { "custom_252.frames", "1" }, { "custom_252.EDITOR", "RocksCE.pcx" }, { "custom_252.EDITOR.xpos", "27" }, { "custom_252.EDITOR.ypos", "15" }, { "custom_253", "RocksCE.pcx" }, { "custom_253.xpos", "12" }, { "custom_253.ypos", "15" }, { "custom_253.frames", "1" }, { "custom_253.EDITOR", "RocksCE.pcx" }, { "custom_253.EDITOR.xpos", "28" }, { "custom_253.EDITOR.ypos", "15" }, { "custom_254", "RocksCE.pcx" }, { "custom_254.xpos", "13" }, { "custom_254.ypos", "15" }, { "custom_254.frames", "1" }, { "custom_254.EDITOR", "RocksCE.pcx" }, { "custom_254.EDITOR.xpos", "29" }, { "custom_254.EDITOR.ypos", "15" }, { "custom_255", "RocksCE.pcx" }, { "custom_255.xpos", "14" }, { "custom_255.ypos", "15" }, { "custom_255.frames", "1" }, { "custom_255.EDITOR", "RocksCE.pcx" }, { "custom_255.EDITOR.xpos", "30" }, { "custom_255.EDITOR.ypos", "15" }, { "custom_256", "RocksCE.pcx" }, { "custom_256.xpos", "15" }, { "custom_256.ypos", "15" }, { "custom_256.frames", "1" }, { "custom_256.EDITOR", "RocksCE.pcx" }, { "custom_256.EDITOR.xpos", "31" }, { "custom_256.EDITOR.ypos", "15" }, #endif /* CONF_CUS_C */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/0000755000175000017500000000000011403523060017022 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Display.h0000644000175000017500000000114111362674776020626 0ustar dimkadimka// ---------------------------------------------------------------------------- // Display.h // ---------------------------------------------------------------------------- #ifndef DISPLAY_H #define DISPLAY_H #include "global.h" extern int ScreenScrollXPos, ScreenScrollYPos; extern int ExplosionShake, ExplosionShakeMurphy; extern boolean NoDisplayFlag; extern long DisplayMinX, DisplayMaxX; extern long DisplayMinY, DisplayMaxY; extern void subDisplayLevel(); extern void ScrollTo(int, int); extern void ScrollTowards(int, int); extern void SoftScrollTo(int, int, long, int); #endif /* DISPLAY_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Globals.c0000644000175000017500000001034611375770741020577 0ustar dimkadimka// ---------------------------------------------------------------------------- // Globals.c // ---------------------------------------------------------------------------- #include "Globals.h" boolean LevelLoaded; boolean DemoAvailable; boolean menBorder; int FieldWidth; // standard size = 60 int FieldHeight; // standard size = 24 int HeaderSize; // standard size = 96 int FieldMax, LevelMax; long FileMax; #if 1 int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; #else int *PlayField16; byte *PlayField8; byte *DisPlayField; #endif int TimerVar; #if 1 short RandomSeed; #else int RandomSeed; #endif int FreezeZonks; LevelInfoType LInfo; int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY; int ScrollX, ScrollY; int MurphyPosIndex, MurphyXPos, MurphyYPos; int MurphyScreenXPos, MurphyScreenYPos; int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos; int KillMurphyFlag, MurphyMoveCounter; long YawnSleepCounter; int MurphyVarFaceLeft; int ScratchGravity, GravityFlag; int RedDiskReleaseFlag, MovingPictureSequencePhase; int YellowDisksExploded; int AllowRedDiskCheat, AllowEatRightRedDiskBug; int GameBusyFlag; int InfotronsNeeded, TotalInfotronsNeeded; int RedDiskCount; int SnikSnaksElectronsFrozen; int DemoKeyCode; int RedDiskReleasePhase; int fiGraphic[] = { aniSpace, aniZonk, aniBase, aniMurphy, aniInfotron, aniRAM, aniHardWare, aniExit, aniOrangeDisk, aniPortRight, aniPortDown, aniPortLeft, aniPortUp, aniSpPortRight, aniSpPortDown, aniSpPortLeft, aniSpPortUp, aniSnikSnak, aniYellowDisk, aniTerminal, aniRedDisk, aniPortUpAndDown, aniPortLeftAndRight, aniPortAllDirections, aniElectron, aniBug, aniRAMLeft, aniRAMRight, aniHW0, aniHW1, aniHW2, aniHW3, aniHW4, aniHW5, aniHW6, aniHW7, aniHW8, aniHW9, aniRAMTop, aniRAMBottom, aniWallSpace }; int aniSnikSnakTurningLeft[] = { aniSnikSnakTurnUpToLeft, aniSnikSnakTurnLeftToDown, aniSnikSnakTurnDownToRight, aniSnikSnakTurnRightToUp }; int aniSnikSnakTurningRight[] = { aniSnikSnakTurnUpToRight, aniSnikSnakTurnRightToDown, aniSnikSnakTurnDownToLeft, aniSnikSnakTurnLeftToUp }; int getSequenceLength(int sequence) { switch (sequence) { case aniBug: return 14; case aniElectron: case aniExplosion: return 9; case aniTouchInfotron: return 7; case aniMurphyExit: return 40; case aniRedDisk: return 1; default: return 8; } } boolean isSnappingSequence(int sequence) { switch (sequence) { case aniTouchBase: case aniTouchInfotron: case aniTouchRedDisk: return TRUE; default: return FALSE; } } void InitGlobals() { AutoScrollFlag = True; FreezeZonks = 0; LevelLoaded = False; FieldWidth = 60; FieldHeight = 24; HeaderSize = 96; FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; bPlaying = False; menBorder = False; #if 0 /* these defaults will be changed after reading a Supaplex level file */ PlayField8 = REDIM_1D(sizeof(byte), 0, FieldMax); DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax); PlayField16 = REDIM_1D(sizeof(int), 0, FieldMax); AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax); AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax); TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax); #endif } int GetSI(int X, int Y) { return Y * FieldWidth + X; } int GetX(int si) { return si % FieldWidth; } int GetY(int si) { return si / FieldWidth; } int GetStretchX(int si) { return StretchWidth * (si % FieldWidth); } int GetStretchY(int si) { return StretchWidth * (si / FieldWidth); } void PrepareLevel() { copyInternalEngineVars_SP(); #if 1 SetDisplayRegion(); SetScrollEdges(); #endif LevelLoaded = True; } #if 0 void Trace(char *Source, char *Message) { printf("::: Trace: Source == '%s', Message == '%s'\n", Source, Message); } void ReportError(char *Source, char *Message) { printf("::: ReportError: Source == '%s', Message == '%s'\n", Source, Message); } #endif int Min(int A, int B) { return (A < B ? A : B); } int Max(int A, int B) { return (A < B ? B : A); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/ASM.c0000644000175000017500000000104711347256770017632 0ustar dimkadimka// ---------------------------------------------------------------------------- // ASM.c // ---------------------------------------------------------------------------- #include "ASM.h" void MovLowByte(int *p, int i) { *p = (*p & 0xff00) | (i & 0xff); } void MovHighByte(int *p, int i) { *p = (*p & 0xff) | ((i << 8) & 0xff00); } int LowByte(int i) { return (i & 0xff); } int HighByte(int i) { return ((i >> 8) & 0xff); } int SgnHighByte(int i) { return (signed char)HighByte(i); } int ByteToInt(byte b) { return (signed char)b; } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Display.c0000644000175000017500000000254611362675006020616 0ustar dimkadimka// ---------------------------------------------------------------------------- // Display.c // ---------------------------------------------------------------------------- #include "Display.h" int ScreenScrollXPos, ScreenScrollYPos; int ExplosionShake, ExplosionShakeMurphy; boolean NoDisplayFlag; long DisplayMinX, DisplayMaxX; long DisplayMinY, DisplayMaxY; void subDisplayLevel() { if (NoDisplayFlag || ! LevelLoaded) return; DisplayLevel(); } void ScrollTo(int X, int Y) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_ScrollTo(X, Y); } void ScrollTowards(int X, int Y) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_ScrollTowards(X, Y, 2 * ZoomFactor); } void SoftScrollTo(int X, int Y, long TimeMS, int FPS) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_SoftScrollTo(X, Y, TimeMS, FPS); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Sound.c0000644000175000017500000000051311347517300020264 0ustar dimkadimka// ---------------------------------------------------------------------------- // Sound.c // ---------------------------------------------------------------------------- #include "Sound.h" void subSoundFX(int si, int element, int action) { int x = GetX(si); int y = GetY(si); PlayLevelSound_SP(x, y, element, action); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/MainGameLoop.c0000644000175000017500000000674711375601317021526 0ustar dimkadimka// ---------------------------------------------------------------------------- // MainGameLoop.c // ---------------------------------------------------------------------------- #include "MainGameLoop.h" boolean bPlaying; int LeadOutCounter; int ExitToMenuFlag; boolean AutoScrollFlag; // ========================================================================== // SUBROUTINE // Play a game/demo // ========================================================================== void subMainGameLoop_Init() { // This was a bug in the original Supaplex: sometimes red disks could not // be released. This happened if Murphy was killed DURING a red disk release // and the next try started. RedDiskReleasePhase = 0; // (re-)enable red disk release } void subMainGameLoop_Main(byte action, boolean warp_mode) { // --------------------------------------------------------------------------- // --------------------- START OF GAME-BUSY LOOP ----------------------------- // --------------------------------------------------------------------------- subProcessKeyboardInput(action); // check keyboard, act on keys // --------------------------------------------------------------------------- // subDoGameStuff(); // do all game stuff // // --------------------------------------------------------------------------- subRedDiskReleaseExplosion(); // Red Disk release and explode subFollowUpExplosions(); // every explosion may cause up to 8 following explosions subCalculateScreenScrollPos(); // calculate screen start addrs if (AutoScrollFlag) ScrollTowards(ScreenScrollXPos, ScreenScrollYPos); TimerVar = TimerVar + 1; #if 1 if (ExplosionShakeMurphy > 0) ExplosionShakeMurphy--; #endif #if 1 if (ExitToMenuFlag == 1) { // happens when demo ends or when Murphy enters exit (to be checked) #if 0 goto locExitMainGameLoop; #endif } #else if (ExitToMenuFlag == 1) goto locExitMainGameLoop; #endif if (LeadOutCounter == 0) // no lead-out: game busy return; // --------------------------------------------------------------------------- // ---------------------- END OF GAME-BUSY LOOP ------------------------------ // --------------------------------------------------------------------------- LeadOutCounter = LeadOutCounter - 1; // do more lead-out after quit if (LeadOutCounter != 0) // lead-out not ready: more return; // lead-out done: exit now // ---------------------- END OF GAME-BUSY LOOP (including lead-out) --------- #if 0 locExitMainGameLoop: #endif #if 0 printf("::: locExitMainGameLoop reached [%d]\n", LeadOutCounter); printf("::: [KillMurphyFlag == %d]\n", KillMurphyFlag); #endif #if 1 /* if the game is not won when reaching this point, then it is lost */ if (!game_sp.LevelSolved) game_sp.GameOver = TRUE; #endif } void subCalculateScreenScrollPos() { #if 1 int jump_pos = TILEX / 2; /* handle wrap-around */ if (MurphyScreenXPos < -jump_pos) { MurphyScreenXPos = FieldWidth * TILEX + MurphyScreenXPos; MurphyScreenYPos -= TILEY; } else if (MurphyScreenXPos >= FieldWidth * TILEX - jump_pos) { MurphyScreenXPos = MurphyScreenXPos - FieldWidth * TILEX; MurphyScreenYPos += TILEY; } #endif if (ExplosionShake != 0) { subGetRandomNumber(); // printf("::: ExplosionShake [%d]\n", FrameCounter); } ScreenScrollXPos = MurphyScreenXPos - (SCR_FIELDX / 2) * TILESIZE; ScreenScrollYPos = MurphyScreenYPos - (SCR_FIELDY / 2) * TILESIZE; } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/SnikSnaks.c0000644000175000017500000003562011347530431021107 0ustar dimkadimka// ---------------------------------------------------------------------------- // SnikSnaks.c // ---------------------------------------------------------------------------- #include "SnikSnaks.h" static void subDrawSnikSnakFromAbove(int, int); static void subDrawSnikSnakFromBelow(int, int); static void subDrawSnikSnakFromLeft(int, int); static void subDrawSnikSnakFromRight(int, int); static void subDrawSnikSnakTurnLeft(int, int); static void subDrawSnikSnakTurnRight(int, int); static void subSnikSnakFromAbove(int, int); static void subSnikSnakFromBelow(int, int); static void subSnikSnakFromLeft(int, int); static void subSnikSnakFromRight(int, int); static void subSnikSnakTurnLeft(int, int); static void subSnikSnakTurnRight(int, int); // static char *VB_Name = "modSnikSnak"; // --- Option Explicit // ========================================================================== // SUBROUTINE // Animate/move Snik-Snaks // ========================================================================== void subAnimateSnikSnaks(int si) { int bx, Tmp; if (SnikSnaksElectronsFrozen == 1) return; #if 1 /* (not sure why this was removed -- this broke several level solutions) */ if (LowByte(PlayField16[si]) != fiSnikSnak) return; #endif // If LowByte(PlayField16(si)) <> fiSnikSnak Then Exit Function // Debug.Assert (LowByte(PlayField16[si]) == fiSnikSnak); bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subSnikSnakTurnRight(si, bx); // turn right break; case 2: subSnikSnakFromBelow(si, bx); // access si from below break; case 3: subSnikSnakFromRight(si, bx); // access si from right break; case 4: subSnikSnakFromAbove(si, bx); // access si from above break; case 5: subSnikSnakFromLeft(si, bx); // access si from left break; default: // Debug.Assert(False); break; } } void subDrawAnimatedSnikSnaks(int si) { int bx, Tmp; // If SnikSnaksElectronsFrozen = 1 Then Exit Function if (LowByte(PlayField16[si]) != fiSnikSnak) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subDrawSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subDrawSnikSnakTurnRight(si, bx); // turn right break; case 2: subDrawSnikSnakFromBelow(si, bx); // access si from below break; case 3: subDrawSnikSnakFromRight(si, bx); // access si from right break; case 4: subDrawSnikSnakFromAbove(si, bx); // access si from above break; case 5: subDrawSnikSnakFromLeft(si, bx); // access si from left break; } } static void subSnikSnakTurnLeft(int si, int bx) { int ax, ah, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7622; return; } // loc_g_75E0: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakTurnLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = (bx + 1) & 0x7; MovHighByte(&PlayField16[si], bx); return; locMayExplode760A: ah = HighByte(ax); if (ah == 0x1B) return; if (ah == 0x19) return; if (ah == 0x18) return; if (ah == 0x1A) return; ExplodeFieldSP(si); // Explode return; loc_g_7622: bl = HighByte(PlayField16[si]); if (bl == 0) goto loc_g_763B; if (bl == 2) goto loc_g_765E; if (bl == 4) goto loc_g_7681; if (bl == 6) goto loc_g_76A7; return; loc_g_763B: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_764E; if (LowByte(ax) == fiMurphy) // above is murphy -> explode goto locMayExplode760A; return; loc_g_764E: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; PlayField16[si] = 0x1011; return; loc_g_765E: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7671; if (LowByte(ax) == fiMurphy) // left is murphy -> explode goto locMayExplode760A; return; loc_g_7671: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; PlayField16[si] = 0x1811; return; loc_g_7681: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7697; if (LowByte(ax) == fiMurphy) // below is murphy -> explode goto locMayExplode760A; return; loc_g_7697: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; PlayField16[si] = 0x2011; return; loc_g_76A7: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_76BD; if (LowByte(ax) == fiMurphy) // right is murphy -> explode goto locMayExplode760A; return; loc_g_76BD: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; PlayField16[si] = 0x2811; } static void subSnikSnakTurnRight(int si, int bx) { int ax, ah, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_771F; return; } // loc_g_76DB: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakTurnRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = ((bx + 1) & 0x7) | 8; MovHighByte(&PlayField16[si], bx); return; locMayExplode7707: ah = HighByte(ax); if (ah == 0x1B) return; if (ah == 0x19) return; if (ah == 0x18) return; if (ah == 0x1A) return; ExplodeFieldSP(si); // Explode return; loc_g_771F: bl = HighByte(PlayField16[si]); if (bl == 0x8) goto loc_g_7738; if (bl == 0xA) goto loc_g_77A4; if (bl == 0xC) goto loc_g_777E; if (bl == 0xE) goto loc_g_775B; return; loc_g_7738: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_774B; if (LowByte(ax) == fiMurphy) // above is murphy -> explode goto locMayExplode7707; return; loc_g_774B: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; PlayField16[si] = 0x1011; return; loc_g_775B: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_776E; if (LowByte(ax) == fiMurphy) // left is murphy -> explode goto locMayExplode7707; return; loc_g_776E: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; PlayField16[si] = 0x1811; return; loc_g_777E: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7794; if (LowByte(ax) == fiMurphy) // below is murphy -> explode goto locMayExplode7707; return; loc_g_7794: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; PlayField16[si] = 0x2011; return; loc_g_77A4: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_77BA; if (LowByte(ax) == fiMurphy) // right is murphy -> explode goto locMayExplode7707; return; loc_g_77BA: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; PlayField16[si] = 0x2811; } static void subSnikSnakFromBelow(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromBelow(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0xF; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion) { PlayField16[si + FieldWidth] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes up { bl = bl + 0x10; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7813 PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si - 1]; // check left field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 1); // start to turn left return; } // loc_g_7826: and 'loc_g_7833: ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above if (ax == 0) // check if empty { PlayField16[si] = 0x1BB; // mark as "sniksnak leaving" si = si - FieldWidth; // go up! PlayField16[si] = 0x1011; return; } // loc_g_784A: if (LowByte(ax) == fiMurphy) // check for murphy above { ExplodeFieldSP(si); // Explode return; } // loc_g_7855: ax = PlayField16[si + 1]; // check right field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 9); // start to turn right return; } // loc_g_7862: and 'loc_g_786F: // else: no way to go, start turning around MovHighByte(&PlayField16[si], 1); } static void subSnikSnakFromRight(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x17; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion) { PlayField16[si + 1] = 0; // sniknak left that field } // loc_g_78AC: if (bl < 8) // sniksnak still goes left { bl = bl + 0x18; MovHighByte(&PlayField16[si], bl); return; } // loc_g_78B9: PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy? { MovHighByte(&PlayField16[si], 3); // yes -> turn left down return; } // loc_g_78CC: and 'loc_g_78D9: ax = PlayField16[si - 1]; // check left, etc ... see the comments on subSnikSnakFromBelow() if (ax == 0) { PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1811; return; } // loc_g_78F0: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_78FB: ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xF); return; } // loc_g_7908:loc_g_7915: MovHighByte(&PlayField16[si], 3); } static void subSnikSnakFromAbove(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromAbove(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x1F; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion) { PlayField16[si - FieldWidth] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes down { bl = bl + 0x20; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7813 PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si + 1]; // check right if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 5); return; } // loc_g_7986: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0) { PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2011; return; } // loc_g_799D: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_79A8: ax = PlayField16[si - 1]; // check left if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xD); return; } // loc_g_79C2: MovHighByte(&PlayField16[si], 5); } static void subSnikSnakFromLeft(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x27; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion) { PlayField16[si - 1] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes right { bl = bl + 0x28; MovHighByte(&PlayField16[si], bl); return; } // loc_g_78B9: PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 7); return; } // loc_g_7A2D: ax = PlayField16[si + 1]; // check right(straight on) if (ax == 0) { PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2811; return; } // loc_g_7A44: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7A4F: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xB); return; } // loc_g_7A69: MovHighByte(&PlayField16[si], 7); } static void subDrawSnikSnakTurnLeft(int si, int bx) { int pos = ((bx + 7) % 8) / 2; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningLeft[pos]; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakTurnRight(int si, int bx) { int pos = ((bx - 1) % 8) / 2; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningRight[pos]; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromBelow(int si, int bx) { int X, Y; bx = bx - 0xF; // get and anti-increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si + FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y - bx * TwoPixels, aniSnikSnakUp, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromRight(int si, int bx) { int X, Y; bx = bx - 0x17; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - bx * TwoPixels, Y, aniSnikSnakLeft, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromAbove(int si, int bx) { int X, Y; bx = bx - 0x1F; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + bx * TwoPixels, aniSnikSnakDown, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromLeft(int si, int bx) { int X, Y; bx = bx - 0x27; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + bx * TwoPixels, Y, aniSnikSnakRight, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Infotrons.h0000644000175000017500000000053511347526054021174 0ustar dimkadimka// ---------------------------------------------------------------------------- // Infotrons.h // ---------------------------------------------------------------------------- #ifndef INFOTRONS_H #define INFOTRONS_H #include "global.h" extern void subAnimateInfotrons(int); extern void subCleanUpForInfotronsAbove(int); #endif /* INFOTRONS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Electrons.h0000644000175000017500000000157611347525777021172 0ustar dimkadimka// ---------------------------------------------------------------------------- // Electrons.h // ---------------------------------------------------------------------------- #ifndef ELECTRONS_H #define ELECTRONS_H #include "global.h" extern void subAnimateElectrons(int); extern void subDrawAnimatedElectrons(int); extern void subDrawElectronFromAbove(int, int); extern void subDrawElectronFromBelow(int, int); extern void subDrawElectronFromLeft(int, int); extern void subDrawElectronFromRight(int, int); extern void subDrawElectronTurnLeft(int, int); extern void subDrawElectronTurnRight(int, int); extern void subElectronFromAbove(int, int); extern void subElectronFromBelow(int, int); extern void subElectronFromLeft(int, int); extern void subElectronFromRight(int, int); extern void subElectronTurnLeft(int, int); extern void subElectronTurnRight(int, int); #endif /* ELECTRONS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/BugsTerminals.c0000644000175000017500000001040611375770350021764 0ustar dimkadimka// ---------------------------------------------------------------------------- // BugsTerminals.c // ---------------------------------------------------------------------------- #include "BugsTerminals.h" #if 1 byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; #else byte *TerminalState; #endif int TerminalMaxCycles; // ========================================================================== // SUBROUTINE // Animate bugs // ========================================================================== void subAnimateBugs(int si) { int bl; if (fiBug != LowByte(PlayField16[si])) return; bl = SgnHighByte(PlayField16[si]); // get and increment sequence number if ((TimerVar & 3) == 0) { bl = bl + 1; if (bl >= 14) // bugs animation has 14 frames { bl = subGetRandomNumber(); // generate new random number bl = -((bl & 0x3F) + 0x20); } MovHighByte(&PlayField16[si], bl); // save sequence number } if (bl < 0) // bug sleeps / is inactive return; // now the bug is active! Beware Murphy! if ((TimerVar & 3) == 0 && (LowByte(PlayField16[si - FieldWidth - 1]) == fiMurphy || LowByte(PlayField16[si - FieldWidth]) == fiMurphy || LowByte(PlayField16[si - FieldWidth + 1]) == fiMurphy || LowByte(PlayField16[si - 1]) == fiMurphy || LowByte(PlayField16[si + 1]) == fiMurphy || LowByte(PlayField16[si + FieldWidth - 1]) == fiMurphy || LowByte(PlayField16[si + FieldWidth]) == fiMurphy || LowByte(PlayField16[si + FieldWidth + 1]) == fiMurphy)) subSoundFX(si, fiBug, actActive); // play dangerous sound // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = (bl == 0 ? aniBugActivating : bl == 12 ? aniBugDeactivating : bl == 13 ? aniBug : aniBugActive); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Animate terminals // ========================================================================== void subAnimateTerminals(int si) { int bl; int lx = GetX(si); int ly = GetY(si); int graphic; if (LowByte(PlayField16[si]) != fiTerminal) return; /* use native frame handling (undo frame incrementation in main loop) */ if (game.use_native_sp_graphics_engine) GfxFrame[lx][ly]--; /* get last random animation delay */ bl = SgnHighByte(PlayField16[si]); bl = bl + 1; if (bl <= 0) /* return if random animation delay not yet reached */ { MovHighByte(&PlayField16[si], bl); return; } /* calculate new random animation delay */ bl = -(subGetRandomNumber() & TerminalMaxCycles); // generate new random number MovHighByte(&PlayField16[si], bl); // save new sequence number /* check terminal state (active or inactive) */ bl = TerminalState[si] + 1; if (bl == 8) bl = 0; else if (15 < bl) bl = 8; TerminalState[si] = bl; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ graphic = (bl < 8 ? aniTerminal : aniTerminalActive); if (game.use_native_sp_graphics_engine) GfxFrame[lx][ly] += getGraphicInfo_Delay(graphic); GfxGraphic[lx][ly] = (bl < 8 ? aniTerminal : aniTerminalActive); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Randomize random number generator // ========================================================================== void subRandomize() { long Tick = MyGetTickCount(); RandomSeed = (Tick ^ (Tick >> 16)) & 0xFFFF; } // ========================================================================== // SUBROUTINE // Generate new random number, first method (see also sub_g_8580) // ========================================================================== int subGetRandomNumber() { RandomSeed = (RandomSeed * 0x5E5 + 0x31) & 0xFFFF; return (RandomSeed >> 1); // Mov ax, randomseed // Mov bx, &H5E5 // mul bx ' dx:ax = reg * ax // Add ax, &H31 // Mov randomseed, ax // shr ax,1 } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/MainGameLoop.h0000644000175000017500000000100411350003072021473 0ustar dimkadimka// ---------------------------------------------------------------------------- // MainGameLoop.h // ---------------------------------------------------------------------------- #ifndef MAINGAMELOOP_H #define MAINGAMELOOP_H #include "global.h" extern boolean AutoScrollFlag; extern boolean bPlaying; extern int ExitToMenuFlag; extern int LeadOutCounter; extern void subMainGameLoop_Init(); extern void subMainGameLoop_Main(byte, boolean); extern void subCalculateScreenScrollPos(); #endif /* MAINGAMELOOP_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/InitGameConditions.h0000644000175000017500000000111411347543216022733 0ustar dimkadimka// ---------------------------------------------------------------------------- // InitGameConditions.h // ---------------------------------------------------------------------------- #ifndef INITGAMECONDITIONS_H #define INITGAMECONDITIONS_H #include "global.h" extern int subConvertToEasySymbols(); extern void InitMurphyPos(); extern void InitMurphyPosB(int); extern void ResetInfotronsNeeded(int); extern void subFetchAndInitLevel(); extern void subFetchAndInitLevelA(); extern void subFetchAndInitLevelB(); extern void subInitGameConditions(); #endif /* INITGAMECONDITIONS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Murphy.h0000644000175000017500000000105111350000371020450 0ustar dimkadimka// ---------------------------------------------------------------------------- // Murphy.h // ---------------------------------------------------------------------------- #ifndef MURPHY_H #define MURPHY_H #include "global.h" extern void subAdjustZonksInfotronsAboveMurphy(int); extern void subAnimateMurphy(int *); extern void subCopyFieldToScreen(int, int); extern void subCopyImageToScreen(int, int); extern void subCopyAnimToScreen(int, int, int); extern void subExplodeSnikSnaksBelow(int); extern void subSpPortTest(int); #endif /* MURPHY_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/InitGameConditions.c0000644000175000017500000001600711362675035022737 0ustar dimkadimka// ---------------------------------------------------------------------------- // InitGameConditions.c // ---------------------------------------------------------------------------- #include "InitGameConditions.h" // ========================================================================== // SUBROUTINE // Init game conditions (variables) // ========================================================================== void subInitGameConditions() { MurphyVarFaceLeft = 0; KillMurphyFlag = 0; // no "kill Murphy" ExitToMenuFlag = 0; LeadOutCounter = 0; // quit flag: lead-out counter RedDiskCount = 0; // Red disk counter YawnSleepCounter = 0; // Wake up sleeping Murphy ExplosionShake = 0; // Force explosion flag off ExplosionShakeMurphy = 0; // Force explosion flag off TerminalMaxCycles = 0x7F; YellowDisksExploded = 0; TimerVar = 0; SnikSnaksElectronsFrozen = 0; // Snik-Snaks and Electrons move! SplitMoveFlag = 0; // Reset Split-through-ports RedDiskReleasePhase = 0; // (re-)enable red disk release RedDiskReleaseMurphyPos = 0; // Red disk was released here } // ========================================================================== // SUBROUTINE // Locate Murphy and init location. // ========================================================================== void InitMurphyPos() { int si; for (si = 0; si < LevelMax; si++) if (PlayField16[si] == fiMurphy) break; InitMurphyPosB(si); MurphyPosIndex = si; } void InitMurphyPosB(int si) { MurphyScreenXPos = MurphyXPos = GetStretchX(si); // Murphy's screen x-position MurphyScreenYPos = MurphyYPos = GetStretchY(si); // Murphy's screen y-position // To Do: draw Murphy in location ax DDSpriteBuffer_BltImg(MurphyScreenXPos, MurphyScreenYPos, aniMurphy, 0); subCalculateScreenScrollPos(); // calculate screen start addrs if (AutoScrollFlag) { if (bPlaying) SoftScrollTo(ScreenScrollXPos, ScreenScrollYPos, 1000, 25); else ScrollTo(ScreenScrollXPos, ScreenScrollYPos); } } // ========================================================================== // SUBROUTINE // Convert to easy symbols and reset Infotron count If not ThenVer62 // ========================================================================== int subConvertToEasySymbols() { int ax, bx, cx, dx, i; int al; bx = 0; dx = 0; cx = LevelMax + 1; i = 0; loc_g_26C9: ax = PlayField16[i]; al = LowByte(ax); if (al == 0xF1) // converted explosion? { MovLowByte(&PlayField16[i], 0x1F); // restore explosions goto loc_g_2778; } if (LowByte(GameBusyFlag) != 1) // free screen write? { if (ax == fiInfotron) // Infotron? -> yes--count! goto loc_g_2704; if (ax == fiSnikSnak) // Snik Snak? -> yes--rearrange goto loc_g_2713; if (ax == fiElectron) // Electron? -> yes--rearrange goto loc_g_2741; } // test for fancy RAM Chips: if (ax == fiRAMLeft || ax == fiRAMRight) goto loc_g_2707; if (ax == fiRAMTop || ax == fiRAMBottom) goto loc_g_2707; if (ax < fiHWFirst) // All but deco hardware? goto loc_g_26F8; if (ax < fiRAMTop) // Decorative hardware? goto loc_g_270D; loc_g_26F8: if (ax < fiSpPortRight) // Gravity change ports only? goto loc_g_2778; if (ax < fiSnikSnak) // Gravity change port! 'loc_g_2702: goto loc_g_276F; goto loc_g_2778; loc_g_2704: // INFOTRON dx = dx + 1; // Count Infotrons goto loc_g_2778; loc_g_2707: // DECO RAM CHIPS PlayField16[i] = fiRAM; // Convert to standard RAM chip goto loc_g_2778; loc_g_270D: // DECO HARDWARE PlayField16[i] = fiHardWare; // Convert to standard hardware goto loc_g_2778; loc_g_2713: // SNIK-SNAK if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up goto loc_g_271F; MovHighByte(&PlayField16[i], 1); // turn left, step = NorthWest goto loc_g_2778; loc_g_271F: if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right goto loc_g_2730; PlayField16[i - FieldWidth] = 0x1011; // SnikSnak accessing from below, step = 0 PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_2730: if (PlayField16[i + 1] != 0) // 1 field right empty? -> point up goto loc_g_2778; PlayField16[i + 1] = 0x2811; // SnikSnak accessing from left, step = 0 PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_2741: // ELECTRON if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up goto loc_g_274D; MovHighByte(&PlayField16[i], 1); goto loc_g_2778; loc_g_274D: if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right goto loc_g_275E; PlayField16[i - FieldWidth] = 0x1018; // 1 field up PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_275E: if (PlayField16[i + 1] != 0) // 1 field right empty? -> no--point down goto loc_g_2778; PlayField16[i + 1] = 0x2818; PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_276F: // GRAVITY CHANGING PORTS PlayField16[i] = (ax - 4) | 0x100; // Convert to standard ports goto loc_g_2778; loc_g_2778: i = i + 1; // Next field bx = bx + 1; cx = cx - 1; if (0 < cx) // Until all done 'loc_g_2782: goto loc_g_26C9; return dx; // return InfotronCount } // ========================================================================== // SUBROUTINE // Reset Infotron count. Call immediately after subConvertToEasySymbols // ========================================================================== void ResetInfotronsNeeded(int dx) { if (LInfo.InfotronsNeeded != 0) // Jump If equal (autodetect) dx = LInfo.InfotronsNeeded; InfotronsNeeded = LowByte(dx); // Remaining Infotrons needed TotalInfotronsNeeded = InfotronsNeeded; // Number of Infotrons needed } // ========================================================================== // SUBROUTINE // Fetch and initialize a level // ========================================================================== void subFetchAndInitLevelB() { subFetchAndInitLevelA(); } void subFetchAndInitLevelA() { GameBusyFlag = 0; // restore scissors too subFetchAndInitLevel(); // fetch and initialize a level GameBusyFlag = 1; // no free screen write DemoKeyCode = 0; // delete last demo key! } void subFetchAndInitLevel() { int InfoCountInLevel; PrepareLevel(); // initialize level data GameBusyFlag = -GameBusyFlag; // make != 1 InfoCountInLevel = subConvertToEasySymbols(); // convert to easy symbols GameBusyFlag = -GameBusyFlag; // restore subDisplayLevel(); // paint (init) game field ResetInfotronsNeeded(InfoCountInLevel); // and reset Infotron count subInitGameConditions(); // init game conditions (vars) InitMurphyPos(); // locate Murphy + screen pos } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/ASM.h0000644000175000017500000000064611347525623017637 0ustar dimkadimka// ---------------------------------------------------------------------------- // ASM.h // ---------------------------------------------------------------------------- #ifndef ASM_H #define ASM_H #include "global.h" extern void MovLowByte(int *, int); extern void MovHighByte(int *, int); extern int LowByte(int); extern int HighByte(int); extern int SgnHighByte(int); extern int ByteToInt(byte); #endif /* ASM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/game_sp.h0000644000175000017500000000151511217234342020615 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * game_sp.h * ***********************************************************/ #ifndef GAME_SP_H #define GAME_SP_H #define GAME_SP_VERSION_1_0_0 #include "export.h" #endif /* GAME_SP_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DoGameStuff.c0000644000175000017500000000765111375770402021357 0ustar dimkadimka// ---------------------------------------------------------------------------- // DoGameStuff.c // ---------------------------------------------------------------------------- #include "DoGameStuff.h" static void CallAnimation(int si, byte bl); static boolean IsToBeAnimated(int bl); #if 1 int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; #else int *AnimationPosTable; byte *AnimationSubTable; #endif // ========================================================================== // SUBROUTINE // Do game stuff // ========================================================================== void subDoGameStuff() { int si, cx, dx, bl; subAnimateMurphy(&MurphyPosIndex); // move Murphy in any direction // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Build a database of locations and subs-to-call of animatable fields only: // Make a snapshot from the field before the animation cycle starts. // first and last line are not animated. si = FieldWidth + 1; cx = LevelMax - 2 * FieldWidth - 1; dx = 0; do // locloop_g_2282: { bl = LowByte(PlayField16[si]); if (((bl & 0xD) != 0) && (bl < 0x20)) // all animatables have 1's in &H0D' above &H1F? (&H1F=explosion!) { if (IsToBeAnimated(bl)) { AnimationPosTable[dx] = si; AnimationSubTable[dx] = bl; dx = dx + 1; // count database entries } } si = si + 1; // next field cx = cx - 1; } while (0 < cx); // locloop_g_2282' until all lines scanned(not top- and bottom edge) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Now use the database to animate all animatables the fastest way. // All the other fields are not checked anymore: those have no database entry. // The field from before animation is frozen in the database in order not to // do follow-up animations in the same loop. if (dx != 0) // any database entries? { dx = dx - 1; for (cx = 0; cx <= dx; cx++) { CallAnimation(AnimationPosTable[cx], AnimationSubTable[cx]); } // loop locloop_g_22B8 ' until all animatables done } // All animations are done now // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (KillMurphyFlag == 1 || MurphyMoveCounter == 0) { if (LeadOutCounter == 0 && !game_sp.LevelSolved && !game_sp.GameOver) { #if 0 printf("::: DoGameStuff.c: killing murphy [%d] ...\n", KillMurphyFlag); #endif KillMurphyFlag = 0; // no more "kill Murphy" ExplodeFieldSP(MurphyExplodePos); // Explode LeadOutCounter = 0x40; // quit: start lead-out #if 0 printf("::: DoGameStuff.c: !!!!!!!!!! GAME OVER !!!!!!!!!!\n"); printf("::: [KillMurphyFlag == %d]\n", KillMurphyFlag); #endif /* give Murphy some more time (LeadOutCounter) to reach the exit */ } } // loc_g_22FB: } static boolean IsToBeAnimated(int bl) { static boolean IsToBeAnimated; switch (bl) { case fiZonk: case fiInfotron: case fiOrangeDisk: case fiSnikSnak: case fiTerminal: case fiElectron: case fiBug: case fiExplosion: IsToBeAnimated = True; break; default: IsToBeAnimated = False; break; } return IsToBeAnimated; } static void CallAnimation(int si, byte bl) { switch (bl) { case fiZonk: subAnimateZonks(si); break; case fiInfotron: subAnimateInfotrons(si); break; case fiOrangeDisk: subAnimateOrangeDisks(si); break; case fiSnikSnak: subAnimateSnikSnaks(si); break; case fiTerminal: subAnimateTerminals(si); break; case fiElectron: subAnimateElectrons(si); break; case fiBug: subAnimateBugs(si); break; case fiExplosion: subAnimateExplosion(si); break; default: // Debug.Assert(False); break; } } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Sound.h0000644000175000017500000000047011347526226020302 0ustar dimkadimka// ---------------------------------------------------------------------------- // Sound.h // ---------------------------------------------------------------------------- #ifndef GAME_SP_SOUND_H #define GAME_SP_SOUND_H #include "global.h" extern void subSoundFX(int, int, int); #endif /* GAME_SP_SOUND_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Globals.h0000644000175000017500000002567511375770761020621 0ustar dimkadimka// ---------------------------------------------------------------------------- // Globals.h // ---------------------------------------------------------------------------- #ifndef GLOBALS_H #define GLOBALS_H #include "global.h" #ifndef False #define False 0 #define True (!False) #endif #define ScrollDelta ((long)1) #define ZoomFactor (2) #define StretchWidth (ZoomFactor * 16) #define TwoPixels (ZoomFactor * 2) // ---------------------------------------------------------------------------- // elements (stored in file and playfield) // ---------------------------------------------------------------------------- #define fiSpace (0) #define fiZonk (1) #define fiBase (2) #define fiMurphy (3) #define fiInfotron (4) #define fiRAM (5) #define fiHardWare (6) #define fiExit (7) #define fiOrangeDisk (8) #define fiPortRight (9) #define fiPortDown (10) #define fiPortLeft (11) #define fiPortUp (12) #define fiSpPortRight (13) #define fiSpPortDown (14) #define fiSpPortLeft (15) #define fiSpPortUp (16) #define fiSnikSnak (17) #define fiYellowDisk (18) #define fiTerminal (19) #define fiRedDisk (20) #define fiPortUpAndDown (21) #define fiPortLeftAndRight (22) #define fiPortAllDirections (23) #define fiElectron (24) #define fiBug (25) #define fiRAMLeft (26) #define fiRAMRight (27) #define fiHWFirst (28) #define fiHW0 (fiHWFirst + 0) // fiHWFirst #define fiHW1 (fiHWFirst + 1) #define fiHW2 (fiHWFirst + 2) #define fiHW3 (fiHWFirst + 3) #define fiHW4 (fiHWFirst + 4) #define fiHW5 (fiHWFirst + 5) #define fiHW6 (fiHWFirst + 6) #define fiHW7 (fiHWFirst + 7) #define fiHW8 (fiHWFirst + 8) #define fiHW9 (fiHWFirst + 9) // fiHWLast #define fiHWLast (37) #define fiRAMTop (38) #define fiRAMBottom (39) #define fiWallSpace (40) #define fiExplosion (0x1F) #define fiFirst (0) #define fiLast (40) // ---------------------------------------------------------------------------- // graphics and animations (used at runtime to display the elements) // ---------------------------------------------------------------------------- // graphics and animations directly related to file elements #define aniSpace IMG_EMPTY_SPACE #define aniZonk IMG_SP_ZONK #define aniBase IMG_SP_BASE #define aniMurphy IMG_SP_MURPHY #define aniInfotron IMG_SP_INFOTRON #define aniRAM IMG_SP_CHIP_SINGLE #define aniHardWare IMG_SP_HARDWARE_GRAY #define aniExit IMG_SP_EXIT_CLOSED #define aniOrangeDisk IMG_SP_DISK_ORANGE #define aniPortRight IMG_SP_PORT_RIGHT #define aniPortDown IMG_SP_PORT_DOWN #define aniPortLeft IMG_SP_PORT_LEFT #define aniPortUp IMG_SP_PORT_UP #define aniSpPortRight IMG_SP_GRAVITY_PORT_RIGHT #define aniSpPortDown IMG_SP_GRAVITY_PORT_DOWN #define aniSpPortLeft IMG_SP_GRAVITY_PORT_LEFT #define aniSpPortUp IMG_SP_GRAVITY_PORT_UP #define aniSnikSnak IMG_SP_SNIKSNAK #define aniYellowDisk IMG_SP_DISK_YELLOW #define aniTerminal IMG_SP_TERMINAL #define aniRedDisk IMG_SP_DISK_RED #define aniPortUpAndDown IMG_SP_PORT_VERTICAL #define aniPortLeftAndRight IMG_SP_PORT_HORIZONTAL #define aniPortAllDirections IMG_SP_PORT_ANY #define aniElectron IMG_SP_ELECTRON #define aniBug IMG_SP_BUGGY_BASE #define aniRAMLeft IMG_SP_CHIP_LEFT #define aniRAMRight IMG_SP_CHIP_RIGHT #define aniHWFirst IMG_SP_HARDWARE_BASE_1 #define aniHW0 IMG_SP_HARDWARE_BASE_1 #define aniHW1 IMG_SP_HARDWARE_GREEN #define aniHW2 IMG_SP_HARDWARE_BLUE #define aniHW3 IMG_SP_HARDWARE_RED #define aniHW4 IMG_SP_HARDWARE_YELLOW #define aniHW5 IMG_SP_HARDWARE_BASE_2 #define aniHW6 IMG_SP_HARDWARE_BASE_3 #define aniHW7 IMG_SP_HARDWARE_BASE_4 #define aniHW8 IMG_SP_HARDWARE_BASE_5 #define aniHW9 IMG_SP_HARDWARE_BASE_6 #define aniHWLast IMG_SP_HARDWARE_BASE_6 #define aniRAMTop IMG_SP_CHIP_TOP #define aniRAMBottom IMG_SP_CHIP_BOTTOM #define aniWallSpace IMG_INVISIBLE_WALL #define aniHWTrash1 #define aniHWTrash2 #define aniHWMurphy // graphics and animations related to in-game animations for element actions #define aniMurphyDropping IMG_SP_MURPHY_DROPPING #define aniMurphySleepLeft IMG_SP_MURPHY_SLEEPING_LEFT #define aniMurphySleepRight IMG_SP_MURPHY_SLEEPING_RIGHT #define aniMurphyTouchLeft IMG_SP_MURPHY_SNAPPING_LEFT #define aniMurphyTouchRight IMG_SP_MURPHY_SNAPPING_RIGHT #define aniMurphyTouchUp IMG_SP_MURPHY_SNAPPING_UP #define aniMurphyTouchDown IMG_SP_MURPHY_SNAPPING_DOWN #define aniMurphyYawn IMG_SP_MURPHY_BORING_1 #define aniPushLeft IMG_SP_MURPHY_PUSHING_LEFT #define aniPushRight IMG_SP_MURPHY_PUSHING_RIGHT #define aniBugActivating IMG_SP_BUGGY_BASE_ACTIVATING #define aniBugDeactivating IMG_SP_BUGGY_BASE_ACTIVATING #define aniBugActive IMG_SP_BUGGY_BASE_ACTIVE #define aniZonkRollLeft IMG_SP_ZONK_MOVING_LEFT #define aniZonkRollRight IMG_SP_ZONK_MOVING_RIGHT #define aniEatInfotronLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniEatInfotronRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniInfotronRollLeft IMG_SP_INFOTRON_MOVING_LEFT #define aniInfotronRollRight IMG_SP_INFOTRON_MOVING_RIGHT #define aniMurphyMoveLeft IMG_SP_MURPHY_MOVING_LEFT #define aniMurphyMoveRight IMG_SP_MURPHY_MOVING_RIGHT #define aniMurphyMoveUpLeft IMG_SP_MURPHY_MOVING_LEFT #define aniMurphyMoveUpRight IMG_SP_MURPHY_MOVING_RIGHT #define aniMurphyDigLeft IMG_SP_MURPHY_DIGGING_LEFT #define aniMurphyDigRight IMG_SP_MURPHY_DIGGING_RIGHT #define aniMurphyDigUpLeft IMG_SP_MURPHY_DIGGING_LEFT #define aniMurphyDigUpRight IMG_SP_MURPHY_DIGGING_RIGHT #define aniMurphyEatLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniMurphyEatRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniMurphyEatUpLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniMurphyEatUpRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniSplitUpDown IMG_SP_MURPHY #define aniMurphyExit IMG_SP_MURPHY_SHRINKING #define aniElectron IMG_SP_ELECTRON #define aniExplosion IMG_SP_DEFAULT_EXPLODING #define aniTouchBase IMG_SP_BASE_SNAPPING #define aniTouchInfotron IMG_SP_INFOTRON_COLLECTING #define aniTouchRedDisk IMG_SP_DISK_RED_COLLECTING #define aniYellowDisk IMG_SP_DISK_YELLOW #define aniOrangeDisk IMG_SP_DISK_ORANGE #define aniRedDisk IMG_SP_DISK_RED #define aniSnikSnakDown IMG_SP_SNIKSNAK_DOWN #define aniSnikSnakLeft IMG_SP_SNIKSNAK_LEFT #define aniSnikSnakRight IMG_SP_SNIKSNAK_RIGHT #define aniSnikSnakUp IMG_SP_SNIKSNAK_UP #define aniSnikSnakTurnLeftToUp IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP #define aniSnikSnakTurnLeftToDown IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN #define aniSnikSnakTurnRightToUp IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP #define aniSnikSnakTurnRightToDown IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN #define aniSnikSnakTurnUpToLeft IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT #define aniSnikSnakTurnUpToRight IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT #define aniSnikSnakTurnDownToLeft IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT #define aniSnikSnakTurnDownToRight IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT #define aniTerminalActive IMG_SP_TERMINAL_ACTIVE #define aniDefaultExplosion IMG_SP_DEFAULT_EXPLODING #define aniElectronExplosion IMG_SP_ELECTRON_EXPLODING #define imgFrameCorner IMG_SP_FRAME_CORNER #define imgFrameHorizontal IMG_SP_FRAME_HORIZONTAL #define imgFrameVertical IMG_SP_FRAME_VERTICAL // ---------------------------------------------------------------------------- // input keys // ---------------------------------------------------------------------------- #define keyNone (0) #define keyUp (1) #define keyLeft (2) #define keyDown (3) #define keyRight (4) #define keySpaceUp (5) #define keySpaceLeft (6) #define keySpaceDown (7) #define keySpaceRight (8) #define keySpace (9) // ---------------------------------------------------------------------------- // data structures // ---------------------------------------------------------------------------- #ifndef HAS_LevelDescriptor typedef struct { int Width; int Height; long OffSet; long Size; } LevelDescriptor; #define HAS_LevelDescriptor #endif #ifndef HAS_SpecialPortType typedef struct { short PortLocation; // = 2*(x+(y*60)) byte Gravity; // 1 = turn on, anything else (0) = turn off byte FreezeZonks; // 2 = turn on, anything else (0) = turn off (1=off!) byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off byte UnUsed; } SpecialPortType; #define HAS_SpecialPortType #endif #ifndef HAS_LevelInfoType typedef struct { byte UnUsed[4]; byte InitialGravity; // 1=on, anything else (0) = off byte Version; // SpeedFixVersion XOR &H20 char LevelTitle[23]; byte InitialFreezeZonks; // 2=on, anything else (0) = off. (1=off too!) byte InfotronsNeeded; // Number of Infotrons needed. 0 means that Supaplex will count the total // amount of Infotrons in the level, and use the low byte of that number. // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!) byte SpecialPortCount; // Maximum 10 allowed! SpecialPortType SpecialPort[10]; byte SpeedByte; // = Speed XOR Highbyte(RandomSeed) byte CheckSumByte; // = CheckSum XOR SpeedByte short DemoRandomSeed; } LevelInfoType; #define HAS_LevelInfoType #endif extern int GetSI(int X, int Y); extern int GetStretchX(int si); extern int GetStretchY(int si); extern int GetX(int si); extern int GetY(int si); extern void InitGlobals(); extern void PrepareLevel(); extern int getSequenceLength(int sequence); extern boolean isSnappingSequence(int sequence); #if 0 extern void Trace(char *Source, char *Message); extern void ReportError(char *Source, char *Message); #endif extern int Min(int A, int B); extern int Max(int A, int B); extern int fiGraphic[]; extern int aniSnikSnakTurningLeft[]; extern int aniSnikSnakTurningRight[]; extern boolean LevelLoaded; extern boolean DemoAvailable; extern boolean menBorder; #if 1 extern int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; extern byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; extern byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; #else extern int *PlayField16; extern byte *PlayField8; extern byte *DisPlayField; #endif extern int FieldHeight; extern int FieldMax, LevelMax; extern int FieldWidth; extern int FreezeZonks; extern int HeaderSize; extern int TimerVar; extern short RandomSeed; extern long FileMax; extern LevelInfoType LInfo; extern int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY; extern int ScrollX, ScrollY; extern int AllowRedDiskCheat, AllowEatRightRedDiskBug; extern int Data_SubRest, Data_SubRstFlg; extern int DemoKeyCode; extern int GameBusyFlag; extern int InfotronsNeeded, TotalInfotronsNeeded; extern int KillMurphyFlag, MurphyMoveCounter; extern int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos; extern int MurphyPosIndex, MurphyXPos, MurphyYPos; extern int MurphyScreenXPos, MurphyScreenYPos; extern int MurphyVarFaceLeft; extern int RedDiskCount; extern int RedDiskReleaseFlag, MovingPictureSequencePhase; extern int RedDiskReleasePhase; extern int ScratchGravity, GravityFlag; extern int SnikSnaksElectronsFrozen; extern int YellowDisksExploded; extern long YawnSleepCounter; #endif /* GLOBALS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/global.h0000644000175000017500000000134211375752451020453 0ustar dimkadimka// ---------------------------------------------------------------------------- // global.h // ---------------------------------------------------------------------------- #ifndef GAME_SP_GLOBAL_H #define GAME_SP_GLOBAL_H #include "main_sp.h" #include "vb_lib.h" #include "ASM.h" #include "BugsTerminals.h" #include "DDScrollBuffer.h" #include "DDSpriteBuffer.h" #include "Display.h" #include "DoGameStuff.h" #include "Electrons.h" #include "Explosions.h" #include "Globals.h" #include "Infotrons.h" #include "InitGameConditions.h" #include "Input.h" #include "MainForm.h" #include "MainGameLoop.h" #include "Murphy.h" #include "OrangeDisk.h" #include "SnikSnaks.h" #include "Sound.h" #include "Zonk.h" #endif /* GAME_SP_GLOBAL_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/SnikSnaks.h0000644000175000017500000000053211347526211021107 0ustar dimkadimka// ---------------------------------------------------------------------------- // SnikSnaks.h // ---------------------------------------------------------------------------- #ifndef SNIKSNAKS_H #define SNIKSNAKS_H #include "global.h" extern void subAnimateSnikSnaks(int); extern void subDrawAnimatedSnikSnaks(int); #endif /* SNIKSNAKS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Infotrons.c0000644000175000017500000002530711347530347021173 0ustar dimkadimka// ---------------------------------------------------------------------------- // Infotrons.c // ---------------------------------------------------------------------------- #include "Infotrons.h" // ========================================================================== // SUBROUTINE // Animate Infotrons (falling) // ========================================================================== void subAnimateInfotrons(int si) { int tFld; int ax, bx, dx, X, Y; int al, bl; tFld = PlayField16[si]; if ((tFld & 0xFF) != fiInfotron) return; if (tFld == fiInfotron) { ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60) if (ax == 0) goto loc_g_11D5; if (ax == fiZonk) goto loc_g_11A6; if (ax == fiInfotron) goto loc_g_11A6; if (ax == fiRAM) goto loc_g_11A6; return; loc_g_11A6: // Case fiZonk, fiInfotron, fiRAM ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_11DC; loc_g_11BD: ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_11F2; return; loc_g_11D5: // Case fiSpace MovHighByte(&PlayField16[si], 0x40); goto loc_g_1207; loc_g_11DC: // roll left? if (PlayField16[si - 1] == 0) goto loc_g_11E5; goto loc_g_11BD; loc_g_11E5: MovHighByte(&PlayField16[si], 0x50); PlayField16[si - 1] = 0x8888; goto loc_g_1207; loc_g_11F2: // roll right? if (PlayField16[si + 1] == 0) goto loc_g_11FA; return; loc_g_11FA: MovHighByte(&PlayField16[si], 0x60); PlayField16[si + 1] = 0x8888; } // tFld = fiInfotron loc_g_1207: // from now on the infotron is definitely moving, // maybe the sequence is in an advanced frame // or just beeing initialized due to the code above bl = HighByte(PlayField16[si]); bx = 0; MovLowByte(&bx, bl); al = bl & 0xF0; if (al == 0x10) // infotron comes falling from above goto loc_g_1242; if (al == 0x20) // infotron comes rolling from right to left goto loc_g_138D; if (al == 0x30) // infotron comes rolling from left to right goto loc_g_13E9; if (al == 0x40) // infotron falls straight down goto loc_g_1444; if (al == 0x50) // infotron rolls left goto loc_g_1472; if (al == 0x60) // infotron rolls right goto loc_g_14E0; if (al == 0x70) // intermediate state goto loc_g_154E; return; loc_g_1242: // infotron comes falling from above // To Do: draw infotron falling from above // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); dx = bl & 0x7; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniInfotron, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x16) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si - FieldWidth); return; } // loc_g_1285: if (bl < 0x18) { MovHighByte(&PlayField16[si], bl); return; } // loc_g_128F: MovHighByte(&PlayField16[si], 0); // infotron arrived at the field // now check if the zonk may go on falling somehow ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty!-> go on falling goto loc_g_132D; if (ax == 0x9999) // below is only temporarily used goto loc_g_132D; if ((ax & 0xFF) == fiMurphy) // Murphy dies goto loc_g_1364; if (ax == fiRedDisk) // red disk hit goto loc_g_1386; if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies goto loc_g_1386; if ((ax & 0xFF) == fiElectron) // Electron cracked! goto loc_g_1386; if (ax == fiYellowDisk) // yellow disk hit goto loc_g_1386; if (ax == fiOrangeDisk) // orange disk hit goto loc_g_1386; #if 1 #if 1 // play the infotron sound, 'cause infotron hits something "hard" subSoundFX(si, fiInfotron, actImpact); #else // play the zonk sound, 'cause zonk hits something "hard" subSoundFX(si, fiZonk, actImpact); #endif #else subSoundFXZonk(); // play the zonk sound,'cause zonk hits something "hard" #endif if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) return; // infotron rolls somewhere ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left goto loc_g_133A; ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right goto loc_g_1350; return; loc_g_132D: // go on falling down? PlayField16[si] = 0x7004; // go into intermediate waitstate PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access" return; loc_g_133A: // test if infotron may roll left // This if(if true) jumps up far above // to the according rountine for fixed infotrons! if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4: goto loc_g_11BD; MovHighByte(&PlayField16[si], 0x50); // infotron rolls left PlayField16[si - 1] = 0x8888; return; loc_g_1350: // test if infotron may roll right if (PlayField16[si + 1] != 0) return; MovHighByte(&PlayField16[si], 0x60); // infotron rolls right PlayField16[si + 1] = 0x8888; return; loc_g_1364: // Murphy dies, but not in any case bl = HighByte(PlayField16[si + FieldWidth]); if (bl == 0xE || bl == 0xF || bl == 0x28) return; if (bl == 0x29 || bl == 0x25 || bl == 0x26) return; loc_g_1386: // someone dies/explodes immediately si = si + FieldWidth; // 1 field down ExplodeFieldSP(si); // Explode return; loc_g_138D: // infotron comes rolling from right to left // To Do: draw infotron rolling from right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniInfotronRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // get and increment sequence# if (bl == 0x24) PlayField16[si + 1] = 0xAAAA; if (bl == 0x26) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si + 1); } else if (bl < 0x28) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0x7004; // go into intermediate state } return; loc_g_13E9: // infotron comes rolling from left to right // To Do: draw infotron rolling from left // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniInfotronRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x34) PlayField16[si - 1] = 0xAAAA; if (bl == 0x36) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si - 1); } else if (bl < 0x38) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0x7004; // go into intermediate state } return; loc_g_1444: // infotron falls straight down bl = bl + 1; if (bl < 0x42) { MovHighByte(&PlayField16[si], bl); } else if (PlayField16[si + FieldWidth] != 0) { bl = bl - 1; // stay waiting MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1004; // go falling } return; loc_g_1472: // infotron rolls left // To Do: draw infotron rolling to left // according to position in (bl And &H0F) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0xF) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniInfotronRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence# if (bl < 0x52) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth - 1] != 0) goto loc_g_14D9; if (PlayField16[si - 1] != 0) { if (PlayField16[si - 1] != 0x8888) goto loc_g_14D9; } PlayField16[si] = 0xFFFF; si = si - 1; // 1 field left PlayField16[si] = 0x2204; PlayField16[si + FieldWidth] = 0x9999; return; loc_g_14D9: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_14E0: // infotron rolls right // To Do: draw infotron rolling to right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniInfotronRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl < 0x62) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth + 1] != 0) goto loc_g_1547; if (PlayField16[si + 1] != 0) { if (PlayField16[si + 1] != 0x8888) goto loc_g_1547; } PlayField16[si] = 0xFFFF; si = si + 1; PlayField16[si] = 0x3204; PlayField16[si + FieldWidth] = 0x9999; return; loc_g_1547: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_154E: // intermediate state ax = PlayField16[si + FieldWidth]; if (ax == 0 || ax == 0x9999) { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1004; // start falling down goto loc_g_1242; } } void subCleanUpForInfotronsAbove(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; if (PlayField16[si - FieldWidth] != 0) { if (PlayField16[si - FieldWidth] != 0x9999) return; if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiZonk) return; } if (PlayField16[si - FieldWidth - 1] == fiInfotron) goto loc_g_16FE; loc_g_16F6: if (PlayField16[si - FieldWidth + 1] == fiInfotron) goto loc_g_1722; return; loc_g_16FE: ax = PlayField16[si - 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth - 1] = 0x6004; PlayField16[si - FieldWidth] = 0x8888; return; } goto loc_g_16F6; loc_g_1722: ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth + 1] = 0x5004; PlayField16[si - FieldWidth] = 0x8888; } } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/vb_lib.c0000644000175000017500000000143511375770641020447 0ustar dimkadimka// ---------------------------------------------------------------------------- // vb_lib.c // ---------------------------------------------------------------------------- #include "main_sp.h" #include "vb_lib.h" /* helper functions for constructs not supported by C */ #if 0 void *REDIM_1D(int data_size, int first_data_pos, int last_data_pos) { /* for a buffer of n elements, first_data_pos is 0 and last_data_pos is n-1 */ /* a negative value for "first_data_pos" indicates a preceding buffer zone */ int data_count = last_data_pos - first_data_pos + 1; int buffer_size = data_size * data_count; int buffer_start = data_size * first_data_pos; return (checked_calloc(buffer_size) - buffer_start); } #endif long MyGetTickCount() { return random_linux_libc(RANDOM_SIMPLE); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/vb_lib.h0000644000175000017500000000064211375770656020461 0ustar dimkadimka// ---------------------------------------------------------------------------- // vb_lib.h // ---------------------------------------------------------------------------- #ifndef VB_LIB_H #define VB_LIB_H #define Abs(x) ABS(x) #define Sqr(x) sqrt(x) /* helper functions for constructs not supported by C */ #if 0 extern void *REDIM_1D(int, int, int); #endif extern long MyGetTickCount(); #endif /* VB_LIB_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Explosions.c0000644000175000017500000001766311375601212021352 0ustar dimkadimka// ---------------------------------------------------------------------------- // Explosions.c // ---------------------------------------------------------------------------- #include "Explosions.h" static void LetExplodeFieldSP(int tsi, int cx, int dh); static void subExplodeInfotron(int tsi, int cx); static void subExplodeZonk(int tsi, int cx); // ========================================================================== // SUBROUTINE // Animate explosion // ========================================================================== void subAnimateExplosion(int si) { int ax, bl, X, Y; if (LowByte(PlayField16[si]) != fiExplosion) return; ax = (TimerVar & 3); if (ax != 0) return; bl = HighByte(PlayField16[si]); if ((bl & 0x80) != 0) // infotron explosion! goto loc_g_28D0; bl = bl + 1; MovHighByte(&PlayField16[si], bl); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); GfxGraphic[GetX(si)][GetY(si)] = aniDefaultExplosion; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (bl == 8) { PlayField16[si] = 0; ExplosionShake = 0; // nothing explodes // ExplosionShakeMurphy = 0; // nothing explodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSpace; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // loc_ret_g_28CF: return; loc_g_28D0: // explosion produces infotron bl = bl + 1; if (bl == 0x89) { PlayField16[si] = fiInfotron; MovLowByte(&ExplosionShake, 0); // nothing explodes // MovLowByte(&ExplosionShakeMurphy, 0); // nothing explodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniInfotron; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ return; } // loc_g_28E3: MovHighByte(&PlayField16[si], bl); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); GfxGraphic[GetX(si)][GetY(si)] = aniElectronExplosion; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Explode // ========================================================================== void ExplodeFieldSP(int si) { int ax, cx, dl; ax = LowByte(PlayField16[si]); if (ax == fiHardWare) return; ExplosionShake = 1; // something explodes if (ax == fiMurphy) { #if 0 printf("::: Explosions.c: ExplodeFieldSP(): killing murphy\n"); #endif KillMurphyFlag = 1; #if 1 ExplosionShakeMurphy = 30; // Murphy explodes #endif } if (ax == fiElectron) { cx = 0x801F; // produce infotrons dl = 0xF3; } else // loc_g_2977: { cx = 0x1F; // normal explosion dl = 0xD; } // loc_g_297C: LetExplodeFieldSP(si - FieldWidth - 1, cx, dl); LetExplodeFieldSP(si - FieldWidth, cx, dl); LetExplodeFieldSP(si - FieldWidth + 1, cx, dl); LetExplodeFieldSP(si - 1, cx, dl); PlayField16[si] = cx; LetExplodeFieldSP(si + 1, cx, dl); LetExplodeFieldSP(si + FieldWidth - 1, cx, dl); LetExplodeFieldSP(si + FieldWidth, cx, dl); LetExplodeFieldSP(si + FieldWidth + 1, cx, dl); GfxGraphic[GetX(si)][GetY(si)] = -1; // restart for chain-explosions // loc_g_2C3B: subSoundFX(si, ax, actExploding); } static void LetExplodeFieldSP(int tsi, int cx, int dh) { int al; if (tsi < (-FieldWidth)) return; al = LowByte(PlayField16[tsi]); switch (al) { case fiHardWare: return; break; case fiOrangeDisk: case fiYellowDisk: case fiSnikSnak: PlayField8[tsi] = dh; PlayField16[tsi] = cx; break; case fiZonk: subExplodeZonk(tsi, cx); break; case fiInfotron: subExplodeInfotron(tsi, cx); break; case fiElectron: PlayField8[tsi] = (-dh) & 0xFF; PlayField16[tsi] = 0x801F; break; case fiMurphy: #if 0 printf("::: Explosions.c: LetExplodeFieldSP(): killing murphy [%d]\n", tsi); #endif KillMurphyFlag = 1; PlayField8[tsi] = dh; PlayField16[tsi] = cx; break; default: PlayField16[tsi] = cx; break; } GfxGraphic[GetX(tsi)][GetY(tsi)] = -1; // restart for chain-explosions } static void subExplodeZonk(int tsi, int cx) { int ah; ah = HighByte(PlayField16[tsi]) & 0xF0; PlayField16[tsi] = cx; switch (ah) { case 0x10: case 0x70: subClearFieldDueToExplosion(tsi - FieldWidth); tsi = tsi + FieldWidth; if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x20: subClearFieldDueToExplosion(tsi + 1); subClearFieldDueToExplosion(tsi + FieldWidth); break; case 0x30: subClearFieldDueToExplosion(tsi - 1); subClearFieldDueToExplosion(tsi + FieldWidth); break; case 0x50: subClearFieldDueToExplosion(tsi - 1); break; case 0x60: subClearFieldDueToExplosion(tsi + 1); break; case 0xFF000070: // !!! 0x70; this will never be reached! ...?? subClearFieldDueToExplosion(tsi + FieldWidth); break; } } static void subExplodeInfotron(int tsi, int cx) { int ah; ah = HighByte(PlayField16[tsi]) & 0xF0; PlayField16[tsi] = cx; switch (ah) { case 0x10: case 0x70: subClearFieldDueToExplosion(tsi - FieldWidth); tsi = tsi + FieldWidth; if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x20: subClearFieldDueToExplosion(tsi + 1); tsi = tsi + FieldWidth; // differnt from zonk version if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x30: subClearFieldDueToExplosion(tsi - 1); tsi = tsi + FieldWidth; // differnt from zonk version if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x50: subClearFieldDueToExplosion(tsi - 1); break; case 0x60: subClearFieldDueToExplosion(tsi + 1); break; case 0xFF000070: // !!! 0x70; this will never be reached! ...?? subClearFieldDueToExplosion(tsi + FieldWidth); break; } } void subClearFieldDueToExplosion(int si) { int X, Y; if (LowByte(PlayField16[si]) == fiExplosion) return; PlayField16[si] = 0; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); GfxGraphic[GetX(si)][GetY(si)] = aniSpace; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subRedDiskReleaseExplosion() { int al, X, Y, si; al = RedDiskReleasePhase; // Red disk release phase if (al <= 1) return; si = RedDiskReleaseMurphyPos; if (PlayField16[si] == 0) // Release red disk PlayField16[si] = fiRedDisk; // +++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); #if 0 // !!! causes flicker -- fix in Murphy.c !!! GfxGraphic[GetX(si)][GetY(si)] = aniRedDisk; #else DDSpriteBuffer_BltImg(X, Y, aniRedDisk, 0); #endif // +++++++++++++++++++++++++++++++++++++++++ RedDiskReleasePhase = RedDiskReleasePhase + 1; if (RedDiskReleasePhase >= 0x28) { // si = RedDiskReleaseMurphyPos ' Red disk was released here ExplodeFieldSP(si); // Explode RedDiskReleasePhase = 0; } } void subFollowUpExplosions() { int ax, si; // locloop_g_2919: for (si = 0; si <= LevelMax; si++) { ax = ByteToInt(PlayField8[si]); if (ax != 0) { if (ax < 0) { ax = ax + 1; PlayField8[si] = ax & 0xFF; if (ax == 0) { PlayField16[si] = 0xFF18; ExplodeFieldSP(si); // Explode } } else { ax = ax - 1; PlayField8[si] = ax; if (ax == 0) ExplodeFieldSP(si); } } } } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/export.h0000644000175000017500000001353211362412735020532 0ustar dimkadimka#ifndef GAME_SP_EXPORT_H #define GAME_SP_EXPORT_H /* ========================================================================= */ /* functions and definitions exported from game_sp to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ #define SP_MAX_PLAYFIELD_WIDTH MAX_PLAYFIELD_WIDTH #define SP_MAX_PLAYFIELD_HEIGHT MAX_PLAYFIELD_HEIGHT #define SP_NUM_LEVELS_PER_PACKAGE 111 #define SP_STD_PLAYFIELD_WIDTH 60 #define SP_STD_PLAYFIELD_HEIGHT 24 #define SP_LEVEL_NAME_LEN 23 #define SP_MAX_SPECIAL_PORTS 10 #define SP_HEADER_SIZE 96 #define SP_STD_PLAYFIELD_SIZE (SP_STD_PLAYFIELD_WIDTH * \ SP_STD_PLAYFIELD_HEIGHT) #define SP_MAX_PLAYFIELD_SIZE (SP_MAX_PLAYFIELD_WIDTH * \ SP_MAX_PLAYFIELD_HEIGHT) #define SP_STD_LEVEL_SIZE (SP_HEADER_SIZE + SP_STD_PLAYFIELD_SIZE) #if 0 #define SP_SCREEN_BUFFER_XSIZE (SCR_FIELDX + 2) #define SP_SCREEN_BUFFER_YSIZE (SCR_FIELDY + 2) #endif #define SP_FRAMES_PER_SECOND 35 #define SP_MAX_TAPE_LEN 64010 /* (see "spfix63.doc") */ /* sound actions */ #define actActive 0 #define actImpact 1 #define actExploding 2 #define actDigging 3 #define actSnapping 4 #define actCollecting 5 #define actPassing 6 #define actPushing 7 #define actDropping 8 /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ #ifndef HAS_SpecialPortType typedef struct { #if 1 short PortLocation; // = 2*(x+(y*60)) /* big endian format */ #else int PortLocation; // = 2*(x+(y*60)) #endif byte Gravity; // 1 = turn on, anything else (0) = turn off byte FreezeZonks; // 2 = turn on, anything else (0) = turn off (1=off!) byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off byte UnUsed; } SpecialPortType; #define HAS_SpecialPortType #endif #ifndef HAS_LevelInfoType typedef struct { byte UnUsed[4]; byte InitialGravity; // 1=on, anything else (0) = off byte Version; // SpeedFixVersion XOR &H20 char LevelTitle[23]; byte InitialFreezeZonks; // 2=on, anything else (0) = off. (1=off too!) byte InfotronsNeeded; // Number of Infotrons needed. 0 means that Supaplex will count the total // amount of Infotrons in the level, and use the low byte of that number. // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!) byte SpecialPortCount; // Maximum 10 allowed! SpecialPortType SpecialPort[10]; byte SpeedByte; // = Speed XOR Highbyte(RandomSeed) byte CheckSumByte; // = CheckSum XOR SpeedByte #if 1 short DemoRandomSeed; /* little endian format */ #else int DemoRandomSeed; #endif } LevelInfoType; #define HAS_LevelInfoType #endif struct GlobalInfo_SP { }; struct GameInfo_SP { boolean LevelSolved; boolean GameOver; /* needed for updating panel */ int time_played; int infotrons_still_needed; int red_disk_count; int score; /* needed for engine snapshots */ int preceding_buffer_size; int scroll_xoffset, scroll_yoffset; }; struct DemoInfo_SP { boolean is_available; /* structure contains valid demo */ int level_nr; /* number of corresponding level */ int length; /* number of demo entries */ byte data[SP_MAX_TAPE_LEN]; /* array of demo entries */ }; struct LevelInfo_SP { LevelInfoType header; byte header_raw_bytes[SP_HEADER_SIZE]; int width, height; byte playfield[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; struct DemoInfo_SP demo; /* used for runtime values */ struct GameInfo_SP *game_sp; }; struct GraphicInfo_SP { Bitmap *bitmap; int src_x, src_y; int src_offset_x, src_offset_y; int dst_offset_x, dst_offset_y; int width, height; Bitmap *crumbled_bitmap; int crumbled_src_x, crumbled_src_y; int crumbled_border_size; boolean has_crumbled_graphics; boolean preserve_background; int unique_identifier; /* used to identify needed screen updates */ }; struct EngineSnapshotInfo_SP { struct GameInfo_SP game_sp; int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; }; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ extern struct GlobalInfo_SP global_sp_info; extern struct GameInfo_SP game_sp; extern struct LevelInfo_SP native_sp_level; extern struct GraphicInfo_SP graphic_info_sp_object[TILE_MAX][8]; extern struct GraphicInfo_SP graphic_info_sp_player[MAX_PLAYERS][SPR_MAX][8]; extern struct EngineSnapshotInfo_SP engine_snapshot_sp; extern void sp_open_all(); extern void sp_close_all(); extern void InitGfxBuffers_SP(); extern void InitGameEngine_SP(); extern void GameActions_SP(byte *, boolean); extern unsigned int InitEngineRandom_SP(long); extern void setLevelInfoToDefaults_SP(); extern void copyInternalEngineVars_SP(); extern boolean LoadNativeLevel_SP(char *, int); extern void SaveNativeLevel_SP(char *); extern void BackToFront_SP(void); extern void BlitScreenToBitmap_SP(Bitmap *); extern void RedrawPlayfield_SP(boolean); extern void DrawGameDoorValues_SP(); extern void LoadEngineSnapshotValues_SP(); extern void SaveEngineSnapshotValues_SP(); extern int map_key_RND_to_SP(int); extern int map_key_SP_to_RND(int); #endif /* GAME_SP_EXPORT_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Explosions.h0000644000175000017500000000072111347526006021350 0ustar dimkadimka// ---------------------------------------------------------------------------- // Explosions.h // ---------------------------------------------------------------------------- #ifndef EXPLOSIONS_H #define EXPLOSIONS_H #include "global.h" extern void ExplodeFieldSP(int); extern void subAnimateExplosion(int); extern void subClearFieldDueToExplosion(int); extern void subFollowUpExplosions(); extern void subRedDiskReleaseExplosion(); #endif /* EXPLOSIONS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/file.c0000644000175000017500000005150311375770562020134 0ustar dimkadimka #include "main_sp.h" #include "global.h" /* ------------------------------------------------------------------------- */ /* functions for loading Supaplex level */ /* ------------------------------------------------------------------------- */ void setTapeInfoToDefaults_SP() { native_sp_level.demo.is_available = FALSE; native_sp_level.demo.length = 0; } void setLevelInfoToDefaults_SP() { LevelInfoType *header = &native_sp_level.header; char *empty_title = "-------- EMPTY --------"; int i, x, y; native_sp_level.game_sp = &game_sp; native_sp_level.width = SP_STD_PLAYFIELD_WIDTH; native_sp_level.height = SP_STD_PLAYFIELD_HEIGHT; for (x = 0; x < native_sp_level.width; x++) for (y = 0; y < native_sp_level.height; y++) native_sp_level.playfield[x][y] = fiSpace; /* copy string (without terminating '\0' character!) */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = empty_title[i]; header->InitialGravity = 0; header->Version = 0; header->InitialFreezeZonks = 0; header->InfotronsNeeded = 0; header->SpecialPortCount = 0; header->SpeedByte = 0; header->CheckSumByte = 0; header->DemoRandomSeed = 0; for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; port->PortLocation = 0; port->Gravity = 0; port->FreezeZonks = 0; port->FreezeEnemies = 0; } /* set raw header bytes (used for subsequent buffer zone) to "hardware" */ for (i = 0; i < SP_HEADER_SIZE; i++) native_sp_level.header_raw_bytes[i] = 0x20; setTapeInfoToDefaults_SP(); } void copyInternalEngineVars_SP() { char *preceding_playfield_memory[] = { "95 89 95 89 95 89 3b 8a 3b 8a 3b 8a 3b 8a 3b 8a", // |......;.;.;.;.;.| "3b 8a 3b 8a 3b 8a e8 8a e8 8a e8 8a e8 8a e8 8a", // |;.;.;.è.è.è.è.è.| "e8 8a e8 8a e8 8a b1 8b b1 8b b1 8b b1 8b b1 8b", // |è.è.è.±.±.±.±.±.| "b1 8b b1 8b b1 8b 85 8c 85 8c 85 8c 85 8c 85 8c", // |±.±.±...........| "85 8c 85 8c 85 8c 5b 8d 5b 8d 5b 8d 5b 8d 5b 8d", // |......[.[.[.[.[.| "5b 8d 5b 8d 5b 8d 06 8e 06 8e 06 8e 06 8e 06 8e", // |[.[.[...........| "06 8e 06 8e 06 8e ac 8e ac 8e ac 8e ac 8e ac 8e", // |......¬.¬.¬.¬.¬.| "ac 8e ac 8e ac 8e 59 8f 59 8f 59 8f 59 8f 59 8f", // |¬.¬.¬.Y.Y.Y.Y.Y.| "59 8f 59 8f 59 8f 00 00 70 13 00 00 00 00 e8 17", // |Y.Y.Y...p.....è.| "00 00 00 00 00 00 69 38 00 00 00 00 00 00 00 00", // |......i8........| "00 00 00 00 00 00 00 00 d0 86 00 00 b2 34 00 00", // |........Ð...²4..| "00 00 00 00 00 00 8f 8b 1d 34 00 00 00 00 00 00", // |.........4......| "00 00 00 00 23 39 09 09 00 0c 00 08 00 58 00 00", // |....#9.......X..| "00 00 00 25 77 06 7f 00 00 00 01 00 00 00 00 00", // |...%w...........| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 ec 06 26 05 00 00 00", // |.........ì.&....| "00 00 00 01 00 00 00 00 31 32 33 34 35 36 37 38", // |........12345678| "39 30 2d 00 08 00 51 57 45 52 54 59 55 49 4f 50", // |90-...QWERTYUIOP| "00 00 0a 00 41 53 44 46 47 48 4a 4b 4c 00 00 00", // |....ASDFGHJKL...| "00 00 5a 58 43 56 42 4e 4d 00 00 00 00 00 00 20", // |..ZXCVBNM...... | "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 2e 00 1e 00 31 00 14 00 39 00", // |..........1...9.| "1f 00 14 00 18 00 ff ff 01 00 01 4c 45 56 45 4c", // |......ÿÿ...LEVEL| "53 2e 44 41 54 00 00 00 00 00 00 00 00 00 00 00", // |S.DAT...........| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| NULL }; int preceding_buffer_size = 0; int count; int i, x, y; for (i = 0; preceding_playfield_memory[i] != NULL; i++) preceding_buffer_size += 8; /* eight 16-bit integer values */ /* needed for engine snapshots */ game_sp.preceding_buffer_size = preceding_buffer_size; LInfo = native_sp_level.header; FieldWidth = native_sp_level.width; FieldHeight = native_sp_level.height; HeaderSize = 96; FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; /* (add one byte for the level number stored as first byte of demo data) */ FileMax = FieldMax + native_sp_level.demo.length + 1; #if 0 PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax); DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax); PlayField16 = REDIM_1D(sizeof(int), -preceding_buffer_size, FieldMax); #endif count = 0; for (i = 0; preceding_playfield_memory[i] != NULL; i++) { char *s = preceding_playfield_memory[i]; boolean hi_byte = FALSE; /* little endian data => start with low byte */ while (s[0] != '\0' && s[1] != '\0') { int hi_nibble = s[0] - (s[0] > '9' ? 'a' - 10 : '0'); int lo_nibble = s[1] - (s[1] > '9' ? 'a' - 10 : '0'); int byte = (hi_nibble << 4) | lo_nibble; if (hi_byte) byte <<= 8; PlayField16[-preceding_buffer_size + count] |= byte; if (hi_byte) count++; hi_byte = !hi_byte; s += 2; while (*s == ' ') s++; } } count = 0; for (y = 0; y < native_sp_level.height; y++) for (x = 0; x < native_sp_level.width; x++) PlayField8[count++] = native_sp_level.playfield[x][y]; /* add raw header bytes to subsequent playfield buffer zone */ for (i = 0; i < SP_HEADER_SIZE; i++) PlayField8[count++] = native_sp_level.header_raw_bytes[i]; for (i = 0; i < count; i++) { PlayField16[i] = PlayField8[i]; DisPlayField[i] = PlayField8[i]; PlayField8[i] = 0; } if (native_sp_level.demo.is_available) { DemoAvailable = True; #if 0 /* !!! NEVER USED !!! */ PlayField8[FieldMax + 1] = native_sp_level.demo.level_nr; /* !!! NEVER USED !!! */ for (i = 0; i < native_sp_level.demo.length; i++) PlayField8[FieldMax + 2 + i] = native_sp_level.demo.data[i]; #endif } #if 0 AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 * FieldWidth); AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 * FieldWidth); TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax); #endif GravityFlag = LInfo.InitialGravity; FreezeZonks = LInfo.InitialFreezeZonks; #if 1 /* this is set by main game tape code to native random generator directly */ #else RandomSeed = LInfo.DemoRandomSeed; #endif LevelLoaded = True; } static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height, boolean demo_available) { LevelInfoType *header = &native_sp_level.header; int i, x, y; /* for details of the Supaplex level format, see Herman Perk's Supaplex documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */ native_sp_level.width = MIN(width, SP_MAX_PLAYFIELD_WIDTH); native_sp_level.height = MIN(height, SP_MAX_PLAYFIELD_HEIGHT); /* read level playfield (width * height == 60 * 24 tiles == 1440 bytes) */ /* (MPX levels may have non-standard playfield size -- check max. size) */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { byte element = getFile8Bit(file); if (x < SP_MAX_PLAYFIELD_WIDTH && y < SP_MAX_PLAYFIELD_HEIGHT) native_sp_level.playfield[x][y] = element; } } /* read level header (96 bytes) */ ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */ /* initial gravity: 1 == "on", anything else (0) == "off" */ header->InitialGravity = getFile8Bit(file); /* SpeedFixVersion XOR 0x20 */ header->Version = getFile8Bit(file); /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = getFile8Bit(file); /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */ header->InitialFreezeZonks = getFile8Bit(file); /* number of infotrons needed; 0 means that Supaplex will count the total amount of infotrons in the level and use the low byte of that number (a multiple of 256 infotrons will result in "0 infotrons needed"!) */ header->InfotronsNeeded = getFile8Bit(file); /* number of special ("gravity") port entries below (maximum 10 allowed) */ header->SpecialPortCount = getFile8Bit(file); /* database of properties of up to 10 special ports (6 bytes per port) */ for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; /* high and low byte of the location of a special port; if (x, y) are the coordinates of a port in the field and (0, 0) is the top-left corner, the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice of what may be expected: Supaplex works with a game field in memory which is 2 bytes per tile) */ port->PortLocation = getFile16BitBE(file); /* yes, big endian */ /* change gravity: 1 == "turn on", anything else (0) == "turn off" */ port->Gravity = getFile8Bit(file); /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */ port->FreezeZonks = getFile8Bit(file); /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */ port->FreezeEnemies = getFile8Bit(file); ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */ } /* SpeedByte XOR Highbyte(RandomSeed) */ header->SpeedByte = getFile8Bit(file); /* CheckSum XOR SpeedByte */ header->CheckSumByte = getFile8Bit(file); /* random seed used for recorded demos */ header->DemoRandomSeed = getFile16BitLE(file); /* yes, little endian */ /* auto-determine number of infotrons if it was stored as "0" -- see above */ if (header->InfotronsNeeded == 0) { for (x = 0; x < native_sp_level.width; x++) for (y = 0; y < native_sp_level.height; y++) if (native_sp_level.playfield[x][y] == fiInfotron) header->InfotronsNeeded++; header->InfotronsNeeded &= 0xff; /* only use low byte -- see above */ } /* read raw level header bytes (96 bytes) */ fseek(file, -(SP_HEADER_SIZE), SEEK_CUR); /* rewind file */ for (i = 0; i < SP_HEADER_SIZE; i++) native_sp_level.header_raw_bytes[i] = fgetc(file); /* also load demo tape, if available (only in single level files) */ if (demo_available) { int level_nr = getFile8Bit(file); level_nr &= 0x7f; /* clear highest bit */ level_nr = (level_nr < 1 ? 1 : level_nr > 111 ? 111 : level_nr); native_sp_level.demo.level_nr = level_nr; for (i = 0; i < SP_MAX_TAPE_LEN && !feof(file); i++) { native_sp_level.demo.data[i] = getFile8Bit(file); if (native_sp_level.demo.data[i] == 0xff) /* "end of demo" byte */ { i++; break; } } native_sp_level.demo.length = i; native_sp_level.demo.is_available = (native_sp_level.demo.length > 0); } } boolean LoadNativeLevel_SP(char *filename, int level_pos) { FILE *file; int i, l, x, y; char name_first, name_last; struct LevelInfo_SP multipart_level; int multipart_xpos, multipart_ypos; boolean is_multipart_level; boolean is_first_part; boolean reading_multipart_level = FALSE; boolean use_empty_level = FALSE; LevelInfoType *header = &native_sp_level.header; boolean is_single_level_file = (strSuffixLower(filename, ".sp") || strSuffixLower(filename, ".mpx")); boolean demo_available = is_single_level_file; boolean is_mpx_file = strSuffixLower(filename, ".mpx"); int file_seek_pos = level_pos * SP_STD_LEVEL_SIZE; int level_width = SP_STD_PLAYFIELD_WIDTH; int level_height = SP_STD_PLAYFIELD_HEIGHT; /* always start with reliable default values */ setLevelInfoToDefaults_SP(); copyInternalEngineVars_SP(); if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename); return FALSE; } if (is_mpx_file) { char mpx_chunk_name[4 + 1]; int mpx_version; int mpx_level_count; LevelDescriptor *mpx_level_desc; getFileChunkBE(file, mpx_chunk_name, NULL); if (!strEqual(mpx_chunk_name, "MPX ")) { Error(ERR_WARN, "cannot find MPX ID in file '%s' -- using empty level", filename); return FALSE; } mpx_version = getFile16BitLE(file); if (mpx_version != 1) { Error(ERR_WARN, "unknown MPX version in file '%s' -- using empty level", filename); return FALSE; } mpx_level_count = getFile16BitLE(file); if (mpx_level_count < 1) { Error(ERR_WARN, "no MPX levels found in file '%s' -- using empty level", filename); return FALSE; } if (level_pos >= mpx_level_count) { Error(ERR_WARN, "MPX level not found in file '%s' -- using empty level", filename); return FALSE; } mpx_level_desc = checked_calloc(mpx_level_count * sizeof(LevelDescriptor)); for (i = 0; i < mpx_level_count; i++) { LevelDescriptor *ldesc = &mpx_level_desc[i]; ldesc->Width = getFile16BitLE(file); ldesc->Height = getFile16BitLE(file); ldesc->OffSet = getFile32BitLE(file); /* starts with 1, not with 0 */ ldesc->Size = getFile32BitLE(file); } level_width = mpx_level_desc[level_pos].Width; level_height = mpx_level_desc[level_pos].Height; file_seek_pos = mpx_level_desc[level_pos].OffSet - 1; } /* position file stream to the requested level (in case of level package) */ if (fseek(file, file_seek_pos, SEEK_SET) != 0) { Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return FALSE; } /* there exist Supaplex level package files with multi-part levels which can be detected as follows: instead of leading and trailing dashes ('-') to pad the level name, they have leading and trailing numbers which are the x and y coordinations of the current part of the multi-part level; if there are '?' characters instead of numbers on the left or right side of the level name, the multi-part level consists of only horizontal or vertical parts */ for (l = level_pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++) { LoadNativeLevelFromFileStream_SP(file, level_width, level_height, demo_available); /* check if this level is a part of a bigger multi-part level */ if (is_single_level_file) break; name_first = header->LevelTitle[0]; name_last = header->LevelTitle[SP_LEVEL_NAME_LEN - 1]; is_multipart_level = ((name_first == '?' || (name_first >= '0' && name_first <= '9')) && (name_last == '?' || (name_last >= '0' && name_last <= '9'))); is_first_part = ((name_first == '?' || name_first == '1') && (name_last == '?' || name_last == '1')); if (is_multipart_level) { /* correct leading multipart level meta information in level name */ for (i = 0; i < SP_LEVEL_NAME_LEN && header->LevelTitle[i] == name_first; i++) header->LevelTitle[i] = '-'; /* correct trailing multipart level meta information in level name */ for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && header->LevelTitle[i] == name_last; i--) header->LevelTitle[i] = '-'; } /* ---------- check for normal single level ---------- */ if (!reading_multipart_level && !is_multipart_level) { /* the current level is simply a normal single-part level, and we are not reading a multi-part level yet, so return the level as it is */ break; } /* ---------- check for empty level (unused multi-part) ---------- */ if (!reading_multipart_level && is_multipart_level && !is_first_part) { /* this is a part of a multi-part level, but not the first part (and we are not already reading parts of a multi-part level); in this case, use an empty level instead of the single part */ use_empty_level = TRUE; break; } /* ---------- check for finished multi-part level ---------- */ if (reading_multipart_level && (!is_multipart_level || !strEqualN(header->LevelTitle, multipart_level.header.LevelTitle, SP_LEVEL_NAME_LEN))) { /* we are already reading parts of a multi-part level, but this level is either not a multi-part level, or a part of a different multi-part level; in both cases, the multi-part level seems to be complete */ break; } /* ---------- here we have one part of a multi-part level ---------- */ reading_multipart_level = TRUE; if (is_first_part) /* start with first part of new multi-part level */ { /* copy level info structure from first part */ multipart_level = native_sp_level; /* clear playfield of new multi-part level */ for (x = 0; x < SP_MAX_PLAYFIELD_WIDTH; x++) for (y = 0; y < SP_MAX_PLAYFIELD_HEIGHT; y++) multipart_level.playfield[x][y] = fiSpace; } if (name_first == '?') name_first = '1'; if (name_last == '?') name_last = '1'; multipart_xpos = (int)(name_first - '0'); multipart_ypos = (int)(name_last - '0'); #if 0 printf("----------> part (%d/%d) of multi-part level '%s'\n", multipart_xpos, multipart_ypos, multipart_level.header.LevelTitle); #endif if (multipart_xpos * SP_STD_PLAYFIELD_WIDTH > SP_MAX_PLAYFIELD_WIDTH || multipart_ypos * SP_STD_PLAYFIELD_HEIGHT > SP_MAX_PLAYFIELD_HEIGHT) { Error(ERR_WARN, "multi-part level is too big -- ignoring part of it"); break; } multipart_level.width = MAX(multipart_level.width, multipart_xpos * SP_STD_PLAYFIELD_WIDTH); multipart_level.height = MAX(multipart_level.height, multipart_ypos * SP_STD_PLAYFIELD_HEIGHT); /* copy level part at the right position of multi-part level */ for (x = 0; x < SP_STD_PLAYFIELD_WIDTH; x++) { for (y = 0; y < SP_STD_PLAYFIELD_HEIGHT; y++) { int start_x = (multipart_xpos - 1) * SP_STD_PLAYFIELD_WIDTH; int start_y = (multipart_ypos - 1) * SP_STD_PLAYFIELD_HEIGHT; multipart_level.playfield[start_x + x][start_y + y] = native_sp_level.playfield[x][y]; } } } fclose(file); if (use_empty_level) { setLevelInfoToDefaults_SP(); Error(ERR_WARN, "single part of multi-part level -- using empty level"); } if (reading_multipart_level) native_sp_level = multipart_level; copyInternalEngineVars_SP(); return TRUE; } void SaveNativeLevel_SP(char *filename) { LevelInfoType *header = &native_sp_level.header; FILE *file; int i, x, y; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save native level file '%s'", filename); return; } /* write level playfield (width * height == 60 * 24 tiles == 1440 bytes) */ for (y = 0; y < native_sp_level.height; y++) for (x = 0; x < native_sp_level.width; x++) putFile8Bit(file, native_sp_level.playfield[x][y]); /* write level header (96 bytes) */ WriteUnusedBytesToFile(file, 4); putFile8Bit(file, header->InitialGravity); putFile8Bit(file, header->Version); for (i = 0; i < SP_LEVEL_NAME_LEN; i++) putFile8Bit(file, header->LevelTitle[i]); putFile8Bit(file, header->InitialFreezeZonks); putFile8Bit(file, header->InfotronsNeeded); putFile8Bit(file, header->SpecialPortCount); for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; putFile16BitBE(file, port->PortLocation); putFile8Bit(file, port->Gravity); putFile8Bit(file, port->FreezeZonks); putFile8Bit(file, port->FreezeEnemies); WriteUnusedBytesToFile(file, 1); } putFile8Bit(file, header->SpeedByte); putFile8Bit(file, header->CheckSumByte); putFile16BitLE(file, header->DemoRandomSeed); /* also save demo tape, if available */ if (native_sp_level.demo.is_available) { putFile8Bit(file, native_sp_level.demo.level_nr); for (i = 0; i < native_sp_level.demo.length; i++) putFile8Bit(file, native_sp_level.demo.data[i]); } fclose(file); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Electrons.c0000644000175000017500000003307011347530333021137 0ustar dimkadimka// ---------------------------------------------------------------------------- // Electrons.c // ---------------------------------------------------------------------------- #include "Electrons.h" // ========================================================================== // SUBROUTINE // Animate/move Electrons // ========================================================================== void subAnimateElectrons(int si) { int bx, Tmp; if (SnikSnaksElectronsFrozen == 1) return; if (LowByte(PlayField16[si]) != fiElectron) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subElectronTurnRight(si, bx); // turn right break; case 2: subElectronFromBelow(si, bx); // access si from below break; case 3: subElectronFromRight(si, bx); // access si from right break; case 4: subElectronFromAbove(si, bx); // access si from above break; case 5: subElectronFromLeft(si, bx); // access si from left break; } } void subDrawAnimatedElectrons(int si) { int bx, Tmp; // If SnikSnaksElectronsFrozen = 1 Then Exit Function if (LowByte(PlayField16[si]) != fiElectron) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subDrawElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subDrawElectronTurnRight(si, bx); // turn right break; case 2: subDrawElectronFromBelow(si, bx); // access si from below break; case 3: subDrawElectronFromRight(si, bx); // access si from right break; case 4: subDrawElectronFromAbove(si, bx); // access si from above break; case 5: subDrawElectronFromLeft(si, bx); // access si from left break; } } void subElectronTurnLeft(int si, int bx) { int ax, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7ACD; return; } // loc_g_7A9F: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronTurnLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = (bx + 1) & 0x7; MovHighByte(&PlayField16[si], bx); return; loc_g_7ACD: bl = HighByte(PlayField16[si]); if (bl == 0) goto loc_g_7AE6; if (bl == 2) goto loc_g_7B05; if (bl == 4) goto loc_g_7B24; if (bl == 6) goto loc_g_7B43; return; loc_g_7AE6: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_7AF5; if (LowByte(ax) == fiMurphy) // above is murphy -> explode ExplodeFieldSP(si); return; loc_g_7AF5: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; // 1 field up PlayField16[si] = 0x1018; return; loc_g_7B05: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7B14; if (LowByte(ax) == fiMurphy) // left is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B14: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; loc_g_7B24: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7B33; if (LowByte(ax) == fiMurphy) // below is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B33: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; loc_g_7B43: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_7B55; if (LowByte(ax) == fiMurphy) // right is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B55: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; } void subElectronTurnRight(int si, int bx) { int ax, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7BA3; return; } // loc_g_7B73: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronTurnRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = ((bx + 1) & 0x7) | 8; MovHighByte(&PlayField16[si], bx); return; loc_g_7BA3: bl = HighByte(PlayField16[si]); if (bl == 0x8) goto loc_g_7BBC; if (bl == 0xA) goto loc_g_7C19; if (bl == 0xC) goto loc_g_7BFA; if (bl == 0xE) goto loc_g_7BDB; return; loc_g_7BBC: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_7BCB; if (LowByte(ax) == fiMurphy) // above is murphy -> explode ExplodeFieldSP(si); return; loc_g_7BCB: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; // 1 field up PlayField16[si] = 0x1018; return; loc_g_7BDB: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7BEA; if (LowByte(ax) == fiMurphy) // left is murphy -> explode ExplodeFieldSP(si); return; loc_g_7BEA: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; loc_g_7BFA: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7C09; if (LowByte(ax) == fiMurphy) // below is murphy -> explode ExplodeFieldSP(si); return; loc_g_7C09: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; loc_g_7C19: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_7C2B; if (LowByte(ax) == fiMurphy) // right is murphy -> explode ExplodeFieldSP(si); return; loc_g_7C2B: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; } void subElectronFromBelow(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromBelow(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0xF; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion) { PlayField16[si + FieldWidth] = 0; // electron left that field } if (bl < 8) // electron still goes up { bl = bl + 0x10; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7C84 PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si - 1]; // check left field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 1); // start to turn left return; } // loc_g_7CA4: ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above if (ax == 0) // check if empty { PlayField16[si] = 0x1BB; // mark as "electron leaving" si = si - FieldWidth; // go up! PlayField16[si] = 0x1018; return; } if (LowByte(ax) == fiMurphy) // check for murphy above { ExplodeFieldSP(si); // Explode return; } // loc_g_7CC6: ax = PlayField16[si + 1]; // check right field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 9); // start to turn right return; } // loc_g_7CE0: // else: no way to go, start turning around MovHighByte(&PlayField16[si], 1); } void subElectronFromRight(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x17; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion) { PlayField16[si + 1] = 0; // electron left that field } // loc_g_7D1D: if (bl < 8) // sniksnak still goes left { bl = bl + 0x18; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7D2A: PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy? { MovHighByte(&PlayField16[si], 3); // yes -> turn left down return; } // loc_g_7D4A: ax = PlayField16[si - 1]; // check left, etc ... see the comments on subElectronFromBelow() if (ax == 0) { PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; } // loc_g_7D61: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7D6C: ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xF); return; } // loc_g_7D86: MovHighByte(&PlayField16[si], 3); } void subElectronFromAbove(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromAbove(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x1F; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion) { PlayField16[si - FieldWidth] = 0; // electron left that field } if (bl < 8) // electron still goes down { bl = bl + 0x20; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7DD7 PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si + 1]; // check right if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 5); return; } // loc_g_7DF7: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0) { PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; } // loc_g_7E0E: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7E19: ax = PlayField16[si - 1]; // check left if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xD); return; } // loc_g_7E33: MovHighByte(&PlayField16[si], 5); } void subElectronFromLeft(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x27; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion) { PlayField16[si - 1] = 0; // electron left that field } if (bl < 8) // electron still goes right { bl = bl + 0x28; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7E7E: PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 7); return; } // loc_g_7E9E: ax = PlayField16[si + 1]; // check right(straight on) if (ax == 0) { PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; return; } // loc_g_7EB5: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7EC0: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xB); return; } // loc_g_7A69: MovHighByte(&PlayField16[si], 7); } void subDrawElectronTurnLeft(int si, int bx) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronTurnRight(int si, int bx) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniElectron, 0x10 - bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromBelow(int si, int bx) { int X, Y; bx = bx - 0xF; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si + FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y - bx * TwoPixels, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromRight(int si, int bx) { int X, Y; bx = bx - 0x17; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - bx * TwoPixels, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromAbove(int si, int bx) { int X, Y; bx = bx - 0x1F; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + bx * TwoPixels, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromLeft(int si, int bx) { int X, Y; bx = bx - 0x27; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + bx * TwoPixels, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DoGameStuff.h0000644000175000017500000000075411375770273021367 0ustar dimkadimka// ---------------------------------------------------------------------------- // DoGameStuff.h // ---------------------------------------------------------------------------- #ifndef DOGAMESTUFF_H #define DOGAMESTUFF_H #include "global.h" #if 1 extern int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; extern byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; #else extern byte *AnimationSubTable; extern int *AnimationPosTable; #endif extern void subDoGameStuff(); #endif /* DOGAMESTUFF_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/MainForm.h0000644000175000017500000000124211347536351020720 0ustar dimkadimka// ---------------------------------------------------------------------------- // MainForm.h // ---------------------------------------------------------------------------- #ifndef MAINFORM_H #define MAINFORM_H #include "global.h" extern void DrawFrameIfNeeded(); extern void DisplayLevel(); extern void DrawField(int X, int Y); extern void DrawFieldAnimated(int X, int Y); extern void DrawFieldNoAnimated(int X, int Y); extern void DrawSprite(int X, int Y, int SpritePos); extern void DrawImage(int X, int Y, int graphic); extern void SetDisplayRegion(); extern void SetScrollEdges(); extern void menPlay_Click(); extern void Form_Load(); #endif /* MAINFORM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Makefile0000644000175000017500000000425311375752375020513 0ustar dimkadimka# ============================================================================= # Makefile for native Supaplex engine for Rocks'n'Diamonds (game_sp) # ----------------------------------------------------------------------------- # (c) 1995-2009 Holger Schemel # ----------------------------------------------------------------------------- # based on MegaPlex version 0.5 beta release xmas 2001 by Frank Schindler, # based on the Speed Fix 6.3+ by Herman Perk, # based on original Supaplex by Michael Stopp & Philip Jespersen # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = init.c \ file.c \ main.c \ vb_lib.c \ \ ASM.c \ BugsTerminals.c \ DDScrollBuffer.c \ DDSpriteBuffer.c \ Display.c \ DoGameStuff.c \ Electrons.c \ Explosions.c \ Globals.c \ Infotrons.c \ InitGameConditions.c \ Input.c \ MainForm.c \ MainGameLoop.c \ Murphy.c \ OrangeDisk.c \ SnikSnaks.c \ Sound.c \ Zonk.c OBJS = init.o \ file.o \ main.o \ vb_lib.o \ \ ASM.o \ BugsTerminals.o \ DDScrollBuffer.o \ DDSpriteBuffer.o \ Display.o \ DoGameStuff.o \ Electrons.o \ Explosions.o \ Globals.o \ Infotrons.o \ InitGameConditions.o \ Input.o \ MainForm.o \ MainGameLoop.o \ Murphy.o \ OrangeDisk.o \ SnikSnaks.o \ Sound.o \ Zonk.o GAME_SP = game_sp.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(GAME_SP) $(GAME_SP): $(OBJS) $(AR) cru $(GAME_SP) $(OBJS) $(RANLIB) $(GAME_SP) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(GAME_SP) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/OrangeDisk.c0000644000175000017500000000414511347530417021233 0ustar dimkadimka// ---------------------------------------------------------------------------- // OrangeDisk.c // ---------------------------------------------------------------------------- #include "OrangeDisk.h" // ========================================================================== // SUBROUTINE // Animate/move orange disks (falling) // ========================================================================== void subAnimateOrangeDisks(int si) { int ax, bl, dx, X, Y; ax = PlayField16[si]; if (LowByte(ax) != fiOrangeDisk) return; if (ax >= 0x3008) // disk is falling goto loc_g_2804; if (ax >= 0x2008) // disk is in wait state before falling goto loc_g_27DA; if (PlayField16[si + FieldWidth] == 0) goto loc_g_27CF; return; loc_g_27CF: // below is empty -> disk may start to fall MovHighByte(&PlayField16[si], 0x20); MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk); return; loc_g_27DA: if (PlayField16[si + FieldWidth] == 0) { PlayField16[si] = fiOrangeDisk; return; } // loc_g_27E8: bl = HighByte(PlayField16[si]) + 1; if (bl == 0x22) // wait phase is finished bl = 0x30; MovHighByte(&PlayField16[si], bl); return; loc_g_2804: // disk is falling // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dx = HighByte(PlayField16[si]) & 0x7; X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniOrangeDisk, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if ((bl & 0x7) != 0) { MovHighByte(&PlayField16[si], bl); return; } PlayField16[si] = 0; PlayField16[si + FieldWidth] = fiOrangeDisk; si = si + FieldWidth; if (PlayField16[si + FieldWidth] == 0) { MovHighByte(&PlayField16[si], 0x30); // go on falling down MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk); return; } // loc_g_2867: if (LowByte(PlayField16[si + FieldWidth]) == fiExplosion) return; ExplodeFieldSP(si); // Explode } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DDSpriteBuffer.c0000644000175000017500000000205311362272640022007 0ustar dimkadimka// ---------------------------------------------------------------------------- // DDSpriteBuffer.c // ---------------------------------------------------------------------------- #include "DDSpriteBuffer.h" static void Blt(int pX, int pY, Bitmap *bitmap, int SpriteX, int SpriteY) { int scx = (mScrollX_last < 0 ? 0 : mScrollX_last); int scy = (mScrollY_last < 0 ? 0 : mScrollY_last); int sx1 = scx - 2 * TILEX; int sy1 = scy - 2 * TILEY; int sx2 = scx + SXSIZE + 1 * TILEX; int sy2 = scy + SYSIZE + 1 * TILEY; int sx = pX - sx1; int sy = pY - sy1; if (NoDisplayFlag) return; /* do not draw fields that are outside the visible screen area */ if (pX < sx1 || pX > sx2 || pY < sy1 || pY > sy2) return; BlitBitmap(bitmap, bitmap_db_field_sp, SpriteX, SpriteY, TILEX, TILEY, sx, sy); } void DDSpriteBuffer_BltImg(int pX, int pY, int graphic, int sync_frame) { struct GraphicInfo_SP g; if (NoDisplayFlag) return; getGraphicSource_SP(&g, graphic, sync_frame, -1, -1); Blt(pX, pY, g.bitmap, g.src_x, g.src_y); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/MainForm.c0000644000175000017500000001334711362702444020717 0ustar dimkadimka// ---------------------------------------------------------------------------- // MainForm.c // ---------------------------------------------------------------------------- #include "MainForm.h" static void DrawFrame(int Delta); static void ReStretch(); void DrawField(int X, int Y); void DrawFieldAnimated(int X, int Y); void DrawFieldNoAnimated(int X, int Y); void DrawFrameIfNeeded() { DrawFrame(0); /* !!! CHECK THIS !!! */ #if 1 if (! menBorder) DrawFrame(1); #endif } void DisplayLevel() { int X, Y; if (! LevelLoaded) return; ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); #if 1 ClearRectangle(bitmap_db_field_sp, 0, 0, FXSIZE, FYSIZE); #else ClearRectangle(bitmap_db_field_sp, 0, 0, MAX_BUF_XSIZE * TILEX, MAX_BUF_YSIZE * TILEY); #endif #if 1 SetDisplayRegion(); #endif DrawFrameIfNeeded(); if (bPlaying) { for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawFieldNoAnimated(X, Y); for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawFieldAnimated(X, Y); } else { for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawField(X, Y); } } void Form_Load() { InitGlobals(); ReStretch(); } static void DrawFrame(int Delta) { int i, LX, tY, RX, BY; LX = -1 + Delta; tY = -1 + Delta; RX = FieldWidth - Delta; BY = FieldHeight - Delta; DrawImage(LX, tY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(LX, BY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(RX, tY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(RX, BY, (Delta > 0 ? imgFrameCorner : aniSpace)); for (i = LX + 1; i <= RX - 1; i++) { DrawImage(i, tY, (Delta > 0 ? imgFrameHorizontal : aniSpace)); DrawImage(i, BY, (Delta > 0 ? imgFrameHorizontal : aniSpace)); } for (i = tY + 1; i <= BY - 1; i++) { DrawImage(LX, i, (Delta > 0 ? imgFrameVertical : aniSpace)); DrawImage(RX, i, (Delta > 0 ? imgFrameVertical : aniSpace)); } if (Delta > 0) { // ... // ClearRectangle(bitmap_db_field_sp, } } static void RestoreFrame() { int i, LX, tY, RX, BY; LX = 0; tY = 0; RX = FieldWidth - 1; BY = FieldHeight - 1; for (i = LX; i <= RX; i++) { DrawField(i, tY); DrawField(i, BY); } for (i = tY + 1; i <= BY - 1; i++) { DrawField(LX, i); DrawField(RX, i); } } void SetDisplayRegion() { if (! menBorder) { DisplayMinX = 1; DisplayMinY = 1; DisplayMaxX = FieldWidth - 2; DisplayMaxY = FieldHeight - 2; if (LevelLoaded) DrawFrame(1); } else { DisplayMinX = 0; DisplayMinY = 0; DisplayMaxX = FieldWidth - 1; DisplayMaxY = FieldHeight - 1; if (LevelLoaded) RestoreFrame(); } } void menPlay_Click() { bPlaying = True; subFetchAndInitLevelB(); ReStretch(); subMainGameLoop_Init(); #if 1 return; #endif bPlaying = False; subFetchAndInitLevel(); } static void ReStretch() { if (LevelLoaded) { SetDisplayRegion(); SetScrollEdges(); ScrollTo(ScrollX, ScrollY); DisplayLevel(); } subCalculateScreenScrollPos(); ScrollTo(ScreenScrollXPos, ScreenScrollYPos); } void SetScrollEdges() { int border1_offset = (menBorder ? 1 : 2); int border2_offset = (menBorder ? 0 : TILESIZE / 2); /* scroll correction for border frame (1 tile) or border element (2 tiles) */ ScrollMinX = 0; ScrollMinY = 0; ScrollMaxX = (DisplayMaxX + border1_offset) * TILEX - SXSIZE; ScrollMaxY = (DisplayMaxY + border1_offset) * TILEY - SYSIZE; /* scroll correction for border element (half tile on left and right side) */ ScrollMinX += border2_offset; ScrollMinY += border2_offset; ScrollMaxX -= border2_offset; ScrollMaxY -= border2_offset; /* scroll correction for even number of visible tiles (half tile shifted) */ ScrollMinX -= game_sp.scroll_xoffset; ScrollMaxX -= game_sp.scroll_xoffset; ScrollMinY -= game_sp.scroll_yoffset; ScrollMaxY -= game_sp.scroll_yoffset; #if 0 printf("::: (%ld, %ld), (%ld, %ld) -> (%d, %d), (%d, %d)\n", DisplayMinX, DisplayMinY, DisplayMaxX, DisplayMaxY, ScrollMinX, ScrollMinY, ScrollMaxX, ScrollMaxY); #endif } void DrawField(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); if (Tmp < fiFirst || Tmp > fiLast) Tmp = fiSpace; if (Tmp == fiRAM || Tmp == fiHardWare || Tmp == fiBug || Tmp == fiWallSpace) Tmp = DisPlayField[tsi]; subCopyImageToScreen(tsi, fiGraphic[Tmp]); if (Tmp != fiSpace && Tmp != fiSnikSnak && Tmp != fiElectron) GfxGraphic[X][Y] = fiGraphic[Tmp]; } void DrawFieldAnimated(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); switch (Tmp) { case fiSnikSnak: subDrawAnimatedSnikSnaks(tsi); break; case fiElectron: subDrawAnimatedElectrons(tsi); break; default: break; } } void DrawFieldNoAnimated(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); switch (Tmp) { case fiSnikSnak: subCopyImageToScreen(tsi, aniSpace); break; case fiElectron: subCopyImageToScreen(tsi, aniSpace); break; default: #if 1 DrawField(X, Y); #else if (Tmp < fiFirst || Tmp > fiLast) Tmp = fiSpace; if (Tmp == fiRAM || Tmp == fiHardWare || Tmp == fiBug || Tmp == fiWallSpace) Tmp = DisPlayField[tsi]; subCopyImageToScreen(tsi, fiGraphic[Tmp]); if (Tmp != fiSpace && Tmp != fiSnikSnak && Tmp != fiElectron) GfxGraphic[X][Y] = fiGraphic[Tmp]; #endif break; } } void DrawImage(int X, int Y, int graphic) { DDSpriteBuffer_BltImg(StretchWidth * X, StretchWidth * Y, graphic, 0); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/OrangeDisk.h0000644000175000017500000000046511347526201021235 0ustar dimkadimka// ---------------------------------------------------------------------------- // OrangeDisk.h // ---------------------------------------------------------------------------- #ifndef ORANGEDISK_H #define ORANGEDISK_H #include "global.h" extern void subAnimateOrangeDisks(int); #endif /* ORANGEDISK_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DDScrollBuffer.c0000644000175000017500000002062311363001310021763 0ustar dimkadimka// ---------------------------------------------------------------------------- // DDScrollBuffer.c // ---------------------------------------------------------------------------- #include "DDScrollBuffer.h" #include long mScrollX, mScrollY; long mScrollX_last, mScrollY_last; #if 1 long ScreenBuffer[2 + MAX_PLAYFIELD_WIDTH + 2][2 + MAX_PLAYFIELD_HEIGHT + 2]; boolean redraw[2 + MAX_PLAYFIELD_WIDTH + 2][2 + MAX_PLAYFIELD_HEIGHT + 2]; #else long ScreenBuffer[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; #endif void RestorePlayfield() { int x1 = mScrollX / TILEX - 2; int y1 = mScrollY / TILEY - 2; int x2 = mScrollX / TILEX + (SCR_FIELDX - 1) + 2; int y2 = mScrollY / TILEY + (SCR_FIELDY - 1) + 2; int x, y; DrawFrameIfNeeded(); for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { DrawFieldNoAnimated(x, y); DrawFieldAnimated(x, y); } } } } static void ScrollPlayfield(int dx, int dy) { int x1 = mScrollX_last / TILEX - 2; int y1 = mScrollY_last / TILEY - 2; int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2; int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2; int x, y; BlitBitmap(bitmap_db_field_sp, bitmap_db_field_sp, TILEX * (dx == -1), TILEY * (dy == -1), (MAX_BUF_XSIZE * TILEX) - TILEX * (dx != 0), (MAX_BUF_YSIZE * TILEY) - TILEY * (dy != 0), TILEX * (dx == 1), TILEY * (dy == 1)); /* when scrolling the whole playfield, do not redraw single tiles */ for (x = 0; x < MAX_BUF_XSIZE; x++) for (y = 0; y < MAX_BUF_YSIZE; y++) redraw[x][y] = FALSE; redraw_tiles = 0; DrawFrameIfNeeded(); for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { int sx = x - x1; int sy = y - y1; int tsi = GetSI(x, y); long id = ((PlayField16[tsi]) | (PlayField8[tsi] << 16) | (DisPlayField[tsi] << 24)); if ((dx == -1 && x == x2) || (dx == +1 && x == x1) || (dy == -1 && y == y2) || (dy == +1 && y == y1)) { DrawFieldNoAnimated(x, y); DrawFieldAnimated(x, y); } ScreenBuffer[sx][sy] = id; } } } } static void ScrollPlayfieldIfNeededExt(boolean reset) { if (reset) { mScrollX_last = -1; mScrollY_last = -1; return; } if (mScrollX_last == -1 || mScrollY_last == -1) { #if 1 mScrollX_last = (mScrollX / TILESIZE) * TILESIZE; mScrollY_last = (mScrollY / TILESIZE) * TILESIZE; #else mScrollX_last = mScrollX; mScrollY_last = mScrollY; #endif return; } /* check if scrolling the playfield requires redrawing the viewport bitmap */ if ((mScrollX != mScrollX_last || mScrollY != mScrollY_last) && (ABS(mScrollX - mScrollX_last) >= TILEX || ABS(mScrollY - mScrollY_last) >= TILEY)) { int dx = (ABS(mScrollX - mScrollX_last) < TILEX ? 0 : mScrollX < mScrollX_last ? 1 : mScrollX > mScrollX_last ? -1 : 0); int dy = (ABS(mScrollY - mScrollY_last) < TILEY ? 0 : mScrollY < mScrollY_last ? 1 : mScrollY > mScrollY_last ? -1 : 0); mScrollX_last -= dx * TILEX; mScrollY_last -= dy * TILEY; ScrollPlayfield(dx, dy); } } static void ScrollPlayfieldIfNeeded() { ScrollPlayfieldIfNeededExt(FALSE); } void InitScrollPlayfield() { ScrollPlayfieldIfNeededExt(TRUE); } void UpdatePlayfield(boolean force_redraw) { int x, y; #if 1 int num_redrawn = 0; #endif for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { int element = LowByte(PlayField16[GetSI(x, y)]); int graphic = GfxGraphic[x][y]; int sync_frame = GfxFrame[x][y]; boolean redraw = force_redraw; #if 0 redraw = TRUE; // !!! TEST ONLY -- ALWAYS REDRAW !!! #endif if (graphic < 0) { GfxGraphicLast[x][y] = GfxGraphic[x][y]; continue; } if (element != GfxElementLast[x][y] && graphic == GfxGraphicLast[x][y]) { /* element changed, but not graphic => disable updating graphic */ GfxElementLast[x][y] = element; GfxGraphicLast[x][y] = GfxGraphic[x][y] = -1; continue; } if (graphic != GfxGraphicLast[x][y]) // new graphic { redraw = TRUE; GfxElementLast[x][y] = element; GfxGraphicLast[x][y] = GfxGraphic[x][y]; sync_frame = GfxFrame[x][y] = 0; } else if (isNextAnimationFrame_SP(graphic, sync_frame)) // new frame { redraw = TRUE; } if (redraw) { int sx = x * StretchWidth; int sy = y * StretchWidth; #if 0 printf("::: REDRAW (%d, %d): %d, %d\n", x, y, graphic, sync_frame); #endif DDSpriteBuffer_BltImg(sx, sy, graphic, sync_frame); #if 1 num_redrawn++; #endif } } } #if 0 printf("::: FRAME %d: %d redrawn\n", FrameCounter, num_redrawn); #endif } /* copy the entire screen to the window at the scroll position */ void BlitScreenToBitmap_SP(Bitmap *target_bitmap) { int px = 2 * TILEX + (mScrollX - mScrollX_last) % TILEX; int py = 2 * TILEY + (mScrollY - mScrollY_last) % TILEY; int sx, sy, sxsize, sysize; #if 0 printf("::: %d, %d / %d, %d / %ld, %ld (%ld, %ld) / %d, %d\n", MurphyScreenXPos, MurphyScreenYPos, ScreenScrollXPos, ScreenScrollYPos, mScrollX, mScrollY, mScrollX_last, mScrollY_last, px, py); #endif int xsize = SXSIZE; int ysize = SYSIZE; int full_xsize = (FieldWidth - (menBorder ? 0 : 1)) * TILEX; int full_ysize = (FieldHeight - (menBorder ? 0 : 1)) * TILEY; sxsize = (full_xsize < xsize ? full_xsize : xsize); sysize = (full_ysize < ysize ? full_ysize : ysize); sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0); sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0); /* scroll correction for even number of visible tiles (half tile shifted) */ px += game_sp.scroll_xoffset; py += game_sp.scroll_yoffset; #if 1 if (ExplosionShakeMurphy != 0) { px += TILEX / 2 - GetSimpleRandom(TILEX + 1); py += TILEY / 2 - GetSimpleRandom(TILEX + 1); } #endif BlitBitmap(bitmap_db_field_sp, target_bitmap, px, py, sxsize, sysize, sx, sy); } void BackToFront_SP(void) { static boolean scrolling_last = FALSE; int left = mScrollX / TILEX; int top = mScrollY / TILEY; boolean scrolling = (mScrollX % TILEX != 0 || mScrollY % TILEY != 0); int x, y; SyncDisplay(); if (1 || redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last) { BlitScreenToBitmap_SP(window); } else { for (x = 0; x < SCR_FIELDX; x++) { for (y = 0; y < SCR_FIELDY; y++) { int xx = (left + x) % MAX_BUF_XSIZE; int yy = (top + y) % MAX_BUF_YSIZE; if (redraw[xx][yy]) BlitBitmap(bitmap_db_field_sp, window, xx * TILEX, yy * TILEY, TILEX, TILEY, SX + x * TILEX, SY + y * TILEY); } } } FlushDisplay(); for (x = 0; x < MAX_BUF_XSIZE; x++) for (y = 0; y < MAX_BUF_YSIZE; y++) redraw[x][y] = FALSE; redraw_tiles = 0; scrolling_last = scrolling; } void DDScrollBuffer_ScrollTo(int X, int Y) { if (NoDisplayFlag) return; ScrollX = mScrollX = X; ScrollY = mScrollY = Y; ScrollPlayfieldIfNeeded(); } void DDScrollBuffer_ScrollTowards(int X, int Y, double Step) { double dx, dY, r; if (NoDisplayFlag) return; dx = X - mScrollX; dY = Y - mScrollY; r = Sqr(dx * dx + dY * dY); if (r == 0) // we are there already return; if (Step < r) r = Step / r; else r = 1; ScrollX = mScrollX = mScrollX + dx * r; ScrollY = mScrollY = mScrollY + dY * r; ScrollPlayfieldIfNeeded(); } void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS) { double dx, dY; long dT, StepCount; double T, tStep; long oldX, oldY, maxD; static boolean AlreadyRunning = False; if (NoDisplayFlag) return; if (AlreadyRunning) return; AlreadyRunning = True; dx = X - mScrollX; dY = Y - mScrollY; maxD = (Abs(dx) < Abs(dY) ? Abs(dY) : Abs(dx)); StepCount = FPS * (TimeMS / (double)1000); if (StepCount > maxD) StepCount = maxD; if (StepCount == 0) StepCount = 1; dT = 1000 / FPS; tStep = (double)1 / StepCount; oldX = mScrollX; oldY = mScrollY; for (T = (double)tStep; T <= (double)1; T += tStep) { ScrollX = mScrollX = oldX + T * dx; ScrollY = mScrollY = oldY + T * dY; } ScrollX = mScrollX = X; ScrollY = mScrollY = Y; AlreadyRunning = False; ScrollPlayfieldIfNeeded(); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Zonk.h0000644000175000017500000000043111375342500020120 0ustar dimkadimka// ---------------------------------------------------------------------------- // Zonk.h // ---------------------------------------------------------------------------- #ifndef ZONK_H #define ZONK_H #include "global.h" extern void subAnimateZonks(int si); #endif /* ZONK_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/BugsTerminals.h0000644000175000017500000000106411375770332021771 0ustar dimkadimka// ---------------------------------------------------------------------------- // BugsTerminals.h // ---------------------------------------------------------------------------- #ifndef BUGSTERMINALS_H #define BUGSTERMINALS_H #include "global.h" #if 1 extern byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; #else extern byte *TerminalState; #endif extern int TerminalMaxCycles; extern void subAnimateBugs(int si); extern void subAnimateTerminals(int si); extern void subRandomize(); extern int subGetRandomNumber(); #endif /* BUGSTERMINALS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Input.c0000644000175000017500000000205511347527762020313 0ustar dimkadimka// ---------------------------------------------------------------------------- // Input.c // ---------------------------------------------------------------------------- #include "Input.h" int map_key_RND_to_SP(int key) { if (key & KEY_BUTTON) { return (key & MV_UP ? keySpaceUp : key & MV_LEFT ? keySpaceLeft : key & MV_DOWN ? keySpaceDown : key & MV_RIGHT ? keySpaceRight : keySpace); } else { return (key & MV_UP ? keyUp : key & MV_LEFT ? keyLeft : key & MV_DOWN ? keyDown : key & MV_RIGHT ? keyRight : keyNone); } } int map_key_SP_to_RND(int key) { return (key == keyUp ? MV_UP : key == keyLeft ? MV_LEFT : key == keyDown ? MV_DOWN : key == keyRight ? MV_RIGHT : key == keySpaceUp ? KEY_BUTTON | MV_UP : key == keySpaceLeft ? KEY_BUTTON | MV_LEFT : key == keySpaceDown ? KEY_BUTTON | MV_DOWN : key == keySpaceRight ? KEY_BUTTON | MV_RIGHT : key == keySpace ? KEY_BUTTON : MV_NONE); } void subProcessKeyboardInput(byte action) { DemoKeyCode = map_key_RND_to_SP(action); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/main_sp.h0000644000175000017500000000607211362272455020643 0ustar dimkadimka#ifndef MAIN_SP_H #define MAIN_SP_H /* ========================================================================= */ /* external functions and definitions imported from main program to game_sp */ /* ========================================================================= */ #include "../engines.h" #include "../conf_gfx.h" /* ========================================================================= */ /* functions and definitions that are exported from game_sp to main program */ /* ========================================================================= */ #include "export.h" /* ========================================================================= */ /* internal functions and definitions that are not exported to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* screen sizes and positions for SP engine */ #define ORIG_TILESIZE 16 #define ZOOM_FACTOR 2 #define TILESIZE (ORIG_TILESIZE * ZOOM_FACTOR) #define TILEX TILESIZE #define TILEY TILESIZE #define ORIG_SCR_MENUX 20 #define ORIG_SCR_MENUY 12 #define SCR_MENUX 17 #define SCR_MENUY 12 #if 1 extern int SCR_FIELDX, SCR_FIELDY; #else #define SCR_FIELDX 17 #define SCR_FIELDY 17 #endif #define MAX_BUF_XSIZE (2 + SCR_FIELDX + 2) #define MAX_BUF_YSIZE (2 + SCR_FIELDY + 2) /* often used screen positions */ #if 1 extern int SX, SY; #else #define SX 8 #define SY 8 #endif #define SXSIZE (SCR_FIELDX * TILEX) #define SYSIZE (SCR_FIELDY * TILEY) #define FXSIZE (MAX_BUF_XSIZE * TILEX) #define FYSIZE (MAX_BUF_YSIZE * TILEY) #if 1 extern int REAL_SX, REAL_SY; #else #define REAL_SX (SX - 2) #define REAL_SY (SY - 2) #endif #define FULL_SXSIZE (2 + SXSIZE + 2) #define FULL_SYSIZE (2 + SYSIZE + 2) /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* exported variables */ /* ------------------------------------------------------------------------- */ extern struct LevelInfo_SP native_sp_level; extern Bitmap *bitmap_db_field_sp; extern int GfxElementLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphicLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphic[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxFrame[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ #endif /* MAIN_SP_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Zonk.c0000644000175000017500000002774511375342553020144 0ustar dimkadimka// ---------------------------------------------------------------------------- // Zonk.c // ---------------------------------------------------------------------------- #include "Zonk.h" void subCleanUpForZonksAbove(int si); // static char *VB_Name = "modZonk"; // --- Option Explicit // ========================================================================== // SUBROUTINE // Animate Zonks (falling) // ========================================================================== void subAnimateZonks(int si) { int tFld; // PseudoRegisters: // int ax, bx, cx, dx, di, X, Y; int ax, bx, dx, X, Y; // int ah, bh, ch, dh, al, bl, cl, dl; int al, bl; tFld = PlayField16[si]; if ((tFld & 0xFF) != fiZonk) return; if (tFld == fiZonk) { if (FreezeZonks == 2) // Do Zonks fall? (debug) return; ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60) if (ax == 0) goto loc_g_0D64; if (ax == fiZonk) goto loc_g_0D35; if (ax == fiInfotron) goto loc_g_0D35; if (ax == fiRAM) goto loc_g_0D35; return; loc_g_0D35: // Case fiZonk, fiInfotron, fiRAM ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_0D6B; loc_g_0D4C: ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_0D81; return; loc_g_0D64: // Case fiSpace MovHighByte(&PlayField16[si], 0x40); goto loc_g_0DA5; loc_g_0D6B: // roll left? if (PlayField16[si - 1] == 0) goto loc_g_0D74; goto loc_g_0D4C; loc_g_0D74: MovHighByte(&PlayField16[si], 0x50); PlayField16[si - 1] = 0x8888; goto loc_g_0DA5; loc_g_0D81: // roll right? if (PlayField16[si + 1] == 0) goto loc_g_0D98; if (PlayField16[si + 1] != 0x9999) // wow right is different from left! return; if (LowByte(PlayField16[si - FieldWidth + 1]) != 1) return; loc_g_0D98: MovHighByte(&PlayField16[si], 0x60); PlayField16[si + 1] = 0x8888; } // tFld = fiZonk loc_g_0DA5: // from now on the zonk is definitely moving, // maybe the sequence is in an advanced frame // or just beeing initialized due to the code above bl = HighByte(PlayField16[si]); bx = 0; MovLowByte(&bx, bl); al = bl & 0xF0; if (al == 0x10) // zonk comes falling from above goto loc_g_0DE8; if (al == 0x20) // zonk comes rolling from right to left goto loc_g_0F83; if (al == 0x30) // zonk comes rolling from left to right goto loc_g_0FE8; if (FreezeZonks == 2) return; if (al == 0x40) // zonk falls straight down goto loc_g_104D; if (al == 0x50) // zonk rolls left goto loc_g_107B; if (al == 0x60) // zonk rolls right goto loc_g_10E9; if (al == 0x70) // intermediate state goto loc_g_1157; return; loc_g_0DE8: // zonk comes falling from above // To Do: draw zonk falling from above // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); dx = bl & 0x7; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniZonk, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x16) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si - FieldWidth); return; } // loc_g_0E2B: if (bl < 0x18) { MovHighByte(&PlayField16[si], bl); return; } // loc_g_0E35: MovHighByte(&PlayField16[si], 0); // zonk arrived at the field if ((FreezeZonks & 0xFF) == 2) return; // loc_g_0E42: // now check if the zonk may go on falling somehow ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty!-> go on falling 'loc_g_0E4C: goto loc_g_0EDD; if (ax == 0x9999) // below is only temporarily used ' loc_g_0E57: goto loc_g_0EDD; if ((ax & 0xFF) == fiMurphy) // Murphy dies 'loc_g_0E61: goto loc_g_0F14; if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies 'loc_g_0E6B: goto loc_g_0F6E; if (ax == 0x2BB) // loc_g_0E76: goto loc_g_0F36; if (ax == 0x4BB) // loc_g_0E81: goto loc_g_0F52; if ((ax & 0xFF) == fiElectron) // Electron cracked! 'loc_g_0E8B: goto loc_g_0F6E; if (ax == fiOrangeDisk) // OrangeDisk explodes 'loc_g_0E95: goto loc_g_0F75; #if 1 // play the zonk sound, 'cause zonk hits something "hard" subSoundFX(si, fiZonk, actImpact); #else subSoundFXZonk(); // play the zonk sound,'cause zonk hits something "hard" #endif if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) return; // loc_g_0EAE: ' Zonk rolls somewhere ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left goto loc_g_0EEA; ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right goto loc_g_0F00; return; loc_g_0EDD: // go on falling down? PlayField16[si] = 0x7001; // go into intermediate waitstate PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access" return; loc_g_0EEA: // test if zonk may roll left // This if(if true) jumps up far above // to the according rountine for fixed zonks! if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4: goto loc_g_0D4C; MovHighByte(&PlayField16[si], 0x50); // zonk rolls left PlayField16[si - 1] = 0x8888; // mark as zonk accessing? return; loc_g_0F00: // test if zonk may roll right if (PlayField16[si + 1] != 0) // loc_g_0F08: return; MovHighByte(&PlayField16[si], 0x60); // zonk rolls right PlayField16[si + 1] = 0x8888; // mark as zonk accessing? return; loc_g_0F14: // Murphy dies, but not in any case bl = HighByte(PlayField16[si + FieldWidth]); if (bl == 0xE || bl == 0xF || bl == 0x28) return; if (bl == 0x29 || bl == 0x25 || bl == 0x26) return; loc_g_0F36: // ?? ax = LowByte(PlayField16[si + FieldWidth - 1]); if (ax == fiElectron) // loc_g_0F43: PlayField16[si + FieldWidth] = fiElectron; if (ax != 0x1F) PlayField16[si + FieldWidth - 1] = 0; goto loc_g_0F6E; loc_g_0F52: // ?? ax = LowByte(PlayField16[si + FieldWidth + 1]); if (ax == fiElectron) // loc_g_0F5F: PlayField16[si + FieldWidth] = fiElectron; if (ax != 0x1F) PlayField16[si + FieldWidth + 1] = 0; goto loc_g_0F6E; loc_g_0F6E: // someone dies/explodes si = si + FieldWidth; // 1 field down ExplodeFieldSP(si); // Explode return; loc_g_0F75: // OrangeDisk explodes next cycle si = si + FieldWidth; // 1 field down PlayField8[si] = fiHardWare; return; loc_g_0F83: // zonk comes rolling from right to left // To Do: draw zonk rolling from right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniZonkRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // get and increment sequence# if (bl == 0x24) PlayField16[si + 1] = 0xAAAA; if (bl == 0x26) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si + 1); } else if (bl < 0x28) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk } return; loc_g_0FE8: // zonk comes rolling from left to right // To Do: draw zonk rolling from left // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniZonkRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x34) PlayField16[si - 1] = 0xAAAA; if (bl == 0x36) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si - 1); } else if (bl < 0x38) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk } return; loc_g_104D: // zonk falls straight down bl = bl + 1; if (bl < 0x42) { MovHighByte(&PlayField16[si], bl); } else if (PlayField16[si + FieldWidth] != 0) { bl = bl - 1; // stay waiting MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; // mark as "zonk leaving" si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // go falling } return; loc_g_107B: // zonk rolls left // To Do: draw zonk rolling to left // according to position in (bl And &H0F) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0xF) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniZonkRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence# if (bl < 0x52) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth - 1] != 0) goto loc_g_10E2; if (PlayField16[si - 1] != 0) { if (PlayField16[si - 1] != 0x8888) goto loc_g_10E2; } // loc_g_10C8: PlayField16[si] = 0xFFFF; si = si - 1; // 1 field left PlayField16[si] = 0x2201; PlayField16[si + FieldWidth] = 0xFFFF; return; loc_g_10E2: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_10E9: // zonk rolls right // To Do: draw zonk rolling to right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniZonkRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl < 0x62) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth + 1] != 0) goto loc_g_1150; if (PlayField16[si + 1] != 0) { if (PlayField16[si + 1] != 0x8888) goto loc_g_1150; } PlayField16[si] = 0xFFFF; si = si + 1; PlayField16[si] = 0x3201; PlayField16[si + FieldWidth] = 0xFFFF; return; loc_g_1150: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_1157: // intermediate state ax = PlayField16[si + FieldWidth]; if (ax == 0 || ax == 0x9999) { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // start falling down goto loc_g_0DE8; } return; } // subAnimateZonks endp void subCleanUpForZonksAbove(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; if (PlayField16[si - FieldWidth] != 0) { if (PlayField16[si - FieldWidth] != 0x9999) return; if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiInfotron) return; } // loc_g_1674: if (PlayField16[si - FieldWidth - 1] != fiZonk) { if (PlayField16[si - FieldWidth + 1] != fiZonk) return; goto loc_g_16A7; } ax = PlayField16[si - 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth - 1] = 0x6001; PlayField16[si - FieldWidth] = 0x8888; return; } if (PlayField16[si - FieldWidth + 1] != fiZonk) return; loc_g_16A7: ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth + 1] = 0x5001; PlayField16[si - FieldWidth] = 0x8888; } return; } // subCleanUpForZonksAbove rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Murphy.c0000644000175000017500000021173011375601355020472 0ustar dimkadimka// ---------------------------------------------------------------------------- // Murphy.c // ---------------------------------------------------------------------------- #include "Murphy.h" static void subEatRedDisk(int si); static boolean subMoveKillsMurphy(int si, int ax, int bl); #if 1 #define LocalStretch (2) #define MurphyZoomFactor (ZoomFactor) #else #define LocalStretch (1) #define MurphyZoomFactor (1) #endif // ========================================================================== // SUBROUTINE // Move Murphy in any direction // ========================================================================== void subAnimateMurphy(int *si) { int ax, al, bl, i, X, Y; int time1, time2; int tDeltaX, tDeltaY, tPos, Tmp; // Variables that hold information about the animation sequence static int dx1 = 0; // image/animation token static int dx2 = 0; // an additional image position of a second sprite, for instance: yellow disk if pushed static int MurphyDX = 0, MurphyDY = 0; // murphys move steps static int SeqPos = 0; // index into dx() static int ClearPos = 0; // Position to clear before blitting sprites, none=-1 static int dxPos = 0; // field-position to draw dx(SeqPos) static int dx2Step = 0; // position of dx2 relative to dx-position static int dx1SequenceLength = 0; ax = PlayField16[*si]; al = LowByte(ax); if (al != fiMurphy) { MurphyMoveCounter = 0; // We have no Murphy! Exit! return; } MurphyMoveCounter = 1; // We have a Murphy! MurphyExplodePos = *si; // (check if high byte of PlayField16 has stored movement information) if (ax != fiMurphy) // yes--go proceed moving murphy? goto locProceedMovingMurphy; // FS: reset moving sequence variables MurphyDX = 0; MurphyDY = 0; ClearPos = *si; dxPos = *si; dx1 = -1; dx2 = -1; SeqPos = 0; // end of FS ScratchGravity = 0; // scratch gravity off if (GravityFlag != 0) // Gravity? (1=gravity on) { bl = LowByte(PlayField16[*si - FieldWidth]); // check above if (! (bl == fiPortUp || bl == fiPortUpAndDown || bl == fiPortAllDirections)) { if (PlayField16[*si + FieldWidth] == 0) // gravity on and space below! ScratchGravity = 1; } } // loc_g_5E8B: bl = DemoKeyCode; if (bl != 0) // a key was pressed! goto locKeyPressed5FCF; RedDiskReleaseFlag = 1; if (ScratchGravity != 0) // gravity pulls & space below?'-> force Space up to down { MurphyDY = 2; goto loc_g_6364; } #if 1 #if 0 ax = (TimerVar & 3); if (ax != 0) return; #endif // ------------------------------------------------------------------ // Murphy's YAWN & SLEEP sequence, counted down by YawnSleepCounter: YawnSleepCounter = YawnSleepCounter + 1; if (YawnSleepCounter < 16) return; if (YawnSleepCounter < 2000) { // normal grin // (default: single graphic, no animation) subCopyAnimToScreen(*si, aniMurphy, YawnSleepCounter - 16); return; } if (YawnSleepCounter < 4000) { // yawn! and look depressed afterwards... // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 2000); return; } if (YawnSleepCounter < 6400) { // yawn again! // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 4000); return; } // time1 = 6400 + 12 * 8; // (default: 6496 == 6400 + 12 * 8) time1 = 6400 + 12 * 10; if (YawnSleepCounter < time1) { // yawn again! - third time // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 6400); return; } // time2 = 6496 + 3 * 64; // (default: 6688 == 6496 + 3 * 64) time2 = 6496 + 3 * 100; if (YawnSleepCounter > time2) // Murphy already went to sleep return; if (PlayField16[*si - 1] == 0) { if (PlayField16[*si + 1] == 0) { // no sleep -- go back to "wait and start yawning" phase YawnSleepCounter = 144; return; } else { // go to sleep (right side) // (default: 3 animation frames with delay of 64) subCopyAnimToScreen(*si, aniMurphySleepRight, YawnSleepCounter - time1); return; } } // go to sleep (left side) // (default: 3 animation frames with delay of 64) subCopyAnimToScreen(*si, aniMurphySleepLeft, YawnSleepCounter - time1); return; // end of YAWN-SLEEP-Sequence #else ax = (TimerVar & 3); if (ax != 0) return; // ------------------------------------------------------------------ // Murphy's YAWN & SLEEP sequence, counted down by YawnSleepCounter: YawnSleepCounter = YawnSleepCounter + 1; if (YawnSleepCounter == 4) { subCopyFieldToScreen(*si, fiMurphy); // normal grin return; } // loc_g_5ECE: if (YawnSleepCounter <= 500) // loc_g_5ED7: return; if (YawnSleepCounter <= 522) { bx = (YawnSleepCounter - 500) / 2; subCopyFieldToScreen(*si, aniMurphyYawn + bx); // yawn! and look depressed afterwards... return; } // loc_g_5F00: if (YawnSleepCounter <= 1000) return; if (YawnSleepCounter <= 1022) { bx = (YawnSleepCounter - 1000) / 2; subCopyFieldToScreen(*si, aniMurphyYawn + bx); // yawn again! return; } // loc_g_5F32: if (YawnSleepCounter <= 1600) // loc_g_5F3B: return; if (YawnSleepCounter <= 1622) { bx = (YawnSleepCounter - 1600) / 2; subCopyFieldToScreen(*si, aniMurphyYawn + bx); // yawn again! - third time return; } // loc_g_5F64: if (YawnSleepCounter > 1654) return; if (PlayField16[*si - 1] == 0) { if (PlayField16[*si + 1] == 0) { YawnSleepCounter = 36; return; } else { bx = (YawnSleepCounter - 1622) / 16; subCopyFieldToScreen(*si, aniMurphySleepRight + bx); // go to sleep return; } } // loc_g_5F81: bx = (YawnSleepCounter - 1622) / 16; subCopyFieldToScreen(*si, aniMurphySleepLeft + bx); // go to sleep return; // end of YAWN-SLEEP-Sequence #endif // ------------------------------------------------------------------ // ========================================================================== // (Direct Jump) a key was pressed // ========================================================================== locKeyPressed5FCF: if (ScratchGravity == 0) goto loc_g_6003; if (PlayField16[*si + FieldWidth] != 0) goto loc_g_6003; if (bl == keyUp) { if (PlayField16[*si - FieldWidth] == fiBase) goto loc_g_6003; } else if (bl == keyLeft) { if (PlayField16[*si - 1] == fiBase) goto loc_g_6003; } else if (bl == keyRight) { if (PlayField16[*si + 1] == fiBase) goto loc_g_6003; } // loc_g_6001: bl = keyDown; // force moving down! loc_g_6003: switch (bl) { case keyUp: // 1 RedDiskReleaseFlag = 0; // moving down to up ... goto loc_g_6078; break; case keyLeft: // 2 RedDiskReleaseFlag = 0; // moving right to left ... goto loc_g_60DA; break; case keyDown: // 3 RedDiskReleaseFlag = 0; // moving up to down ... goto loc_g_6154; break; case keyRight: // 4 RedDiskReleaseFlag = 0; // moving left to right ... goto loc_g_61B6; break; case keySpaceUp: // 5 RedDiskReleaseFlag = 0; // touching down to up ... goto loc_g_622E; break; case keySpaceLeft: // 6 RedDiskReleaseFlag = 0; // touching right to left ... goto loc_g_6258; break; case keySpaceDown: // 7 RedDiskReleaseFlag = 0; // touching up to down ... goto loc_g_6288; break; case keySpaceRight: // 8 RedDiskReleaseFlag = 0; // touching left to right ... goto loc_g_62B2; break; case keySpace: // 9 goto loc_g_62E2; // no move ... break; default: RedDiskReleaseFlag = 0; return; break; } // ========================================================================== // moving down to up ... // ========================================================================== loc_g_6078: // FS: MurphyDY = -2; // end of FS ax = PlayField16[*si - FieldWidth]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6312; if (ax == fiBase) goto loc_g_63D3; if (al == fiBug) goto loc_g_63C2; if (ax == fiInfotron) goto loc_g_65C6; if (ax == fiExit) goto loc_g_6756; if (al == fiTerminal) goto loc_g_6817; if (al == fiPortUp || al == fiPortUpAndDown || al == fiPortAllDirections) goto loc_g_6916; if (al == fiRedDisk) goto loc_g_69A6; if (al == fiYellowDisk) goto loc_g_6AB8; if (! subMoveKillsMurphy(*si - FieldWidth, ax, bl)) goto loc_g_6078; return; // ========================================================================== // moving right to left ... // ========================================================================== loc_g_60DA: // FS: MurphyDX = -2; // end of FS MurphyVarFaceLeft = 1; ax = PlayField16[*si - 1]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6341; if (ax == fiBase) goto loc_g_641C; if (al == fiBug) goto loc_g_640B; if (ax == fiInfotron) goto loc_g_65FE; if (ax == fiExit) goto loc_g_6756; if (ax == fiZonk) goto loc_g_679B; if (al == fiTerminal) goto loc_g_684E; if (al == fiPortLeft || al == fiPortLeftAndRight || al == fiPortAllDirections) goto loc_g_693A; if (ax == fiRedDisk) goto loc_g_69CE; if (ax == fiYellowDisk) goto loc_g_6AF1; if (ax == fiOrangeDisk) goto loc_g_6B9B; if (! subMoveKillsMurphy(*si - 1, ax, bl)) goto loc_g_60DA; return; // ========================================================================== // moving up to down ... // ========================================================================== loc_g_6154: // FS: MurphyDY = 2; // end of FS ax = PlayField16[*si + FieldWidth]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6364; if (ax == fiBase) goto loc_g_6459; if (al == fiBug) goto loc_g_6448; if (ax == fiInfotron) goto loc_g_662A; if (ax == fiExit) goto loc_g_6756; if (al == fiTerminal) goto loc_g_6884; if (al == fiPortDown || al == fiPortUpAndDown || al == fiPortAllDirections) goto loc_g_695E; if (al == fiRedDisk) goto loc_g_69F7; if (al == fiYellowDisk) goto loc_g_6B2A; if (! subMoveKillsMurphy(*si + FieldWidth, ax, bl)) goto loc_g_6154; return; // ========================================================================== // moving left to right ... // ========================================================================== loc_g_61B6: // FS: MurphyDX = 2; // end of FS MurphyVarFaceLeft = 0; ax = PlayField16[*si + 1]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6399; if (ax == fiBase) goto loc_g_64A2; if (al == fiBug) goto loc_g_6491; if (ax == fiInfotron) goto loc_g_6662; if (ax == fiExit) goto loc_g_6756; if (ax == fiZonk) goto loc_g_67D4; if (al == fiTerminal) goto loc_g_68BA; if (al == fiPortRight || al == fiPortLeftAndRight || al == fiPortAllDirections) goto loc_g_6982; if (al == fiRedDisk) goto loc_g_6A1F; if (al == fiYellowDisk) goto loc_g_6B63; if (ax == fiOrangeDisk) goto loc_g_6BD3; if (! subMoveKillsMurphy(*si + 1, ax, bl)) goto loc_g_61B6; return; // ========================================================================== // touching down to up ... // ========================================================================== loc_g_622E: // FS: ClearPos = -1; dxPos = *si - FieldWidth; // end of FS ax = PlayField16[*si - FieldWidth]; al = LowByte(ax); al = LowByte(ax); if (ax == fiBase) goto loc_g_64DF; if (al == fiBug) goto loc_g_64CE; if (ax == fiInfotron) goto loc_g_668E; if (al == fiTerminal) goto loc_g_6817; if (al == fiRedDisk) goto loc_g_6A48; return; // ========================================================================== // touching right to left ... // ========================================================================== loc_g_6258: // FS: ClearPos = -1; dxPos = *si - 1; // end of FS MurphyVarFaceLeft = 1; ax = PlayField16[*si - 1]; al = LowByte(ax); if (ax == fiBase) goto loc_g_651D; if (al == fiBug) goto loc_g_650C; if (ax == fiInfotron) goto loc_g_66C0; if (al == fiTerminal) goto loc_g_684E; if (al == fiRedDisk) goto loc_g_6A64; return; // ========================================================================== // touching up to down ... // ========================================================================== loc_g_6288: // FS: ClearPos = -1; dxPos = *si + FieldWidth; // end of FS ax = PlayField16[*si + FieldWidth]; al = LowByte(ax); if (ax == fiBase) goto loc_g_655B; if (al == fiBug) goto loc_g_654A; if (ax == fiInfotron) goto loc_g_66F2; if (al == fiTerminal) goto loc_g_6884; if (al == fiRedDisk) goto loc_g_6A80; return; // ========================================================================== // touching left to right ... // ========================================================================== loc_g_62B2: // FS: ClearPos = -1; dxPos = *si + 1; // end of FS MurphyVarFaceLeft = 0; ax = PlayField16[*si + 1]; al = LowByte(ax); if (ax == fiBase) goto loc_g_6599; if (al == fiBug) goto loc_g_6588; if (ax == fiInfotron) goto loc_g_6724; if (al == fiTerminal) goto loc_g_68BA; if (al == fiRedDisk) goto loc_g_6A9C; return; // ========================================================================== // Release Red disk: no move ... // ========================================================================== loc_g_62E2: // FS: ClearPos = -1; // end of FS if (LowByte(RedDiskCount) == 0) return; if (LowByte(RedDiskReleasePhase) != 0) return; if (LowByte(RedDiskReleaseFlag) != 1) return; MovHighByte(&PlayField16[*si], 0x2A); MovingPictureSequencePhase = 0x40; // init picture move sequence dx1 = aniRedDisk; MovLowByte(&RedDiskReleasePhase, 1); RedDiskReleaseMurphyPos = *si; // remember Murphy's location goto loc_Split; // ========================================================================== // SPACE moving down to up // ========================================================================== loc_g_6312: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyMoveUpRight : aniMurphyMoveUpLeft); PlayField16[*si - FieldWidth] = 0x103; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // SPACE moving right to left // ========================================================================== loc_g_6341: dx1 = aniMurphyMoveLeft; PlayField16[*si - 1] = 0x203; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // SPACE moving up to down, and when gravity is pulling! // ========================================================================== loc_g_6364: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyMoveUpRight : aniMurphyMoveUpLeft); PlayField16[*si + FieldWidth] = 0x303; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // SPACE moving left to right // ========================================================================== loc_g_6399: dx1 = aniMurphyMoveRight; PlayField16[*si + 1] = 0x403; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // BUG moving down to up // ========================================================================== loc_g_63C2: if (SgnHighByte(PlayField16[*si - FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - FieldWidth] = fiBase; // ========================================================================== // BASE moving down to up // ========================================================================== loc_g_63D3: subSoundFX(*si, fiBase, actDigging); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyDigUpRight : aniMurphyDigUpLeft); PlayField16[*si - FieldWidth] = 0x503; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // BUG moving right to left // ========================================================================== loc_g_640B: if (SgnHighByte(PlayField16[*si - 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - 1] = fiBase; // ========================================================================== // BASE moving right to left // ========================================================================== loc_g_641C: subSoundFX(*si, fiBase, actDigging); dx1 = aniMurphyDigLeft; PlayField16[*si - 1] = 0x203; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // BUG moving up to down // ========================================================================== loc_g_6448: if (SgnHighByte(PlayField16[*si + FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + FieldWidth] = fiBase; // ========================================================================== // BASE moving up to down // ========================================================================== loc_g_6459: subSoundFX(*si, fiBase, actDigging); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyDigUpRight : aniMurphyDigUpLeft); PlayField16[*si + FieldWidth] = 0x703; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // BUG moving left to right // ========================================================================== loc_g_6491: if (SgnHighByte(PlayField16[*si + 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + 1] = fiBase; // ========================================================================== // BASE moving left to right // ========================================================================== loc_g_64A2: subSoundFX(*si, fiBase, actDigging); dx1 = aniMurphyDigRight; PlayField16[*si + 1] = 0x803; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // BUG touching down to up // ========================================================================== loc_g_64CE: if (SgnHighByte(PlayField16[*si - FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - FieldWidth] = fiBase; // ========================================================================== // BASE touching down to up // ========================================================================== loc_g_64DF: subCopyImageToScreen(*si, aniMurphyTouchUp); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si - FieldWidth; MovHighByte(&PlayField16[*si], 0x10); goto loc_StopNoSplit; // ========================================================================== // BUG touching right to left // ========================================================================== loc_g_650C: if (SgnHighByte(PlayField16[*si - 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - 1] = fiBase; // ========================================================================== // BASE touching right to left // ========================================================================== loc_g_651D: subCopyImageToScreen(*si, aniMurphyTouchLeft); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si - 1; MovHighByte(&PlayField16[*si], 0x11); goto loc_StopNoSplit; // ========================================================================== // BUG touching up to down // ========================================================================== loc_g_654A: if (SgnHighByte(PlayField16[*si + FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + FieldWidth] = fiBase; // ========================================================================== // BASE touching up to down // ========================================================================== loc_g_655B: subCopyImageToScreen(*si, aniMurphyTouchDown); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si + FieldWidth; MovHighByte(&PlayField16[*si], 0x12); goto loc_StopNoSplit; // ========================================================================== // BUG touching left to right // ========================================================================== loc_g_6588: if (SgnHighByte(PlayField16[*si + 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + 1] = fiBase; // ========================================================================== // BASE touching left to right // ========================================================================== loc_g_6599: subCopyImageToScreen(*si, aniMurphyTouchRight); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si + 1; MovHighByte(&PlayField16[*si], 0x13); goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving down to up // ========================================================================== loc_g_65C6: subSoundFX(*si, fiInfotron, actCollecting); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si - FieldWidth] = 0x903; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving right to left // ========================================================================== loc_g_65FE: subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniEatInfotronLeft; #if 0 dx2 = fiInfotron; dx2Step = -1; ClearPos = -1; #endif PlayField16[*si - 1] = 0xA03; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving up to down // ========================================================================== loc_g_662A: subSoundFX(*si, fiInfotron, actCollecting); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si + FieldWidth] = 0xB03; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving left to right // ========================================================================== loc_g_6662: subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniEatInfotronRight; #if 0 dx2 = fiInfotron; dx2Step = 1; ClearPos = -1; #endif PlayField16[*si + 1] = 0xC03; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching down to up // ========================================================================== loc_g_668E: subCopyImageToScreen(*si, aniMurphyTouchUp); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x14); MovHighByte(&PlayField16[*si - FieldWidth], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching right to left // ========================================================================== loc_g_66C0: subCopyImageToScreen(*si, aniMurphyTouchLeft); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x15); MovHighByte(&PlayField16[*si - 1], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching up to down // ========================================================================== loc_g_66F2: subCopyImageToScreen(*si, aniMurphyTouchDown); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x16); MovHighByte(&PlayField16[*si + FieldWidth], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching left to right // ========================================================================== loc_g_6724: subCopyImageToScreen(*si, aniMurphyTouchRight); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x17); MovHighByte(&PlayField16[*si + 1], 0xFF); goto loc_StopNoSplit; // ========================================================================== // EXIT pressed from any direction // ========================================================================== loc_g_6756: // FS ClearPos = -1; MurphyDX = 0; MurphyDY = 0; // end of FS if (LowByte(InfotronsNeeded) != 0) return; #if 0 if (!game_sp.LevelSolved) printf("::: Murphy.c: !!!!!!!!!! LEVEL %d SOLVED !!!!!!!!!!\n", level_nr); #endif #if 1 game_sp.LevelSolved = TRUE; #endif subSoundFX(*si, fiExit, actPassing); LeadOutCounter = 0x40; // quit: start lead-out dx1 = aniMurphyExit; MovHighByte(&PlayField16[*si], 0xD); goto loc_StopNoSplit; // ========================================================================== // ZONK moving right to left // ========================================================================== loc_g_679B: ax = PlayField16[*si - 2]; if (ax != 0) return; MovHighByte(&PlayField16[*si - 2], 1); subCopyImageToScreen(*si, aniPushLeft); // draw pushing murphy dx1 = aniZonkRollLeft; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; MovHighByte(&PlayField16[*si], 0xE); goto loc_MoveNoSplit; // ========================================================================== // ZONK moving left to right // ========================================================================== loc_g_67D4: ax = PlayField16[*si + 2]; if (ax != 0) return; ax = PlayField16[*si + FieldWidth + 1]; if (ax == 0) // zonk falls return; MovHighByte(&PlayField16[*si + 2], 1); subCopyImageToScreen(*si, aniPushRight); // draw pushing murphy dx1 = aniZonkRollRight; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; MovHighByte(&PlayField16[*si], 0xF); goto loc_MoveNoSplit; // ========================================================================== // TERMINAL moving/touching down to up // ========================================================================== loc_g_6817: subCopyImageToScreen(*si, aniMurphyTouchUp); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: #if 1 // draw new terminal type #if 1 GfxGraphic[GetX(*si - FieldWidth)][GetY(*si - FieldWidth)] = aniTerminalActive; #else subCopyImageToScreen(*si - FieldWidth, aniTerminalActive); #endif #else subCopyFieldToScreen(*si - FieldWidth, 0x88); // draw new terminal type #endif TerminalState[*si - FieldWidth] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching right to left // ========================================================================== loc_g_684E: subCopyImageToScreen(*si, aniMurphyTouchLeft); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: #if 1 // draw new terminal type #if 1 GfxGraphic[GetX(*si - 1)][GetY(*si - 1)] = aniTerminalActive; #else subCopyImageToScreen(*si - 1, aniTerminalActive); #endif #else subCopyFieldToScreen(*si - 1, 0x88); // draw new terminal type #endif TerminalState[*si - 1] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching up to down // ========================================================================== loc_g_6884: subCopyImageToScreen(*si, aniMurphyTouchDown); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: #if 1 // draw new terminal type #if 1 GfxGraphic[GetX(*si + FieldWidth)][GetY(*si + FieldWidth)] = aniTerminalActive; #else subCopyImageToScreen(*si + FieldWidth, aniTerminalActive); #endif #else subCopyFieldToScreen(*si + FieldWidth, 0x88); // draw new terminal type #endif TerminalState[*si + FieldWidth] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching left to right // ========================================================================== loc_g_68BA: subCopyImageToScreen(*si, aniMurphyTouchRight); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: #if 1 // draw new terminal type #if 1 GfxGraphic[GetX(*si + 1)][GetY(*si + 1)] = aniTerminalActive; #else subCopyImageToScreen(*si + 1, aniTerminalActive); #endif #else subCopyFieldToScreen(*si + 1, 0x88); // draw new terminal type #endif TerminalState[*si + 1] = 8; // ========================================================================== // common TERMINAL stuff moving/touching from all directions // ========================================================================== loc_g_68F0: TerminalMaxCycles = 7; YellowDisksExploded = 1; for (i = 0; i <= LevelMax; i++) { if (PlayField16[i] == fiYellowDisk) ExplodeFieldSP (i); } return; // ========================================================================== // PORT down to up, VERTICAL PORT, CROSS PORT all moving down to up // ========================================================================== loc_g_6916: if (PlayField16[*si - 2 * FieldWidth] != 0) return; dx1 = aniSplitUpDown; dx2Step = -FieldWidth; PlayField16[*si] = 0x1803; PlayField16[*si - 2 * FieldWidth] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT right to left, HORIZONTAL PORT, CROSS PORT all moving right to left // ========================================================================== loc_g_693A: if (PlayField16[*si - 2] != 0) return; dx1 = aniMurphyMoveLeft; dx2Step = -1; PlayField16[*si] = 0x1903; PlayField16[*si - 2] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT up to down, VERTICAL PORT, CROSS PORT all moving up to down // ========================================================================== loc_g_695E: if (PlayField16[*si + 2 * FieldWidth] != 0) return; dx1 = aniSplitUpDown; dx2Step = FieldWidth; PlayField16[*si] = 0x1A03; PlayField16[*si + 2 * FieldWidth] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT left to right, HORIZONTAL PORT, CROSS PORT all moving left to right // ========================================================================== loc_g_6982: if (PlayField16[*si + 2] != 0) return; dx1 = aniMurphyMoveRight; dx2Step = 1; PlayField16[*si] = 0x1B03; PlayField16[*si + 2] = 0x300; loc_StopSplit: MovingPictureSequencePhase = 0; // stop picture move sequence SplitMoveFlag = 1; // port: split movement goto loc_Split; // ========================================================================== // RED DISK moving down to up // ========================================================================== loc_g_69A6: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si] = 0x1C03; PlayField16[*si - FieldWidth] = 0x300; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving right to left // ========================================================================== loc_g_69CE: dx1 = aniMurphyEatLeft; PlayField16[*si] = 0x300; // !!!!!! this time we move murphy at sequence-start! PlayField16[*si - 1] = 0x1D03; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving up to down // ========================================================================== loc_g_69F7: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si] = 0x1E03; PlayField16[*si + FieldWidth] = 0x300; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving left to right // ========================================================================== loc_g_6A1F: // dx = aniMurphyEatRightRedDisk 'this sequence is 9 steps long! dx1 = aniMurphyEatRight; // -------------------------------------------------------------------------- // BugFix // Table data_h_145A, pointed to by table data_h_105E, has a severe bug: // The Red Disk sequence is 8 pictures long, but 9 are displayed, because it // has 1 extra entry, which causes Murphy to end slightly shifted to the left! // We may not fix the table, because then the timing of the game changes // and several existing demo's do not run properly anymore. // We only correct Murphies x-location here, when the sequence starts. // Remember that this is not the real bug-fix, but we must live with // this existing bug and correct for the consequences of it. if (AllowEatRightRedDiskBug == 0) // Murphy's screen x-position MurphyScreenXPos = MurphyScreenXPos - 2 * MurphyZoomFactor; SeqPos = -1; // FS: for me this means to blit the first animation frame twice // end of BugFix // -------------------------------------------------------------------------- PlayField16[*si] = 0x300; // !!!!!! this time we move murphy at sequence-start! PlayField16[*si + 1] = 0x1F03; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // RED DISK touching down to up // ========================================================================== loc_g_6A48: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x20); MovHighByte(&PlayField16[*si - FieldWidth], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching right to left // ========================================================================== loc_g_6A64: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x21); MovHighByte(&PlayField16[*si - 1], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching up to down // ========================================================================== loc_g_6A80: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x22); MovHighByte(&PlayField16[*si + FieldWidth], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching left to right // ========================================================================== loc_g_6A9C: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x23); MovHighByte(&PlayField16[*si + 1], 3); loc_StopNoSplit: MovingPictureSequencePhase = 0; // stop picture move sequence goto loc_NoSplit; // ========================================================================== // YELLOW DISK moving down to up // ========================================================================== loc_g_6AB8: if (PlayField16[*si - 2 * FieldWidth] != 0) return; PlayField16[*si - 2 * FieldWidth] = 0x1200; dx1 = aniYellowDisk; dxPos = *si - FieldWidth; dx2 = (MurphyVarFaceLeft == 0 ? aniPushRight : aniPushLeft); dx2Step = FieldWidth; PlayField16[*si] = 0x2403; subCopyImageToScreen(*si, dx2); goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving right to left // ========================================================================== loc_g_6AF1: if (PlayField16[*si - 2] != 0) return; PlayField16[*si - 2] = 0x1200; subCopyImageToScreen(*si, aniPushLeft); dx1 = aniYellowDisk; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; PlayField16[*si] = 0x2503; goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving up to down // ========================================================================== loc_g_6B2A: if (PlayField16[*si + 2 * FieldWidth] != 0) return; PlayField16[*si + 2 * FieldWidth] = 0x1200; dx1 = aniYellowDisk; dxPos = *si + FieldWidth; dx2 = (MurphyVarFaceLeft == 0 ? aniPushRight : aniPushLeft); dx2Step = -FieldWidth; PlayField16[*si] = 0x2703; subCopyImageToScreen(*si, dx2); goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving left to right // ========================================================================== loc_g_6B63: if (PlayField16[*si + 2] != 0) return; PlayField16[*si + 2] = 0x1200; subCopyImageToScreen(*si, aniPushRight); dx1 = aniYellowDisk; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; PlayField16[*si] = 0x2603; goto loc_MoveNoSplit; // ========================================================================== // ORANGE DISK moving right to left // ========================================================================== loc_g_6B9B: if (PlayField16[*si - 2] != 0) return; PlayField16[*si - 2] = 0x800; subCopyImageToScreen(*si, aniPushLeft); dx1 = aniOrangeDisk; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; PlayField16[*si] = 0x2803; goto loc_MoveNoSplit; // ========================================================================== // ORANGE DISK moving left to right // ========================================================================== loc_g_6BD3: if (PlayField16[*si + 2] != 0) return; if (PlayField16[*si + FieldWidth + 1] == 0) // falling goes before pushing return; PlayField16[*si + 2] = 0x100; subCopyImageToScreen(*si, aniPushRight); dx1 = aniOrangeDisk; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; PlayField16[*si] = 0x2903; // ========================================================================== // Copy screen animation action table to action work space // (To paint sequence: Push Zonk/Disk / release red disk / Port passing) // ========================================================================== loc_MoveNoSplit: MovingPictureSequencePhase = 8; // init picture move sequence loc_NoSplit: SplitMoveFlag = 0; // no port: no split movement loc_Split: // copy/store global move sequence info???????????????????????????????????? // ... dont think so ...(FS) // ========================================================================== // Proceed with all movements // ========================================================================== locProceedMovingMurphy: // proceed moving murphy YawnSleepCounter = 0; // Wake up sleeping Murphy ax = MovingPictureSequencePhase; // sequence busy? if (ax == 0) // no -- start sequence! goto loc_g_6C8F; ax = ax - 1; // next picture of sequence MovingPictureSequencePhase = ax; // store for later if (ax == 0) // Sound effects { switch (HighByte(PlayField16[*si])) { case 0xE: case 0xF: subSoundFX(*si, fiZonk, actPushing); break; case 0x28: case 0x29: subSoundFX(*si, fiOrangeDisk, actPushing); break; case 0x24: case 0x25: case 0x26: case 0x27: subSoundFX(*si, fiYellowDisk, actPushing); break; default: break; } } bl = HighByte(PlayField16[*si]); if (bl == 0xE) // Push Zonk to left goto loc_g_6F7E; if (bl == 0xF) // Push Zonk to right goto loc_g_6FBC; if (bl == 0x28) // Push orange disk to left goto loc_g_6FFA; if (bl == 0x29) // Push orange disk to right goto loc_g_7038; if (bl == 0x24) // Push yellow disk up goto loc_g_7076; if (bl == 0x25) // Push yellow disk to left goto loc_g_70B4; if (bl == 0x27) // Push yellow disk down goto loc_g_70F2; if (bl == 0x26) // Push yellow disk to right goto loc_g_7130; if (bl == 0x2A) // Red disk release timer goto loc_g_716E; return; // ========================================================================== // Paint frame of MOVING.DAT sequence // ========================================================================== loc_g_6C8F: #if 1 if (SeqPos <= 0) dx1SequenceLength = getSequenceLength(dx1); #endif if (SplitMoveFlag == 0) { // ++++++++++++++++++++++++++ // Begin of normal movement MurphyScreenXPos = MurphyScreenXPos + MurphyDX * MurphyZoomFactor; MurphyScreenYPos = MurphyScreenYPos + MurphyDY * MurphyZoomFactor; if (!(ClearPos < 0)) // clear field that murphy is leaving subCopyImageToScreen(ClearPos, aniSpace); #if 0 // !!! special two-tile animation currently not used !!! if (dx2 == fiInfotron) // special case of infotron moving left or right { tDeltaX = 0; tDeltaY = 0; } else #endif { tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1); tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1); } X = GetStretchX(dxPos) + tDeltaX; Y = GetStretchY(dxPos) + tDeltaY; Tmp = (SeqPos < 0 ? 0 : SeqPos); // 9StepBugFix!(red disk move right) #if 1 if (isSnappingSequence(dx1) && SeqPos == dx1SequenceLength - 1) dx1 = aniSpace; #endif #if 1 DDSpriteBuffer_BltImg(X, Y, dx1, Tmp); GfxGraphic[GetX(*si)][GetY(*si)] = -1; // (Murphy's position) GfxGraphic[GetX(dxPos)][GetY(dxPos)] = -1; // (snapping position) // printf("::: Tmp: %d\n", Tmp); #else StretchedSprites.BltEx(X, Y, dx[Tmp]); #endif if (!(dx2 < 0)) { tPos = dxPos + dx2Step; X = GetStretchX(tPos); Y = GetStretchY(tPos); #if 0 // !!! special two-tile animation currently not used !!! if (dx2 == fiInfotron) // special case of infotron moving left or right { StretchedSprites.BltEx(X, Y, dx[SeqPos] + dx2Step); } else // pushing something #endif { // (SeqPos iterates from 0 to 7 while pushing) DDSpriteBuffer_BltImg(X + tDeltaX, Y + tDeltaY, dx2, SeqPos); } } // End of normal movement // ------------------------ } else { // ++++++++++++++++++++++++++++++++ // Begin of split movement (port) MurphyScreenXPos = MurphyScreenXPos + 2 * MurphyDX * MurphyZoomFactor; MurphyScreenYPos = MurphyScreenYPos + 2 * MurphyDY * MurphyZoomFactor; subCopyImageToScreen(ClearPos, aniSpace); // clear the field that murphy leaves tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1); tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1); X = GetStretchX(dxPos) + tDeltaX; Y = GetStretchY(dxPos) + tDeltaY; DDSpriteBuffer_BltImg(X, Y, dx1, SeqPos); // plot first murphy tPos = dxPos + dx2Step; X = GetStretchX(tPos); Y = GetStretchY(tPos); DDSpriteBuffer_BltImg(X + tDeltaX, Y + tDeltaY, dx1, SeqPos); // plot second murphy DDSpriteBuffer_BltImg(X, Y, fiGraphic[LowByte(PlayField16[tPos])], 0); // replot the port on top // End of split movement (port) // ------------------------------ } // loc_g_6D1E:'loc_g_6D28: SeqPos = SeqPos + 1; #if 1 if (SeqPos < dx1SequenceLength) return; #else if (dx[SeqPos] > -1) return; #endif // Follow-up after movement completed 'loc_g_6D35: MurphyXPos = MurphyXPos + MurphyDX; MurphyYPos = MurphyYPos + MurphyDY; bl = HighByte(PlayField16[*si]); // animation phase MovHighByte(&PlayField16[*si], 0); if (bl == 0x1) // space, moving up goto loc_g_6EC8; if (bl == 0x2) // space, moving left goto loc_g_6EE6; if (bl == 0x3) // space, moving down goto loc_g_6F04; if (bl == 0x4) // space, moving right goto loc_g_71C4; if (bl == 0x5) // base , moving up goto loc_g_6EC8; if (bl == 0x6) // base , moving left -> 6 is not used, value is set to 2 instead of 6! goto loc_g_6EE6; if (bl == 0x7) // base , moving down goto loc_g_6F04; if (bl == 0x8) // base , moving right goto loc_g_71C4; if (bl == 0x9) // infotron, moving up goto loc_g_6EBA; if (bl == 0xA) // infotron, moving left goto loc_g_6ED8; if (bl == 0xB) // infotron, moving down goto loc_g_6EF6; if (bl == 0xC) // infotron, moving right goto loc_g_71B6; if (bl == 0xD) // exit goto loc_g_6F77; if (bl == 0xE) // zonk, pushing left goto loc_g_6F18; if (bl == 0xF) // zonk, pushing right goto loc_g_6F3B; if (bl == 0x10) // base , touching up goto loc_g_71E2; if (bl == 0x11) // base , touching left goto loc_g_71FE; if (bl == 0x12) // base , touching down goto loc_g_721A; if (bl == 0x13) // base , touching right goto loc_g_7236; if (bl == 0x14) // infotron touching up goto loc_g_71D4; if (bl == 0x15) // infotron touching left goto loc_g_71F0; if (bl == 0x16) // infotron touching down goto loc_g_720C; if (bl == 0x17) // infotron touching right goto loc_g_7228; if (bl == 0x18) // port up goto loc_g_7244; if (bl == 0x19) // port left goto loc_g_7272; if (bl == 0x1A) // port down goto loc_g_729F; if (bl == 0x1B) // port right goto loc_g_72CD; if (bl == 0x1C) // red disk, moving up goto loc_g_72FA; if (bl == 0x1D) // red disk, moving left goto loc_g_7318; if (bl == 0x1E) // red disk, moving down goto loc_g_7333; if (bl == 0x1F) // red disk, moving right -> 9-Step-Bug! goto loc_g_7351; if (bl == 0x20) // red disk, touching up goto loc_g_736C; if (bl == 0x21) // red disk, touching left goto loc_g_7381; if (bl == 0x22) // red disk, touching down goto loc_g_7396; if (bl == 0x23) // red disk, touching right goto loc_g_73AB; if (bl == 0x24) // yellow disk, pushing up goto loc_g_73C0; if (bl == 0x25) // yellow disk, pushing left goto loc_g_73DD; if (bl == 0x26) // yellow disk, pushing right -> order of "down" exchanged with "right"! goto loc_g_7417; if (bl == 0x27) // yellow disk, pushing down -> order of "down" exchanged with "right"! goto loc_g_73FA; if (bl == 0x28) // orange disk, pushing left goto loc_g_7434; if (bl == 0x29) // orange disk, pushing right goto loc_g_7451; if (bl == 0x2A) // red disk, release goto loc_g_747F; ExitToMenuFlag = 1; return; // ========================================================================== // infotron, moving up // ========================================================================== loc_g_6EBA: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6EC8: // space, base PlayField16[*si] = fiMurphy; subAdjustZonksInfotronsAboveMurphy(*si + FieldWidth); return; // ========================================================================== // infotron, moving left // ========================================================================== loc_g_6ED8: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6EE6: // space, base PlayField16[*si] = fiMurphy; subAdjustZonksInfotronsAboveMurphy(*si + 1); return; // ========================================================================== // infotron, moving down // ========================================================================== loc_g_6EF6: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6F04: // space, base if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; PlayField16[*si] = fiMurphy; return; // ========================================================================== // infotron, moving right // ========================================================================== loc_g_71B6: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71C4: // space, base subAdjustZonksInfotronsAboveMurphy(*si - 1); PlayField16[*si] = fiMurphy; return; // ========================================================================== // infotron, touching up // ========================================================================== loc_g_71D4: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71E2: // base if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; return; // ========================================================================== // infotron, touching left // ========================================================================== loc_g_71F0: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71FE: // base if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; return; // ========================================================================== // infotron, touching down // ========================================================================== loc_g_720C: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_721A: // base if (LowByte(PlayField16[*si + FieldWidth]) != fiExplosion) PlayField16[*si + FieldWidth] = 0; return; // ========================================================================== // infotron, touching right // ========================================================================== loc_g_7228: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_7236: // base if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; return; // ========================================================================== // zonk, pushing left // ========================================================================== loc_g_6F18: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 1] = fiMurphy; PlayField16[*si - 2] = fiZonk; subExplodeSnikSnaksBelow(*si - 2); *si = *si - 1; return; // ========================================================================== // zonk, pushing right // ========================================================================== loc_g_6F3B: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 1] = fiMurphy; PlayField16[*si + 2] = fiZonk; subExplodeSnikSnaksBelow(*si + 2); *si = *si + 1; return; // ========================================================================== // exit // ========================================================================== loc_g_6F77: ExitToMenuFlag = 1; #if 1 PlayField16[*si] = fiSpace; // remove Murphy from playfield after exiting #endif return; // ========================================================================== // Push Zonk from right to left // ========================================================================== loc_g_6F7E: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiZonk) return; PlayField16[*si] = fiMurphy; // else restore - no more zonk pushing! PlayField16[*si - 1] = fiZonk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push Zonk from left to right // ========================================================================== loc_g_6FBC: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiZonk) return; PlayField16[*si] = fiMurphy; // else restore - no more zonk pushing! PlayField16[*si + 1] = fiZonk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push orange disk from right to left // ========================================================================== loc_g_6FFA: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiOrangeDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - 1] = fiOrangeDisk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push orange disk from left to right // ========================================================================== loc_g_7038: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiOrangeDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + 1] = fiOrangeDisk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from down to up // ========================================================================== loc_g_7076: if (DemoKeyCode == keyUp && PlayField16[*si - FieldWidth] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - FieldWidth] = fiYellowDisk; if (LowByte(PlayField16[*si - 2 * FieldWidth]) != fiExplosion) PlayField16[*si - 2 * FieldWidth] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from right to left // ========================================================================== loc_g_70B4: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - 1] = fiYellowDisk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from up to down // ========================================================================== loc_g_70F2: if (DemoKeyCode == keyDown && PlayField16[*si + FieldWidth] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + FieldWidth] = fiYellowDisk; if (LowByte(PlayField16[*si + 2 * FieldWidth]) != fiExplosion) PlayField16[*si + 2 * FieldWidth] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from left to right // ========================================================================== loc_g_7130: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + 1] = fiYellowDisk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // time red disk release (space) // ========================================================================== loc_g_716E: if (DemoKeyCode != keySpace) { PlayField16[*si] = fiMurphy; subCopyImageToScreen(*si, aniMurphy); RedDiskReleasePhase = 0; } else if (MovingPictureSequencePhase == 0x20) { // anxious murphy, dropping red disk subCopyImageToScreen(*si, aniMurphyDropping); RedDiskReleasePhase = 1; } return; // ========================================================================== // Special port down to up // ========================================================================== loc_g_7244: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 2 * FieldWidth] = fiMurphy; SplitMoveFlag = 0; *si = *si - FieldWidth; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si - FieldWidth; return; // ========================================================================== // Special port right to left // ========================================================================== loc_g_7272: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 2] = fiMurphy; SplitMoveFlag = 0; *si = *si - 1; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si - 1; return; // ========================================================================== // Special port up to down // ========================================================================== loc_g_729F: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 2 * FieldWidth] = fiMurphy; SplitMoveFlag = 0; *si = *si + FieldWidth; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si + FieldWidth; return; // ========================================================================== // Special port left to right // ========================================================================== loc_g_72CD: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 2] = fiMurphy; SplitMoveFlag = 0; *si = *si + 1; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si + 1; return; // ========================================================================== // Move Red Disk up // ========================================================================== loc_g_72FA: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - FieldWidth; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk left // ========================================================================== loc_g_7318: if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk down // ========================================================================== loc_g_7333: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + FieldWidth; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk right // ========================================================================== loc_g_7351: if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk up // ========================================================================== loc_g_736C: if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; subEatRedDisk(*si - FieldWidth); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk left // ========================================================================== loc_g_7381: if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; subEatRedDisk(*si - 1); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk down // ========================================================================== loc_g_7396: if (LowByte(PlayField16[*si + FieldWidth]) != fiExplosion) PlayField16[*si + FieldWidth] = 0; subEatRedDisk(*si + FieldWidth); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk right // ========================================================================== loc_g_73AB: if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; subEatRedDisk(*si + 1); // inc+show Murphy's red disks return; // ========================================================================== // yellow disk, pushing up // ========================================================================== loc_g_73C0: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - FieldWidth; PlayField16[*si] = fiMurphy; PlayField16[*si - FieldWidth] = fiYellowDisk; return; // ========================================================================== // yellow disk, pushing left // ========================================================================== loc_g_73DD: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - 1; PlayField16[*si] = fiMurphy; PlayField16[*si - 1] = fiYellowDisk; return; // ========================================================================== // yellow disk, pushing down // ========================================================================== loc_g_73FA: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + FieldWidth; PlayField16[*si] = fiMurphy; PlayField16[*si + FieldWidth] = fiYellowDisk; return; // ========================================================================== // yellow disk pushing right // ========================================================================== loc_g_7417: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + 1; PlayField16[*si] = fiMurphy; PlayField16[*si + 1] = fiYellowDisk; return; // ========================================================================== // orange disk, pushing left // ========================================================================== loc_g_7434: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - 1; PlayField16[*si] = fiMurphy; PlayField16[*si - 1] = fiOrangeDisk; return; // ========================================================================== // orange disk, pushing right // ========================================================================== loc_g_7451: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + 1; PlayField16[*si] = fiMurphy; PlayField16[*si + 1] = fiOrangeDisk; if (PlayField16[*si + FieldWidth + 1] == 0) // make it fall down if below is empty { MovHighByte(&PlayField16[*si + 1], 0x20); MovHighByte(&PlayField16[*si + FieldWidth + 1], fiOrangeDisk); } return; // ========================================================================== // Release a red disk // ========================================================================== loc_g_747F: PlayField16[*si] = fiMurphy; RedDiskReleasePhase = 2; RedDiskCount = RedDiskCount - 1; subSoundFX(*si, fiRedDisk, actDropping); } // subAnimateMurphy // ========================================================================== // SUBROUTINE // ========================================================================== void subExplodeSnikSnaksBelow(int si) { int ax; ax = LowByte(PlayField16[si + FieldWidth]); if (ax == 0x11 || ax == 0xBB) ExplodeFieldSP(si + FieldWidth); } // subExplodeSnikSnaksBelow // ========================================================================== // SUBROUTINE // Does pushing against an object kill Murphy? // ========================================================================== static boolean subMoveKillsMurphy(int si, int ax, int bl) { static boolean subMoveKillsMurphy; int al, ah; al = LowByte(ax); ah = HighByte(ax); if (ax == 0xFFFF || ax == 0xAAAA || ah == 0) goto loc_g_752E; if (al == fiZonk) goto loc_g_74E7; if (al == fiExplosion) goto loc_g_7530; if (fiOrangeDisk <= al && al <= fiPortUp) goto loc_g_752E; ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; return subMoveKillsMurphy; loc_g_74E7: // zonk if (bl == keyLeft) goto loc_g_74F6; if (bl == keyRight) goto loc_g_7512; ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; return subMoveKillsMurphy; loc_g_74F6: // zonk left ah = ah & 0xF0; if (! (ah == 0x20 || ah == 0x40 || ah == 0x50 || ah == 0x70)) ExplodeFieldSP(si); subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_7512: // zonk right ah = ah & 0xF0; if (! (ah == 0x30 || ah == 0x40 || ah == 0x60 || ah == 0x70)) ExplodeFieldSP(si); loc_g_752E: // Marked fields and Ports subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_7530: // explosion if ((ah & 0x80) != 0) goto loc_g_753A; if (ah >= 4) goto loc_g_753F; loc_g_753A: ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_753F: PlayField16[si] = 0; subMoveKillsMurphy = False; return subMoveKillsMurphy; } // subMoveKillsMurphy // ========================================================================== // SUBROUTINE // Test If si 's a special (grav) port and If so Then fetch new values (see below) // change conditions to port specs // The 10-port data base is at data_h_0D28, 10 entries of 6 bytes each: // (hi),(lo),(gravity),(freeze zonks),(freeze enemies),(unused) // ========================================================================== void subSpPortTest(int si) { int i; for (i = 0; i < LInfo.SpecialPortCount; i++) { if (LInfo.SpecialPort[i].PortLocation / 2 == si) { GravityFlag = LInfo.SpecialPort[i].Gravity; FreezeZonks = LInfo.SpecialPort[i].FreezeZonks; SnikSnaksElectronsFrozen = LInfo.SpecialPort[i].FreezeEnemies; break; } } } void subCopyAnimToScreen(int si, int graphic, int sync_frame) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, graphic, sync_frame); // +++++++++++++++++++++++++++++++++++++++++ } void subCopyImageToScreen(int si, int graphic) { subCopyAnimToScreen(si, graphic, 0); } static void subEatRedDisk(int si) { if (AllowRedDiskCheat == 0) { if (RedDiskReleasePhase != 0) { if (RedDiskReleaseMurphyPos == si) return; } } RedDiskCount = (RedDiskCount + 1) % 256; } void subAdjustZonksInfotronsAboveMurphy(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; ax = PlayField16[si - FieldWidth]; if (ax == 0 || ax == 0x9999) goto loc_g_15A8; if (ax == fiZonk || ax == fiInfotron) { MovHighByte(&PlayField16[si - FieldWidth], 0x40); // make falling straigt down } return; loc_g_15A8: // empty above ax = PlayField16[si - FieldWidth - 1]; if (ax == fiZonk || ax == fiInfotron) goto loc_g_15C5; loc_g_15B6: ax = PlayField16[si - FieldWidth + 1]; if (ax == fiZonk || ax == fiInfotron) goto loc_g_15E8; return; loc_g_15C5: // zonk/infotron above left ax = PlayField16[si - 1]; if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) // continue testing right above goto loc_g_15B6; MovHighByte(&PlayField16[si - FieldWidth - 1], 0x60); // make roll right PlayField16[si - FieldWidth] = 0x8888; return; loc_g_15E8: // zonk/infotron above right ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { MovHighByte(&PlayField16[si - FieldWidth + 1], 0x50); // make roll left PlayField16[si - FieldWidth] = 0x8888; } } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DDSpriteBuffer.h0000644000175000017500000000055511350014242022006 0ustar dimkadimka// ---------------------------------------------------------------------------- // DDSpriteBuffer.h // ---------------------------------------------------------------------------- #ifndef DDSPRITEBUFFER_H #define DDSPRITEBUFFER_H #include "global.h" extern void DDSpriteBuffer_BltImg(int pX, int pY, int graphic, int sync_frame); #endif /* DDSPRITEBUFFER_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/main.c0000644000175000017500000000436311375336314020134 0ustar dimkadimka #include "main_sp.h" #include "global.h" struct GameInfo_SP game_sp; struct LevelInfo_SP native_sp_level; int GfxElementLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxGraphicLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxGraphic[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxFrame[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; void InitGameEngine_SP() { int x, y; gfx.anim_random_frame = -1; // (use simple, ad-hoc random numbers) game_sp.LevelSolved = FALSE; game_sp.GameOver = FALSE; game_sp.time_played = 0; game_sp.infotrons_still_needed = native_sp_level.header.InfotronsNeeded; game_sp.red_disk_count = 0; game_sp.score = 0; menBorder = setup.sp_show_border_elements; game_sp.scroll_xoffset = (EVEN(SCR_FIELDX) ? TILEX / 2 : 0); game_sp.scroll_yoffset = (EVEN(SCR_FIELDY) ? TILEY / 2 : 0); #if 1 if (native_sp_level.width <= SCR_FIELDX) game_sp.scroll_xoffset = TILEX / 2; if (native_sp_level.height <= SCR_FIELDY) game_sp.scroll_yoffset = TILEY / 2; #endif for (x = 0; x < SP_MAX_PLAYFIELD_WIDTH; x++) { for (y = 0; y < SP_MAX_PLAYFIELD_HEIGHT; y++) { GfxElementLast[x][y] = -1; GfxGraphicLast[x][y] = -1; GfxGraphic[x][y] = -1; GfxFrame[x][y] = 0; } } InitScrollPlayfield(); menPlay_Click(); } void RedrawPlayfield_SP(boolean force_redraw) { if (force_redraw) RestorePlayfield(); UpdatePlayfield(force_redraw); BackToFront_SP(); } void DrawGameDoorValues_SP() { game_sp.time_played = TimerVar / setup.game_frame_delay; game_sp.infotrons_still_needed = InfotronsNeeded; game_sp.red_disk_count = RedDiskCount; game_sp.score = 0; // (currently no score in Supaplex engine) } void GameActions_SP(byte action[MAX_PLAYERS], boolean warp_mode) { byte single_player_action = action[0]; int x, y; UpdateEngineValues(mScrollX / TILEX, mScrollY / TILEY); subMainGameLoop_Main(single_player_action, warp_mode); RedrawPlayfield_SP(FALSE); if (!warp_mode) /* do not redraw values in warp mode */ DrawGameDoorValues_SP(); CheckSingleStepMode_SP(PlayField16[MurphyPosIndex] != fiMurphy); for (x = DisplayMinX; x <= DisplayMaxX; x++) for (y = DisplayMinY; y <= DisplayMaxY; y++) GfxFrame[x][y]++; } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/DDScrollBuffer.h0000644000175000017500000000150311362137553022006 0ustar dimkadimka// ---------------------------------------------------------------------------- // DDScrollBuffer.h // ---------------------------------------------------------------------------- #ifndef DDSCROLLBUFFER_H #define DDSCROLLBUFFER_H #include "global.h" extern long mScrollX, mScrollY; extern long mScrollX_last, mScrollY_last; #if 1 extern boolean redraw[2 + MAX_PLAYFIELD_WIDTH + 2][2 + MAX_PLAYFIELD_HEIGHT + 2]; #else extern boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; #endif extern int TEST_flag; extern void InitScrollPlayfield(); extern void UpdatePlayfield(); extern void RestorePlayfield(); extern void DDScrollBuffer_ScrollTo(int X, int Y); extern void DDScrollBuffer_ScrollTowards(int X, int Y, double Step); extern void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS); #endif /* DDSCROLLBUFFER_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/init.c0000644000175000017500000001404111376571224020147 0ustar dimkadimka #include "main_sp.h" #include "global.h" Bitmap *bitmap_db_field_sp; struct EngineSnapshotInfo_SP engine_snapshot_sp; void sp_open_all() { Form_Load(); } void sp_close_all() { } void InitGfxBuffers_SP() { ReCreateBitmap(&bitmap_db_field_sp, FXSIZE, FYSIZE, DEFAULT_DEPTH); } unsigned int InitEngineRandom_SP(long seed) { if (seed == NEW_RANDOMIZE) { subRandomize(); seed = (long)RandomSeed; } RandomSeed = (short)seed; return (unsigned int) seed; } /* ------------------------------------------------------------------------- */ /* Supaplex game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ void SaveEngineSnapshotValues_SP() { int i; engine_snapshot_sp.game_sp = game_sp; /* these arrays have playfield-size dependent variable size */ for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.PlayField16[i] = PlayField16[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.PlayField8[i] = PlayField8[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.DisPlayField[i] = DisPlayField[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) engine_snapshot_sp.AnimationPosTable[i] = AnimationPosTable[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) engine_snapshot_sp.AnimationSubTable[i] = AnimationSubTable[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.TerminalState[i] = TerminalState[i]; /* store special data into engine snapshot buffers */ SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldWidth)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldHeight)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldMax)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(LevelMax)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FileMax)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimerVar)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RandomSeed)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TerminalMaxCycles)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollX_last)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollY_last)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenScrollXPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenScrollYPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMinX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMinY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMaxX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMaxY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(InfotronsNeeded)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(KillMurphyFlag)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyMoveCounter)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyExplodePos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(SplitMoveFlag)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseMurphyPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyPosIndex)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyXPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyYPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyScreenXPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyScreenYPos)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyVarFaceLeft)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskCount)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseFlag)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovingPictureSequencePhase)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleasePhase)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScratchGravity)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GravityFlag)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(SnikSnaksElectronsFrozen)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(YellowDisksExploded)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(YawnSleepCounter)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(LeadOutCounter)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElementLast)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxGraphicLast)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxGraphic)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMinX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMinY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMaxX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMaxY)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollX)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollY)); SaveEngineSnapshotBuffer(&PlayField16[-game_sp.preceding_buffer_size], game_sp.preceding_buffer_size * sizeof(int)); } void LoadEngineSnapshotValues_SP() { int i; /* stored engine snapshot buffers already restored at this point */ game_sp = engine_snapshot_sp.game_sp; /* these arrays have playfield-size dependent variable size */ for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) PlayField16[i] = engine_snapshot_sp.PlayField16[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) PlayField8[i] = engine_snapshot_sp.PlayField8[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) DisPlayField[i] = engine_snapshot_sp.DisPlayField[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) AnimationPosTable[i] = engine_snapshot_sp.AnimationPosTable[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) AnimationSubTable[i] = engine_snapshot_sp.AnimationSubTable[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) TerminalState[i] = engine_snapshot_sp.TerminalState[i]; RedrawPlayfield_SP(TRUE); } rocksndiamonds-3.3.0.1+dfsg1/src/game_sp/Input.h0000644000175000017500000000044411347527757020324 0ustar dimkadimka// ---------------------------------------------------------------------------- // Input.h // ---------------------------------------------------------------------------- #ifndef INPUT_H #define INPUT_H #include "global.h" extern void subProcessKeyboardInput(byte); #endif /* INPUT_H */ rocksndiamonds-3.3.0.1+dfsg1/src/game.h0000644000175000017500000002330711354413754016513 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * game.h * ***********************************************************/ #ifndef GAME_H #define GAME_H /* (not included here due to collisions with Emerald Mine engine definitions) */ /* #include "main.h" */ #define MAX_INVENTORY_SIZE 1000 #define STD_NUM_KEYS 4 #define MAX_NUM_KEYS 8 #define NUM_BELTS 4 #define NUM_BELT_PARTS 3 #define NUM_PANEL_INVENTORY 8 #define NUM_PANEL_GRAPHICS 8 #define NUM_PANEL_ELEMENTS 8 #define NUM_PANEL_CE_SCORE 8 #if 1 struct GamePanelInfo { struct TextPosInfo level_number; struct TextPosInfo gems; struct TextPosInfo inventory_count; struct TextPosInfo inventory_first[NUM_PANEL_INVENTORY]; struct TextPosInfo inventory_last[NUM_PANEL_INVENTORY]; struct TextPosInfo key[MAX_NUM_KEYS]; struct TextPosInfo key_white; struct TextPosInfo key_white_count; struct TextPosInfo score; struct TextPosInfo highscore; struct TextPosInfo time; struct TextPosInfo time_hh; struct TextPosInfo time_mm; struct TextPosInfo time_ss; struct TextPosInfo frame; struct TextPosInfo shield_normal; struct TextPosInfo shield_normal_time; struct TextPosInfo shield_deadly; struct TextPosInfo shield_deadly_time; struct TextPosInfo exit; struct TextPosInfo emc_magic_ball; struct TextPosInfo emc_magic_ball_switch; struct TextPosInfo light_switch; struct TextPosInfo light_switch_time; struct TextPosInfo timegate_switch; struct TextPosInfo timegate_switch_time; struct TextPosInfo switchgate_switch; struct TextPosInfo emc_lenses; struct TextPosInfo emc_lenses_time; struct TextPosInfo emc_magnifier; struct TextPosInfo emc_magnifier_time; struct TextPosInfo balloon_switch; struct TextPosInfo dynabomb_number; struct TextPosInfo dynabomb_size; struct TextPosInfo dynabomb_power; struct TextPosInfo penguins; struct TextPosInfo sokoban_objects; struct TextPosInfo sokoban_fields; struct TextPosInfo robot_wheel; struct TextPosInfo conveyor_belt[NUM_BELTS]; struct TextPosInfo conveyor_belt_switch[NUM_BELTS]; struct TextPosInfo magic_wall; struct TextPosInfo magic_wall_time; struct TextPosInfo gravity_state; struct TextPosInfo graphic[NUM_PANEL_GRAPHICS]; struct TextPosInfo element[NUM_PANEL_ELEMENTS]; struct TextPosInfo element_count[NUM_PANEL_ELEMENTS]; struct TextPosInfo ce_score[NUM_PANEL_CE_SCORE]; struct TextPosInfo ce_score_element[NUM_PANEL_CE_SCORE]; struct TextPosInfo player_name; struct TextPosInfo level_name; struct TextPosInfo level_author; }; struct GameButtonInfo { struct MenuPosInfo stop; struct MenuPosInfo pause; struct MenuPosInfo play; struct MenuPosInfo sound_music; struct MenuPosInfo sound_loops; struct MenuPosInfo sound_simple; }; #else struct GamePanelInfo { struct XY level; struct XY gems; struct XY inventory; struct XY keys; struct XY score; struct XY time; }; #endif struct GameInfo { /* values for control panel */ struct GamePanelInfo panel; struct GameButtonInfo button; /* values for graphics engine customization */ boolean use_native_emc_graphics_engine; boolean use_native_sp_graphics_engine; boolean use_masked_pushing; int forced_scroll_delay_value; int scroll_delay_value; /* values for engine initialization */ int default_push_delay_fixed; int default_push_delay_random; /* constant within running game */ int engine_version; int emulation; int initial_move_delay[MAX_PLAYERS]; int initial_move_delay_value[MAX_PLAYERS]; int initial_push_delay_value; /* flags to handle bugs in and changes between different engine versions */ /* (for the latest engine version, these flags should always be "FALSE") */ boolean use_change_when_pushing_bug; boolean use_block_last_field_bug; boolean max_num_changes_per_frame; boolean use_reverse_scan_direction; /* variable within running game */ int yamyam_content_nr; boolean robot_wheel_active; boolean magic_wall_active; int magic_wall_time_left; int light_time_left; int timegate_time_left; int belt_dir[4]; int belt_dir_nr[4]; int switchgate_pos; int wind_direction; boolean gravity; boolean explosions_delayed; boolean envelope_active; /* values for the new EMC elements */ int lenses_time_left; int magnify_time_left; boolean ball_state; int ball_content_nr; /* values for player idle animation (no effect on engine) */ int player_boring_delay_fixed; int player_boring_delay_random; int player_sleeping_delay_fixed; int player_sleeping_delay_random; /* values for special game initialization control */ boolean restart_level; /* values for special game control */ int centered_player_nr; int centered_player_nr_next; boolean set_centered_player; /* values for random number generator initialization after snapshot */ unsigned long num_random_calls; }; struct PlayerInfo { boolean present; /* player present in level playfield */ boolean connected; /* player connected (locally or via network) */ boolean active; /* player present and connected */ boolean mapped; /* player already mapped to input device */ boolean killed; /* player maybe present/active, but killed */ boolean reanimated; /* player maybe killed, but reanimated */ int index_nr; /* player number (0 to 3) */ int index_bit; /* player number bit (1 << 0 to 1 << 3) */ int element_nr; /* element (EL_PLAYER_1 to EL_PLAYER_4) */ int client_nr; /* network client identifier */ byte action; /* action from local input device */ byte mapped_action; /* action mapped from device to player */ byte effective_action; /* action acknowledged from network server or summarized over all configured input devices when in single player mode */ byte programmed_action; /* action forced by game itself (like moving through doors); overrides other actions */ int jx, jy, last_jx, last_jy; int MovDir, MovPos, GfxDir, GfxPos; int Frame, StepFrame; int GfxAction; int initial_element; /* EL_PLAYER_1 to EL_PLAYER_4 or EL_SP_MURPHY */ int artwork_element; boolean use_murphy; boolean block_last_field; int block_delay_adjustment; /* needed for different engine versions */ boolean can_fall_into_acid; boolean gravity; boolean LevelSolved, GameOver; boolean LevelSolved_GameWon; boolean LevelSolved_GameEnd; boolean LevelSolved_PanelOff; boolean LevelSolved_SaveTape; boolean LevelSolved_SaveScore; int LevelSolved_CountingTime; int LevelSolved_CountingScore; int last_move_dir; boolean is_active; boolean is_waiting; boolean is_moving; boolean is_auto_moving; boolean is_digging; boolean is_snapping; boolean is_collecting; boolean is_pushing; boolean is_switching; boolean is_dropping; boolean is_dropping_pressed; boolean is_bored; boolean is_sleeping; boolean cannot_move; int frame_counter_bored; int frame_counter_sleeping; int anim_delay_counter; int post_delay_counter; int dir_waiting; int action_waiting, last_action_waiting; int special_action_bored; int special_action_sleeping; int num_special_action_bored; int num_special_action_sleeping; int switch_x, switch_y; int drop_x, drop_y; int show_envelope; int move_delay; int move_delay_value; int move_delay_value_next; int move_delay_reset_counter; int push_delay; int push_delay_value; unsigned long actual_frame_counter; int drop_delay; int drop_pressed_delay; int step_counter; int score; int score_final; int gems_still_needed; int sokobanfields_still_needed; int lights_still_needed; int friends_still_needed; int key[MAX_NUM_KEYS]; int num_white_keys; int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl; int shield_normal_time_left; int shield_deadly_time_left; int inventory_element[MAX_INVENTORY_SIZE]; int inventory_infinite_element; int inventory_size; }; extern struct GameInfo game; extern struct PlayerInfo stored_player[MAX_PLAYERS], *local_player; #ifdef DEBUG void DEBUG_SetMaximumDynamite(); #endif void GetPlayerConfig(void); int GetElementFromGroupElement(int); void DrawGameValue_Time(int); void DrawGameDoorValues(void); void UpdateAndDisplayGameControlValues(); void InitGameSound(); void InitGame(); void UpdateEngineValues(int, int); void GameWon(void); void GameEnd(void); void InitPlayerGfxAnimation(struct PlayerInfo *, int, int); void Moving2Blocked(int, int, int *, int *); void Blocked2Moving(int, int, int *, int *); void DrawDynamite(int, int); void StartGameActions(boolean, boolean, long); void GameActions(void); void GameActions_EM_Main(); void GameActions_SP_Main(); void GameActions_RND(); void ScrollLevel(int, int); void InitPlayLevelSound(); void PlayLevelSound_EM(int, int, int, int); void PlayLevelSound_SP(int, int, int, int); void RaiseScore(int); void RaiseScoreElement(int); void RequestQuitGameExt(boolean, boolean, char *); void RequestQuitGame(boolean); unsigned int InitEngineRandom_RND(long); unsigned int RND(int); void FreeEngineSnapshot(); void LoadEngineSnapshot(); void SaveEngineSnapshot(); boolean CheckEngineSnapshot(); void CreateGameButtons(); void FreeGameButtons(); void UnmapGameButtons(); void RedrawGameButtons(); void HandleSoundButtonKeys(Key); #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_grp.c0000644000175000017500000002222411375255512017366 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_grp.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GRP_C #define CONF_GRP_C /* values for graphics configuration (group elements) */ { "group_1", "RocksCE.pcx" }, { "group_1.xpos", "0" }, { "group_1.ypos", "16" }, { "group_1.frames", "1" }, { "group_1.EDITOR", "RocksCE.pcx" }, { "group_1.EDITOR.xpos", "16" }, { "group_1.EDITOR.ypos", "16" }, { "group_2", "RocksCE.pcx" }, { "group_2.xpos", "1" }, { "group_2.ypos", "16" }, { "group_2.frames", "1" }, { "group_2.EDITOR", "RocksCE.pcx" }, { "group_2.EDITOR.xpos", "17" }, { "group_2.EDITOR.ypos", "16" }, { "group_3", "RocksCE.pcx" }, { "group_3.xpos", "2" }, { "group_3.ypos", "16" }, { "group_3.frames", "1" }, { "group_3.EDITOR", "RocksCE.pcx" }, { "group_3.EDITOR.xpos", "18" }, { "group_3.EDITOR.ypos", "16" }, { "group_4", "RocksCE.pcx" }, { "group_4.xpos", "3" }, { "group_4.ypos", "16" }, { "group_4.frames", "1" }, { "group_4.EDITOR", "RocksCE.pcx" }, { "group_4.EDITOR.xpos", "19" }, { "group_4.EDITOR.ypos", "16" }, { "group_5", "RocksCE.pcx" }, { "group_5.xpos", "4" }, { "group_5.ypos", "16" }, { "group_5.frames", "1" }, { "group_5.EDITOR", "RocksCE.pcx" }, { "group_5.EDITOR.xpos", "20" }, { "group_5.EDITOR.ypos", "16" }, { "group_6", "RocksCE.pcx" }, { "group_6.xpos", "5" }, { "group_6.ypos", "16" }, { "group_6.frames", "1" }, { "group_6.EDITOR", "RocksCE.pcx" }, { "group_6.EDITOR.xpos", "21" }, { "group_6.EDITOR.ypos", "16" }, { "group_7", "RocksCE.pcx" }, { "group_7.xpos", "6" }, { "group_7.ypos", "16" }, { "group_7.frames", "1" }, { "group_7.EDITOR", "RocksCE.pcx" }, { "group_7.EDITOR.xpos", "22" }, { "group_7.EDITOR.ypos", "16" }, { "group_8", "RocksCE.pcx" }, { "group_8.xpos", "7" }, { "group_8.ypos", "16" }, { "group_8.frames", "1" }, { "group_8.EDITOR", "RocksCE.pcx" }, { "group_8.EDITOR.xpos", "23" }, { "group_8.EDITOR.ypos", "16" }, { "group_9", "RocksCE.pcx" }, { "group_9.xpos", "8" }, { "group_9.ypos", "16" }, { "group_9.frames", "1" }, { "group_9.EDITOR", "RocksCE.pcx" }, { "group_9.EDITOR.xpos", "24" }, { "group_9.EDITOR.ypos", "16" }, { "group_10", "RocksCE.pcx" }, { "group_10.xpos", "9" }, { "group_10.ypos", "16" }, { "group_10.frames", "1" }, { "group_10.EDITOR", "RocksCE.pcx" }, { "group_10.EDITOR.xpos", "25" }, { "group_10.EDITOR.ypos", "16" }, { "group_11", "RocksCE.pcx" }, { "group_11.xpos", "10" }, { "group_11.ypos", "16" }, { "group_11.frames", "1" }, { "group_11.EDITOR", "RocksCE.pcx" }, { "group_11.EDITOR.xpos", "26" }, { "group_11.EDITOR.ypos", "16" }, { "group_12", "RocksCE.pcx" }, { "group_12.xpos", "11" }, { "group_12.ypos", "16" }, { "group_12.frames", "1" }, { "group_12.EDITOR", "RocksCE.pcx" }, { "group_12.EDITOR.xpos", "27" }, { "group_12.EDITOR.ypos", "16" }, { "group_13", "RocksCE.pcx" }, { "group_13.xpos", "12" }, { "group_13.ypos", "16" }, { "group_13.frames", "1" }, { "group_13.EDITOR", "RocksCE.pcx" }, { "group_13.EDITOR.xpos", "28" }, { "group_13.EDITOR.ypos", "16" }, { "group_14", "RocksCE.pcx" }, { "group_14.xpos", "13" }, { "group_14.ypos", "16" }, { "group_14.frames", "1" }, { "group_14.EDITOR", "RocksCE.pcx" }, { "group_14.EDITOR.xpos", "29" }, { "group_14.EDITOR.ypos", "16" }, { "group_15", "RocksCE.pcx" }, { "group_15.xpos", "14" }, { "group_15.ypos", "16" }, { "group_15.frames", "1" }, { "group_15.EDITOR", "RocksCE.pcx" }, { "group_15.EDITOR.xpos", "30" }, { "group_15.EDITOR.ypos", "16" }, { "group_16", "RocksCE.pcx" }, { "group_16.xpos", "15" }, { "group_16.ypos", "16" }, { "group_16.frames", "1" }, { "group_16.EDITOR", "RocksCE.pcx" }, { "group_16.EDITOR.xpos", "31" }, { "group_16.EDITOR.ypos", "16" }, { "group_17", "RocksCE.pcx" }, { "group_17.xpos", "0" }, { "group_17.ypos", "17" }, { "group_17.frames", "1" }, { "group_17.EDITOR", "RocksCE.pcx" }, { "group_17.EDITOR.xpos", "16" }, { "group_17.EDITOR.ypos", "17" }, { "group_18", "RocksCE.pcx" }, { "group_18.xpos", "1" }, { "group_18.ypos", "17" }, { "group_18.frames", "1" }, { "group_18.EDITOR", "RocksCE.pcx" }, { "group_18.EDITOR.xpos", "17" }, { "group_18.EDITOR.ypos", "17" }, { "group_19", "RocksCE.pcx" }, { "group_19.xpos", "2" }, { "group_19.ypos", "17" }, { "group_19.frames", "1" }, { "group_19.EDITOR", "RocksCE.pcx" }, { "group_19.EDITOR.xpos", "18" }, { "group_19.EDITOR.ypos", "17" }, { "group_20", "RocksCE.pcx" }, { "group_20.xpos", "3" }, { "group_20.ypos", "17" }, { "group_20.frames", "1" }, { "group_20.EDITOR", "RocksCE.pcx" }, { "group_20.EDITOR.xpos", "19" }, { "group_20.EDITOR.ypos", "17" }, { "group_21", "RocksCE.pcx" }, { "group_21.xpos", "4" }, { "group_21.ypos", "17" }, { "group_21.frames", "1" }, { "group_21.EDITOR", "RocksCE.pcx" }, { "group_21.EDITOR.xpos", "20" }, { "group_21.EDITOR.ypos", "17" }, { "group_22", "RocksCE.pcx" }, { "group_22.xpos", "5" }, { "group_22.ypos", "17" }, { "group_22.frames", "1" }, { "group_22.EDITOR", "RocksCE.pcx" }, { "group_22.EDITOR.xpos", "21" }, { "group_22.EDITOR.ypos", "17" }, { "group_23", "RocksCE.pcx" }, { "group_23.xpos", "6" }, { "group_23.ypos", "17" }, { "group_23.frames", "1" }, { "group_23.EDITOR", "RocksCE.pcx" }, { "group_23.EDITOR.xpos", "22" }, { "group_23.EDITOR.ypos", "17" }, { "group_24", "RocksCE.pcx" }, { "group_24.xpos", "7" }, { "group_24.ypos", "17" }, { "group_24.frames", "1" }, { "group_24.EDITOR", "RocksCE.pcx" }, { "group_24.EDITOR.xpos", "23" }, { "group_24.EDITOR.ypos", "17" }, { "group_25", "RocksCE.pcx" }, { "group_25.xpos", "8" }, { "group_25.ypos", "17" }, { "group_25.frames", "1" }, { "group_25.EDITOR", "RocksCE.pcx" }, { "group_25.EDITOR.xpos", "24" }, { "group_25.EDITOR.ypos", "17" }, { "group_26", "RocksCE.pcx" }, { "group_26.xpos", "9" }, { "group_26.ypos", "17" }, { "group_26.frames", "1" }, { "group_26.EDITOR", "RocksCE.pcx" }, { "group_26.EDITOR.xpos", "25" }, { "group_26.EDITOR.ypos", "17" }, { "group_27", "RocksCE.pcx" }, { "group_27.xpos", "10" }, { "group_27.ypos", "17" }, { "group_27.frames", "1" }, { "group_27.EDITOR", "RocksCE.pcx" }, { "group_27.EDITOR.xpos", "26" }, { "group_27.EDITOR.ypos", "17" }, { "group_28", "RocksCE.pcx" }, { "group_28.xpos", "11" }, { "group_28.ypos", "17" }, { "group_28.frames", "1" }, { "group_28.EDITOR", "RocksCE.pcx" }, { "group_28.EDITOR.xpos", "27" }, { "group_28.EDITOR.ypos", "17" }, { "group_29", "RocksCE.pcx" }, { "group_29.xpos", "12" }, { "group_29.ypos", "17" }, { "group_29.frames", "1" }, { "group_29.EDITOR", "RocksCE.pcx" }, { "group_29.EDITOR.xpos", "28" }, { "group_29.EDITOR.ypos", "17" }, { "group_30", "RocksCE.pcx" }, { "group_30.xpos", "13" }, { "group_30.ypos", "17" }, { "group_30.frames", "1" }, { "group_30.EDITOR", "RocksCE.pcx" }, { "group_30.EDITOR.xpos", "29" }, { "group_30.EDITOR.ypos", "17" }, { "group_31", "RocksCE.pcx" }, { "group_31.xpos", "14" }, { "group_31.ypos", "17" }, { "group_31.frames", "1" }, { "group_31.EDITOR", "RocksCE.pcx" }, { "group_31.EDITOR.xpos", "30" }, { "group_31.EDITOR.ypos", "17" }, { "group_32", "RocksCE.pcx" }, { "group_32.xpos", "15" }, { "group_32.ypos", "17" }, { "group_32.frames", "1" }, { "group_32.EDITOR", "RocksCE.pcx" }, { "group_32.EDITOR.xpos", "31" }, { "group_32.EDITOR.ypos", "17" }, #endif /* CONF_GRP_C */ rocksndiamonds-3.3.0.1+dfsg1/src/Makefile0000644000175000017500000002014011403523057017052 0ustar dimkadimka# ============================================================================= # Rocks'n'Diamonds Makefile (src) # ----------------------------------------------------------------------------- # (c) 1995-2006 Holger Schemel # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- .EXPORT_ALL_VARIABLES: ifndef PLATFORM # unknown platform -- try auto detection ifdef COMSPEC PLATFORM = msdos else PLATFORM = unix endif endif ifdef X11_PATH # path to X11 from top level Makefile XINC_PATH = $(X11_PATH)/include XLIB_PATH = $(X11_PATH)/lib X11_INCL = -I$(XINC_PATH) X11_LIBS = -L$(XLIB_PATH) -lX11 endif AR = ar RANLIB = ranlib ETAGS = etags RM = rm -f BMP2ICO = bmp2ico WINDRES = windres PROGBASE = rocksndiamonds ifdef SPECIAL_EDITION # create special edition PROGBASE = $(SPECIAL_EDITION) endif PROGNAME = ../$(PROGBASE) # ----------------------------------------------------------------------------- # configuring platform # ----------------------------------------------------------------------------- ifeq ($(PLATFORM),solaris) # native compiling to Solaris EXTRA_LDFLAGS = -lnsl -lsocket -R$(XLIB_PATH) PLATFORM = unix endif ifeq ($(PLATFORM),macosx) # native compiling to Mac OS X EXTRA_LDFLAGS = -lstdc++ PLATFORM = unix TARGET = sdl endif ifeq ($(PLATFORM),os2) # native compiling to OS/2 RANLIB = echo PROGNAME = ../$(PROGBASE).exe EXTRA_CFLAGS = -Zbin-files -D__ST_MT_ERRNO__ -Zmtd -fomit-frame-pointer EXTRA_LDFLAGS = -lsocket PLATFORM = unix TARGET = x11 endif ifeq ($(PLATFORM),unix) # native compiling to Unix (generic) PROFILING_FLAGS = -pg endif ifeq ($(PLATFORM),cross-win32) # cross-compiling to Windows PROGNAME = ../$(PROGBASE).exe EXTRA_LDFLAGS = -lshfolder -lwsock32 TARGET = sdl endif ifeq ($(PLATFORM),cross-msdos) # cross-compiling to MS-DOS PROGBASE = rocks PROGNAME = ../$(PROGBASE).exe TARGET = allegro endif ifeq ($(PLATFORM),msdos) # native compiling to MS-DOS PROGBASE = rocks PROGNAME = ../$(PROGBASE).exe SYS_CFLAGS = -DTARGET_X11 SYS_LDFLAGS = -s -lalleg RM = del endif # ----------------------------------------------------------------------------- # configuring target # ----------------------------------------------------------------------------- ifeq ($(TARGET),x11) # compiling for X11 target SYS_CFLAGS = -DTARGET_X11 $(X11_INCL) SYS_LDFLAGS = $(X11_LIBS) endif ifeq ($(TARGET),sdl) # compiling for SDL target SYS_CFLAGS = -DTARGET_SDL $(shell sdl-config --cflags) SDL_LIBS = -lSDL_image -lSDL_mixer -lSDL_net -lsmpeg SYS_LDFLAGS = $(SDL_LIBS) $(shell sdl-config --libs) endif ifeq ($(TARGET),sdl-static) # compiling for SDL target (static) SYS_CFLAGS = -DTARGET_SDL $(shell sdl-config --cflags) SDL_LIBS = -lSDL_image -lSDL_mixer -lSDL_net -lsmpeg SYS_LDFLAGS = $(SDL_LIBS) $(shell sdl-config --static-libs) endif ifeq ($(TARGET),allegro) # compiling for Allegro target SYS_CFLAGS = -DTARGET_ALLEGRO -I$(CROSS_PATH_MSDOS)/include SYS_LDFLAGS = -lalleg endif # ----------------------------------------------------------------------------- # configuring compile-time definitions # ----------------------------------------------------------------------------- ifdef RO_GAME_DIR # path to read-only game data specified CONFIG_RO_GAME_DIR = -DRO_GAME_DIR="\"$(RO_GAME_DIR)\"" endif ifdef RW_GAME_DIR # path to writable game data specified CONFIG_RW_GAME_DIR = -DRW_GAME_DIR="\"$(RW_GAME_DIR)\"" endif ifdef SCORE_ENTRIES # number of score entries per player CONFIG_SCORE_ENTRIES = -D$(SCORE_ENTRIES) endif ifdef SPECIAL_EDITION ifeq ($(SPECIAL_EDITION),rnd_jue) # create special edition CONFIG_SPECIAL = -DCREATE_SPECIAL_EDITION -DCREATE_SPECIAL_EDITION_RND_JUE endif endif CONFIG_GAME_DIR = $(CONFIG_RO_GAME_DIR) $(CONFIG_RW_GAME_DIR) CONFIG_GAME = $(CONFIG_GAME_DIR) $(CONFIG_SCORE_ENTRIES) $(CONFIG_SPECIAL) CONFIG = $(CONFIG_GAME) $(JOYSTICK) # DEBUG = -DDEBUG -g # PROFILING = $(PROFILING_FLAGS) # OPTIONS = $(DEBUG) -Wall # only for debugging purposes # OPTIONS = $(DEBUG) -O3 -Wall # only for debugging purposes OPTIONS = $(DEBUG) -Wall # only for debugging purposes # OPTIONS = $(DEBUG) -Wall -ansi -pedantic # only for debugging purposes # OPTIONS = -O3 -Wall -ansi -pedantic # OPTIONS = -O3 -Wall # OPTIONS = -O3 # OPTIONS = -DSYSV -Ae # may be needed for HP-UX ifdef BUILD_DIST # distribution build OPTIONS = -O3 -Wall endif CFLAGS = $(OPTIONS) $(SYS_CFLAGS) $(EXTRA_CFLAGS) $(CONFIG) LDFLAGS = $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm SRCS = main.c \ conf_gfx.c \ conf_snd.c \ conf_mus.c \ conf_hlp.c \ init.c \ config.c \ events.c \ tools.c \ screens.c \ game.c \ editor.c \ files.c \ tape.c \ cartoons.c \ network.c \ netserv.c OBJS = main.o \ conf_gfx.o \ conf_snd.o \ conf_mus.o \ conf_hlp.o \ init.o \ config.o \ events.o \ tools.o \ screens.o \ game.o \ editor.o \ files.o \ tape.o \ cartoons.o \ network.o \ netserv.o CNFS = conf_gfx.h \ conf_snd.h \ conf_mus.h \ conf_chr.c \ conf_chr.h \ conf_cus.c \ conf_cus.h \ conf_grp.c \ conf_grp.h \ conf_e2g.c \ conf_esg.c \ conf_e2s.c \ conf_fnt.c \ conf_g2s.c \ conf_g2m.c \ conf_var.c \ conf_act.c CNFS_CMD = ../Scripts/create_element_defs.pl TIMESTAMP_FILE = conftime.h LIBGAME_DIR = libgame LIBGAME = $(LIBGAME_DIR)/libgame.a GAME_EM_DIR = game_em GAME_EM = $(GAME_EM_DIR)/game_em.a GAME_SP_DIR = game_sp GAME_SP = $(GAME_SP_DIR)/game_sp.a RNDLIBS = $(LIBGAME) $(GAME_EM) $(GAME_SP) ICONBASE = windows_icon ifeq ($(PLATFORM),cross-win32) ifdef SPECIAL_EDITION ICONSUFFIX = 32x32_$(SPECIAL_EDITION) else ICONSUFFIX = 32x32 endif ICON32X32 = ../graphics/$(ICONBASE)_$(ICONSUFFIX).bmp ICON = $(ICONBASE).o endif # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: libgame_dir game_em_dir game_sp_dir $(PROGNAME) $(PROGNAME): $(RNDLIBS) $(TIMESTAMP_FILE) $(OBJS) $(ICON) $(CC) $(PROFILING) $(OBJS) $(ICON) $(RNDLIBS) $(LDFLAGS) -o $(PROGNAME) libgame_dir: @$(MAKE) -C $(LIBGAME_DIR) $(LIBGAME): @$(MAKE) -C $(LIBGAME_DIR) game_em_dir: @$(MAKE) -C $(GAME_EM_DIR) $(GAME_EM): @$(MAKE) -C $(GAME_EM_DIR) game_sp_dir: @$(MAKE) -C $(GAME_SP_DIR) $(GAME_SP): @$(MAKE) -C $(GAME_SP_DIR) auto-conf: @for i in $(CNFS); do \ echo "$(CNFS_CMD) $$i > $$i"; \ $(CNFS_CMD) $$i > $$i; \ done conf_gfx.h: conf_gfx.c @$(MAKE) auto-conf conf_snd.h: conf_snd.c @$(MAKE) auto-conf conf_mus.h: conf_mus.c @$(MAKE) auto-conf $(TIMESTAMP_FILE): $(SRCS) $(LIBGAME) $(GAME_EM) $(GAME_SP) @date '+"%Y-%m-%d %H:%M"' \ | sed -e 's/^/#define COMPILE_DATE_STRING /' \ > $(TIMESTAMP_FILE) $(ICON): $(BMP2ICO) -transparent $(ICONBASE).ico $(ICON32X32) echo "$(ICONBASE) ICON $(ICONBASE).ico" | $(WINDRES) -o $(ICON) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean-obj: $(MAKE) -C $(LIBGAME_DIR) clean $(MAKE) -C $(GAME_EM_DIR) clean $(MAKE) -C $(GAME_SP_DIR) clean $(RM) $(OBJS) $(RM) $(LIBGAME) $(RM) $(GAME_EM) $(RM) $(GAME_SP) clean-ico: $(RM) $(ICONBASE).ico $(RM) $(ICONBASE).o clean-bin: $(RM) $(PROGNAME) $(RM) ../*.exe clean: clean-obj clean-ico clean-bin # ----------------------------------------------------------------------------- # run and test targets # ----------------------------------------------------------------------------- run: all cd .. && ./$(PROGBASE) --verbose gdb: all cd .. && gdb -batch -x GDB_COMMANDS ./$(PROGBASE) valgrind: all cd .. && valgrind -v --leak-check=yes ./$(PROGBASE) 2> valgrind.out # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- dist-clean: clean-obj tags: $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch] $(GAME_SP_DIR)/*.[ch] depend: $(MAKE) -C $(LIBGAME_DIR) depend $(MAKE) -C $(GAME_EM_DIR) depend $(MAKE) -C $(GAME_SP_DIR) depend for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_mus.c0000644000175000017500000000572710577214777017426 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_mus.c * ***********************************************************/ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is MUS_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo music_config_suffix[] = { { ".mode_loop", ARG_UNDEFINED, TYPE_BOOLEAN }, { NULL, NULL, 0 } }; struct ConfigInfo music_config[] = { { "background", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.SCORES", UNDEFINED_FILENAME }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", "rhythmloop.wav" }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1",UNDEFINED_FILENAME }, { "background.titlemessage_initial_2",UNDEFINED_FILENAME }, { "background.titlemessage_initial_3",UNDEFINED_FILENAME }, { "background.titlemessage_initial_4",UNDEFINED_FILENAME }, { "background.titlemessage_initial_5",UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, /* there is no definition for "background.PLAYING", because this would prevent selecting music from music directory that is not defined in "musicinfo.conf", when no default music is defined here */ { NULL, NULL } }; rocksndiamonds-3.3.0.1+dfsg1/src/conf_snd.h0000644000175000017500000002272111375255512017371 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_snd.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_SND_H #define CONF_SND_H /* values for sounds configuration */ #define SND_CLASS_DEFAULT_DIGGING 0 #define SND_CLASS_DEFAULT_COLLECTING 1 #define SND_CLASS_DEFAULT_SNAPPING 2 #define SND_CLASS_DEFAULT_PUSHING 3 #define SND_CLASS_DEFAULT_IMPACT 4 #define SND_CLASS_DEFAULT_WALKING 5 #define SND_CLASS_DEFAULT_PASSING 6 #define SND_CLASS_DEFAULT_DYING 7 #define SND_CLASS_DEFAULT_EXPLODING 8 #define SND_CLASS_SP_DEFAULT_EXPLODING 9 #define SND_BD_DIAMOND_COLLECTING 10 #define SND_BD_DIAMOND_IMPACT 11 #define SND_BD_ROCK_PUSHING 12 #define SND_BD_ROCK_IMPACT 13 #define SND_BD_MAGIC_WALL_ACTIVATING 14 #define SND_BD_MAGIC_WALL_ACTIVE 15 #define SND_BD_MAGIC_WALL_FILLING 16 #define SND_BD_AMOEBA_WAITING 17 #define SND_BD_AMOEBA_GROWING 18 #define SND_BD_AMOEBA_TURNING_TO_GEM 19 #define SND_BD_AMOEBA_TURNING_TO_ROCK 20 #define SND_BD_BUTTERFLY_MOVING 21 #define SND_BD_BUTTERFLY_WAITING 22 #define SND_BD_FIREFLY_MOVING 23 #define SND_BD_FIREFLY_WAITING 24 #define SND_SP_BASE_DIGGING 25 #define SND_SP_BUGGY_BASE_DIGGING 26 #define SND_SP_BUGGY_BASE_ACTIVE 27 #define SND_SP_INFOTRON_COLLECTING 28 #define SND_SP_INFOTRON_IMPACT 29 #define SND_SP_ZONK_PUSHING 30 #define SND_SP_ZONK_IMPACT 31 #define SND_SP_DISK_RED_COLLECTING 32 #define SND_SP_DISK_ORANGE_PUSHING 33 #define SND_SP_DISK_YELLOW_PUSHING 34 #define SND_CLASS_SP_PORT_PASSING 35 #define SND_CLASS_SP_EXIT_PASSING 36 #define SND_CLASS_SP_EXIT_OPENING 37 #define SND_CLASS_SP_EXIT_CLOSING 38 #define SND_SP_SNIKSNAK_MOVING 39 #define SND_SP_SNIKSNAK_WAITING 40 #define SND_SP_ELECTRON_MOVING 41 #define SND_SP_ELECTRON_WAITING 42 #define SND_SP_TERMINAL_ACTIVATING 43 #define SND_SP_TERMINAL_ACTIVE 44 #define SND_CLASS_SOKOBAN_PUSHING 45 #define SND_CLASS_SOKOBAN_FILLING 46 #define SND_CLASS_SOKOBAN_EMPTYING 47 #define SND_CLASS_PLAYER_MOVING 48 #define SND_SAND_DIGGING 49 #define SND_CLASS_EMERALD_COLLECTING 50 #define SND_CLASS_EMERALD_IMPACT 51 #define SND_DIAMOND_COLLECTING 52 #define SND_DIAMOND_IMPACT 53 #define SND_DIAMOND_BREAKING 54 #define SND_ROCK_PUSHING 55 #define SND_ROCK_IMPACT 56 #define SND_BOMB_PUSHING 57 #define SND_NUT_PUSHING 58 #define SND_NUT_BREAKING 59 #define SND_NUT_IMPACT 60 #define SND_CLASS_DYNAMITE_COLLECTING 61 #define SND_CLASS_DYNAMITE_DROPPING 62 #define SND_CLASS_DYNAMITE_ACTIVE 63 #define SND_CLASS_KEY_COLLECTING 64 #define SND_CLASS_GATE_PASSING 65 #define SND_BUG_MOVING 66 #define SND_BUG_WAITING 67 #define SND_SPACESHIP_MOVING 68 #define SND_SPACESHIP_WAITING 69 #define SND_YAMYAM_MOVING 70 #define SND_YAMYAM_WAITING 71 #define SND_YAMYAM_DIGGING 72 #define SND_ROBOT_MOVING 73 #define SND_ROBOT_WAITING 74 #define SND_ROBOT_WHEEL_ACTIVATING 75 #define SND_ROBOT_WHEEL_ACTIVE 76 #define SND_MAGIC_WALL_ACTIVATING 77 #define SND_MAGIC_WALL_ACTIVE 78 #define SND_MAGIC_WALL_FILLING 79 #define SND_DC_MAGIC_WALL_ACTIVATING 80 #define SND_DC_MAGIC_WALL_ACTIVE 81 #define SND_DC_MAGIC_WALL_FILLING 82 #define SND_CLASS_AMOEBA_WAITING 83 #define SND_CLASS_AMOEBA_GROWING 84 #define SND_CLASS_AMOEBA_DROPPING 85 #define SND_ACID_SPLASHING 86 #define SND_CLASS_QUICKSAND_FILLING 87 #define SND_CLASS_QUICKSAND_EMPTYING 88 #define SND_CLASS_EXIT_OPENING 89 #define SND_CLASS_EXIT_CLOSING 90 #define SND_CLASS_EXIT_PASSING 91 #define SND_CLASS_STEEL_EXIT_OPENING 92 #define SND_CLASS_STEEL_EXIT_CLOSING 93 #define SND_CLASS_STEEL_EXIT_PASSING 94 #define SND_CLASS_EM_EXIT_OPENING 95 #define SND_CLASS_EM_EXIT_CLOSING 96 #define SND_CLASS_EM_EXIT_PASSING 97 #define SND_CLASS_EM_STEEL_EXIT_OPENING 98 #define SND_CLASS_EM_STEEL_EXIT_CLOSING 99 #define SND_CLASS_EM_STEEL_EXIT_PASSING 100 #define SND_PENGUIN_PASSING 101 #define SND_BALLOON_MOVING 102 #define SND_BALLOON_WAITING 103 #define SND_BALLOON_PUSHING 104 #define SND_CLASS_BALLOON_SWITCH_ACTIVATING 105 #define SND_SPRING_MOVING 106 #define SND_SPRING_PUSHING 107 #define SND_SPRING_IMPACT 108 #define SND_CLASS_WALL_GROWING 109 #define SND_EMC_ANDROID_PUSHING 110 #define SND_EMC_ANDROID_MOVING 111 #define SND_EMC_ANDROID_DROPPING 112 #define SND_EMC_MAGIC_BALL_DROPPING 113 #define SND_PEARL_COLLECTING 114 #define SND_PEARL_BREAKING 115 #define SND_PEARL_IMPACT 116 #define SND_CRYSTAL_COLLECTING 117 #define SND_CRYSTAL_IMPACT 118 #define SND_CLASS_ENVELOPE_COLLECTING 119 #define SND_CLASS_ENVELOPE_OPENING 120 #define SND_CLASS_ENVELOPE_CLOSING 121 #define SND_INVISIBLE_SAND_DIGGING 122 #define SND_INVISIBLE_SAND_ACTIVE_DIGGING 123 #define SND_SHIELD_NORMAL_COLLECTING 124 #define SND_SHIELD_NORMAL_ACTIVE 125 #define SND_SHIELD_DEADLY_COLLECTING 126 #define SND_SHIELD_DEADLY_ACTIVE 127 #define SND_EXTRA_TIME_COLLECTING 128 #define SND_MOLE_MOVING 129 #define SND_MOLE_WAITING 130 #define SND_MOLE_DIGGING 131 #define SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING 132 #define SND_CLASS_SWITCHGATE_OPENING 133 #define SND_CLASS_SWITCHGATE_CLOSING 134 #define SND_CLASS_SWITCHGATE_PASSING 135 #define SND_CLASS_TIMEGATE_SWITCH_ACTIVATING 136 #define SND_CLASS_TIMEGATE_SWITCH_ACTIVE 137 #define SND_CLASS_TIMEGATE_SWITCH_DEACTIVATING 138 #define SND_CLASS_TIMEGATE_OPENING 139 #define SND_CLASS_TIMEGATE_CLOSING 140 #define SND_CLASS_TIMEGATE_PASSING 141 #define SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING 142 #define SND_CLASS_CONVEYOR_BELT_ACTIVE 143 #define SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING 144 #define SND_LIGHT_SWITCH_ACTIVATING 145 #define SND_LIGHT_SWITCH_DEACTIVATING 146 #define SND_DX_SUPABOMB_PUSHING 147 #define SND_TRAP_DIGGING 148 #define SND_TRAP_ACTIVATING 149 #define SND_CLASS_TUBE_WALKING 150 #define SND_AMOEBA_TURNING_TO_GEM 151 #define SND_AMOEBA_TURNING_TO_ROCK 152 #define SND_SPEED_PILL_COLLECTING 153 #define SND_DYNABOMB_INCREASE_NUMBER_COLLECTING 154 #define SND_DYNABOMB_INCREASE_SIZE_COLLECTING 155 #define SND_DYNABOMB_INCREASE_POWER_COLLECTING 156 #define SND_CLASS_DYNABOMB_DROPPING 157 #define SND_CLASS_DYNABOMB_ACTIVE 158 #define SND_SATELLITE_MOVING 159 #define SND_SATELLITE_WAITING 160 #define SND_SATELLITE_PUSHING 161 #define SND_LAMP_ACTIVATING 162 #define SND_LAMP_DEACTIVATING 163 #define SND_TIME_ORB_FULL_COLLECTING 164 #define SND_TIME_ORB_FULL_IMPACT 165 #define SND_TIME_ORB_EMPTY_PUSHING 166 #define SND_TIME_ORB_EMPTY_IMPACT 167 #define SND_GAME_OF_LIFE_WAITING 168 #define SND_GAME_OF_LIFE_GROWING 169 #define SND_BIOMAZE_WAITING 170 #define SND_BIOMAZE_GROWING 171 #define SND_PACMAN_MOVING 172 #define SND_PACMAN_WAITING 173 #define SND_PACMAN_DIGGING 174 #define SND_DARK_YAMYAM_MOVING 175 #define SND_DARK_YAMYAM_WAITING 176 #define SND_DARK_YAMYAM_DIGGING 177 #define SND_PENGUIN_MOVING 178 #define SND_PENGUIN_WAITING 179 #define SND_PIG_MOVING 180 #define SND_PIG_WAITING 181 #define SND_PIG_DIGGING 182 #define SND_DRAGON_MOVING 183 #define SND_DRAGON_WAITING 184 #define SND_DRAGON_ATTACKING 185 #define SND_GAME_STARTING 186 #define SND_GAME_RUNNING_OUT_OF_TIME 187 #define SND_GAME_LEVELTIME_BONUS 188 #define SND_GAME_LOSING 189 #define SND_GAME_WINNING 190 #define SND_GAME_SOKOBAN_SOLVING 191 #define SND_DOOR_OPENING 192 #define SND_DOOR_CLOSING 193 #define SND_MENU_ITEM_ACTIVATING 194 #define SND_MENU_ITEM_SELECTING 195 #define SND_BACKGROUND_TITLE_INITIAL 196 #define SND_BACKGROUND_TITLE 197 #define SND_BACKGROUND_MAIN 198 #define SND_BACKGROUND_LEVELS 199 #define SND_BACKGROUND_SCORES 200 #define SND_BACKGROUND_EDITOR 201 #define SND_BACKGROUND_INFO 202 #define SND_BACKGROUND_SETUP 203 #define SND_BACKGROUND_TITLESCREEN_INITIAL_1 204 #define SND_BACKGROUND_TITLESCREEN_INITIAL_2 205 #define SND_BACKGROUND_TITLESCREEN_INITIAL_3 206 #define SND_BACKGROUND_TITLESCREEN_INITIAL_4 207 #define SND_BACKGROUND_TITLESCREEN_INITIAL_5 208 #define SND_BACKGROUND_TITLESCREEN_1 209 #define SND_BACKGROUND_TITLESCREEN_2 210 #define SND_BACKGROUND_TITLESCREEN_3 211 #define SND_BACKGROUND_TITLESCREEN_4 212 #define SND_BACKGROUND_TITLESCREEN_5 213 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 214 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_2 215 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_3 216 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_4 217 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_5 218 #define SND_BACKGROUND_TITLEMESSAGE_1 219 #define SND_BACKGROUND_TITLEMESSAGE_2 220 #define SND_BACKGROUND_TITLEMESSAGE_3 221 #define SND_BACKGROUND_TITLEMESSAGE_4 222 #define SND_BACKGROUND_TITLEMESSAGE_5 223 #define NUM_SOUND_FILES 224 #endif /* CONF_SND_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_cus.h0000644000175000017500000003131611375255512017377 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_cus.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CUS_H #define CONF_CUS_H /* values for elements configuration (custom elements) */ #define EL_CUSTOM_1 (EL_CUSTOM_START + 0) #define EL_CUSTOM_2 (EL_CUSTOM_START + 1) #define EL_CUSTOM_3 (EL_CUSTOM_START + 2) #define EL_CUSTOM_4 (EL_CUSTOM_START + 3) #define EL_CUSTOM_5 (EL_CUSTOM_START + 4) #define EL_CUSTOM_6 (EL_CUSTOM_START + 5) #define EL_CUSTOM_7 (EL_CUSTOM_START + 6) #define EL_CUSTOM_8 (EL_CUSTOM_START + 7) #define EL_CUSTOM_9 (EL_CUSTOM_START + 8) #define EL_CUSTOM_10 (EL_CUSTOM_START + 9) #define EL_CUSTOM_11 (EL_CUSTOM_START + 10) #define EL_CUSTOM_12 (EL_CUSTOM_START + 11) #define EL_CUSTOM_13 (EL_CUSTOM_START + 12) #define EL_CUSTOM_14 (EL_CUSTOM_START + 13) #define EL_CUSTOM_15 (EL_CUSTOM_START + 14) #define EL_CUSTOM_16 (EL_CUSTOM_START + 15) #define EL_CUSTOM_17 (EL_CUSTOM_START + 16) #define EL_CUSTOM_18 (EL_CUSTOM_START + 17) #define EL_CUSTOM_19 (EL_CUSTOM_START + 18) #define EL_CUSTOM_20 (EL_CUSTOM_START + 19) #define EL_CUSTOM_21 (EL_CUSTOM_START + 20) #define EL_CUSTOM_22 (EL_CUSTOM_START + 21) #define EL_CUSTOM_23 (EL_CUSTOM_START + 22) #define EL_CUSTOM_24 (EL_CUSTOM_START + 23) #define EL_CUSTOM_25 (EL_CUSTOM_START + 24) #define EL_CUSTOM_26 (EL_CUSTOM_START + 25) #define EL_CUSTOM_27 (EL_CUSTOM_START + 26) #define EL_CUSTOM_28 (EL_CUSTOM_START + 27) #define EL_CUSTOM_29 (EL_CUSTOM_START + 28) #define EL_CUSTOM_30 (EL_CUSTOM_START + 29) #define EL_CUSTOM_31 (EL_CUSTOM_START + 30) #define EL_CUSTOM_32 (EL_CUSTOM_START + 31) #define EL_CUSTOM_33 (EL_CUSTOM_START + 32) #define EL_CUSTOM_34 (EL_CUSTOM_START + 33) #define EL_CUSTOM_35 (EL_CUSTOM_START + 34) #define EL_CUSTOM_36 (EL_CUSTOM_START + 35) #define EL_CUSTOM_37 (EL_CUSTOM_START + 36) #define EL_CUSTOM_38 (EL_CUSTOM_START + 37) #define EL_CUSTOM_39 (EL_CUSTOM_START + 38) #define EL_CUSTOM_40 (EL_CUSTOM_START + 39) #define EL_CUSTOM_41 (EL_CUSTOM_START + 40) #define EL_CUSTOM_42 (EL_CUSTOM_START + 41) #define EL_CUSTOM_43 (EL_CUSTOM_START + 42) #define EL_CUSTOM_44 (EL_CUSTOM_START + 43) #define EL_CUSTOM_45 (EL_CUSTOM_START + 44) #define EL_CUSTOM_46 (EL_CUSTOM_START + 45) #define EL_CUSTOM_47 (EL_CUSTOM_START + 46) #define EL_CUSTOM_48 (EL_CUSTOM_START + 47) #define EL_CUSTOM_49 (EL_CUSTOM_START + 48) #define EL_CUSTOM_50 (EL_CUSTOM_START + 49) #define EL_CUSTOM_51 (EL_CUSTOM_START + 50) #define EL_CUSTOM_52 (EL_CUSTOM_START + 51) #define EL_CUSTOM_53 (EL_CUSTOM_START + 52) #define EL_CUSTOM_54 (EL_CUSTOM_START + 53) #define EL_CUSTOM_55 (EL_CUSTOM_START + 54) #define EL_CUSTOM_56 (EL_CUSTOM_START + 55) #define EL_CUSTOM_57 (EL_CUSTOM_START + 56) #define EL_CUSTOM_58 (EL_CUSTOM_START + 57) #define EL_CUSTOM_59 (EL_CUSTOM_START + 58) #define EL_CUSTOM_60 (EL_CUSTOM_START + 59) #define EL_CUSTOM_61 (EL_CUSTOM_START + 60) #define EL_CUSTOM_62 (EL_CUSTOM_START + 61) #define EL_CUSTOM_63 (EL_CUSTOM_START + 62) #define EL_CUSTOM_64 (EL_CUSTOM_START + 63) #define EL_CUSTOM_65 (EL_CUSTOM_START + 64) #define EL_CUSTOM_66 (EL_CUSTOM_START + 65) #define EL_CUSTOM_67 (EL_CUSTOM_START + 66) #define EL_CUSTOM_68 (EL_CUSTOM_START + 67) #define EL_CUSTOM_69 (EL_CUSTOM_START + 68) #define EL_CUSTOM_70 (EL_CUSTOM_START + 69) #define EL_CUSTOM_71 (EL_CUSTOM_START + 70) #define EL_CUSTOM_72 (EL_CUSTOM_START + 71) #define EL_CUSTOM_73 (EL_CUSTOM_START + 72) #define EL_CUSTOM_74 (EL_CUSTOM_START + 73) #define EL_CUSTOM_75 (EL_CUSTOM_START + 74) #define EL_CUSTOM_76 (EL_CUSTOM_START + 75) #define EL_CUSTOM_77 (EL_CUSTOM_START + 76) #define EL_CUSTOM_78 (EL_CUSTOM_START + 77) #define EL_CUSTOM_79 (EL_CUSTOM_START + 78) #define EL_CUSTOM_80 (EL_CUSTOM_START + 79) #define EL_CUSTOM_81 (EL_CUSTOM_START + 80) #define EL_CUSTOM_82 (EL_CUSTOM_START + 81) #define EL_CUSTOM_83 (EL_CUSTOM_START + 82) #define EL_CUSTOM_84 (EL_CUSTOM_START + 83) #define EL_CUSTOM_85 (EL_CUSTOM_START + 84) #define EL_CUSTOM_86 (EL_CUSTOM_START + 85) #define EL_CUSTOM_87 (EL_CUSTOM_START + 86) #define EL_CUSTOM_88 (EL_CUSTOM_START + 87) #define EL_CUSTOM_89 (EL_CUSTOM_START + 88) #define EL_CUSTOM_90 (EL_CUSTOM_START + 89) #define EL_CUSTOM_91 (EL_CUSTOM_START + 90) #define EL_CUSTOM_92 (EL_CUSTOM_START + 91) #define EL_CUSTOM_93 (EL_CUSTOM_START + 92) #define EL_CUSTOM_94 (EL_CUSTOM_START + 93) #define EL_CUSTOM_95 (EL_CUSTOM_START + 94) #define EL_CUSTOM_96 (EL_CUSTOM_START + 95) #define EL_CUSTOM_97 (EL_CUSTOM_START + 96) #define EL_CUSTOM_98 (EL_CUSTOM_START + 97) #define EL_CUSTOM_99 (EL_CUSTOM_START + 98) #define EL_CUSTOM_100 (EL_CUSTOM_START + 99) #define EL_CUSTOM_101 (EL_CUSTOM_START + 100) #define EL_CUSTOM_102 (EL_CUSTOM_START + 101) #define EL_CUSTOM_103 (EL_CUSTOM_START + 102) #define EL_CUSTOM_104 (EL_CUSTOM_START + 103) #define EL_CUSTOM_105 (EL_CUSTOM_START + 104) #define EL_CUSTOM_106 (EL_CUSTOM_START + 105) #define EL_CUSTOM_107 (EL_CUSTOM_START + 106) #define EL_CUSTOM_108 (EL_CUSTOM_START + 107) #define EL_CUSTOM_109 (EL_CUSTOM_START + 108) #define EL_CUSTOM_110 (EL_CUSTOM_START + 109) #define EL_CUSTOM_111 (EL_CUSTOM_START + 110) #define EL_CUSTOM_112 (EL_CUSTOM_START + 111) #define EL_CUSTOM_113 (EL_CUSTOM_START + 112) #define EL_CUSTOM_114 (EL_CUSTOM_START + 113) #define EL_CUSTOM_115 (EL_CUSTOM_START + 114) #define EL_CUSTOM_116 (EL_CUSTOM_START + 115) #define EL_CUSTOM_117 (EL_CUSTOM_START + 116) #define EL_CUSTOM_118 (EL_CUSTOM_START + 117) #define EL_CUSTOM_119 (EL_CUSTOM_START + 118) #define EL_CUSTOM_120 (EL_CUSTOM_START + 119) #define EL_CUSTOM_121 (EL_CUSTOM_START + 120) #define EL_CUSTOM_122 (EL_CUSTOM_START + 121) #define EL_CUSTOM_123 (EL_CUSTOM_START + 122) #define EL_CUSTOM_124 (EL_CUSTOM_START + 123) #define EL_CUSTOM_125 (EL_CUSTOM_START + 124) #define EL_CUSTOM_126 (EL_CUSTOM_START + 125) #define EL_CUSTOM_127 (EL_CUSTOM_START + 126) #define EL_CUSTOM_128 (EL_CUSTOM_START + 127) #define EL_CUSTOM_129 (EL_CUSTOM_START + 128) #define EL_CUSTOM_130 (EL_CUSTOM_START + 129) #define EL_CUSTOM_131 (EL_CUSTOM_START + 130) #define EL_CUSTOM_132 (EL_CUSTOM_START + 131) #define EL_CUSTOM_133 (EL_CUSTOM_START + 132) #define EL_CUSTOM_134 (EL_CUSTOM_START + 133) #define EL_CUSTOM_135 (EL_CUSTOM_START + 134) #define EL_CUSTOM_136 (EL_CUSTOM_START + 135) #define EL_CUSTOM_137 (EL_CUSTOM_START + 136) #define EL_CUSTOM_138 (EL_CUSTOM_START + 137) #define EL_CUSTOM_139 (EL_CUSTOM_START + 138) #define EL_CUSTOM_140 (EL_CUSTOM_START + 139) #define EL_CUSTOM_141 (EL_CUSTOM_START + 140) #define EL_CUSTOM_142 (EL_CUSTOM_START + 141) #define EL_CUSTOM_143 (EL_CUSTOM_START + 142) #define EL_CUSTOM_144 (EL_CUSTOM_START + 143) #define EL_CUSTOM_145 (EL_CUSTOM_START + 144) #define EL_CUSTOM_146 (EL_CUSTOM_START + 145) #define EL_CUSTOM_147 (EL_CUSTOM_START + 146) #define EL_CUSTOM_148 (EL_CUSTOM_START + 147) #define EL_CUSTOM_149 (EL_CUSTOM_START + 148) #define EL_CUSTOM_150 (EL_CUSTOM_START + 149) #define EL_CUSTOM_151 (EL_CUSTOM_START + 150) #define EL_CUSTOM_152 (EL_CUSTOM_START + 151) #define EL_CUSTOM_153 (EL_CUSTOM_START + 152) #define EL_CUSTOM_154 (EL_CUSTOM_START + 153) #define EL_CUSTOM_155 (EL_CUSTOM_START + 154) #define EL_CUSTOM_156 (EL_CUSTOM_START + 155) #define EL_CUSTOM_157 (EL_CUSTOM_START + 156) #define EL_CUSTOM_158 (EL_CUSTOM_START + 157) #define EL_CUSTOM_159 (EL_CUSTOM_START + 158) #define EL_CUSTOM_160 (EL_CUSTOM_START + 159) #define EL_CUSTOM_161 (EL_CUSTOM_START + 160) #define EL_CUSTOM_162 (EL_CUSTOM_START + 161) #define EL_CUSTOM_163 (EL_CUSTOM_START + 162) #define EL_CUSTOM_164 (EL_CUSTOM_START + 163) #define EL_CUSTOM_165 (EL_CUSTOM_START + 164) #define EL_CUSTOM_166 (EL_CUSTOM_START + 165) #define EL_CUSTOM_167 (EL_CUSTOM_START + 166) #define EL_CUSTOM_168 (EL_CUSTOM_START + 167) #define EL_CUSTOM_169 (EL_CUSTOM_START + 168) #define EL_CUSTOM_170 (EL_CUSTOM_START + 169) #define EL_CUSTOM_171 (EL_CUSTOM_START + 170) #define EL_CUSTOM_172 (EL_CUSTOM_START + 171) #define EL_CUSTOM_173 (EL_CUSTOM_START + 172) #define EL_CUSTOM_174 (EL_CUSTOM_START + 173) #define EL_CUSTOM_175 (EL_CUSTOM_START + 174) #define EL_CUSTOM_176 (EL_CUSTOM_START + 175) #define EL_CUSTOM_177 (EL_CUSTOM_START + 176) #define EL_CUSTOM_178 (EL_CUSTOM_START + 177) #define EL_CUSTOM_179 (EL_CUSTOM_START + 178) #define EL_CUSTOM_180 (EL_CUSTOM_START + 179) #define EL_CUSTOM_181 (EL_CUSTOM_START + 180) #define EL_CUSTOM_182 (EL_CUSTOM_START + 181) #define EL_CUSTOM_183 (EL_CUSTOM_START + 182) #define EL_CUSTOM_184 (EL_CUSTOM_START + 183) #define EL_CUSTOM_185 (EL_CUSTOM_START + 184) #define EL_CUSTOM_186 (EL_CUSTOM_START + 185) #define EL_CUSTOM_187 (EL_CUSTOM_START + 186) #define EL_CUSTOM_188 (EL_CUSTOM_START + 187) #define EL_CUSTOM_189 (EL_CUSTOM_START + 188) #define EL_CUSTOM_190 (EL_CUSTOM_START + 189) #define EL_CUSTOM_191 (EL_CUSTOM_START + 190) #define EL_CUSTOM_192 (EL_CUSTOM_START + 191) #define EL_CUSTOM_193 (EL_CUSTOM_START + 192) #define EL_CUSTOM_194 (EL_CUSTOM_START + 193) #define EL_CUSTOM_195 (EL_CUSTOM_START + 194) #define EL_CUSTOM_196 (EL_CUSTOM_START + 195) #define EL_CUSTOM_197 (EL_CUSTOM_START + 196) #define EL_CUSTOM_198 (EL_CUSTOM_START + 197) #define EL_CUSTOM_199 (EL_CUSTOM_START + 198) #define EL_CUSTOM_200 (EL_CUSTOM_START + 199) #define EL_CUSTOM_201 (EL_CUSTOM_START + 200) #define EL_CUSTOM_202 (EL_CUSTOM_START + 201) #define EL_CUSTOM_203 (EL_CUSTOM_START + 202) #define EL_CUSTOM_204 (EL_CUSTOM_START + 203) #define EL_CUSTOM_205 (EL_CUSTOM_START + 204) #define EL_CUSTOM_206 (EL_CUSTOM_START + 205) #define EL_CUSTOM_207 (EL_CUSTOM_START + 206) #define EL_CUSTOM_208 (EL_CUSTOM_START + 207) #define EL_CUSTOM_209 (EL_CUSTOM_START + 208) #define EL_CUSTOM_210 (EL_CUSTOM_START + 209) #define EL_CUSTOM_211 (EL_CUSTOM_START + 210) #define EL_CUSTOM_212 (EL_CUSTOM_START + 211) #define EL_CUSTOM_213 (EL_CUSTOM_START + 212) #define EL_CUSTOM_214 (EL_CUSTOM_START + 213) #define EL_CUSTOM_215 (EL_CUSTOM_START + 214) #define EL_CUSTOM_216 (EL_CUSTOM_START + 215) #define EL_CUSTOM_217 (EL_CUSTOM_START + 216) #define EL_CUSTOM_218 (EL_CUSTOM_START + 217) #define EL_CUSTOM_219 (EL_CUSTOM_START + 218) #define EL_CUSTOM_220 (EL_CUSTOM_START + 219) #define EL_CUSTOM_221 (EL_CUSTOM_START + 220) #define EL_CUSTOM_222 (EL_CUSTOM_START + 221) #define EL_CUSTOM_223 (EL_CUSTOM_START + 222) #define EL_CUSTOM_224 (EL_CUSTOM_START + 223) #define EL_CUSTOM_225 (EL_CUSTOM_START + 224) #define EL_CUSTOM_226 (EL_CUSTOM_START + 225) #define EL_CUSTOM_227 (EL_CUSTOM_START + 226) #define EL_CUSTOM_228 (EL_CUSTOM_START + 227) #define EL_CUSTOM_229 (EL_CUSTOM_START + 228) #define EL_CUSTOM_230 (EL_CUSTOM_START + 229) #define EL_CUSTOM_231 (EL_CUSTOM_START + 230) #define EL_CUSTOM_232 (EL_CUSTOM_START + 231) #define EL_CUSTOM_233 (EL_CUSTOM_START + 232) #define EL_CUSTOM_234 (EL_CUSTOM_START + 233) #define EL_CUSTOM_235 (EL_CUSTOM_START + 234) #define EL_CUSTOM_236 (EL_CUSTOM_START + 235) #define EL_CUSTOM_237 (EL_CUSTOM_START + 236) #define EL_CUSTOM_238 (EL_CUSTOM_START + 237) #define EL_CUSTOM_239 (EL_CUSTOM_START + 238) #define EL_CUSTOM_240 (EL_CUSTOM_START + 239) #define EL_CUSTOM_241 (EL_CUSTOM_START + 240) #define EL_CUSTOM_242 (EL_CUSTOM_START + 241) #define EL_CUSTOM_243 (EL_CUSTOM_START + 242) #define EL_CUSTOM_244 (EL_CUSTOM_START + 243) #define EL_CUSTOM_245 (EL_CUSTOM_START + 244) #define EL_CUSTOM_246 (EL_CUSTOM_START + 245) #define EL_CUSTOM_247 (EL_CUSTOM_START + 246) #define EL_CUSTOM_248 (EL_CUSTOM_START + 247) #define EL_CUSTOM_249 (EL_CUSTOM_START + 248) #define EL_CUSTOM_250 (EL_CUSTOM_START + 249) #define EL_CUSTOM_251 (EL_CUSTOM_START + 250) #define EL_CUSTOM_252 (EL_CUSTOM_START + 251) #define EL_CUSTOM_253 (EL_CUSTOM_START + 252) #define EL_CUSTOM_254 (EL_CUSTOM_START + 253) #define EL_CUSTOM_255 (EL_CUSTOM_START + 254) #define EL_CUSTOM_256 (EL_CUSTOM_START + 255) #endif /* CONF_CUS_C */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/0000755000175000017500000000000011403523060017007 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/src/libgame/toons.h0000644000175000017500000000320610471574615020343 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * toons.h * ***********************************************************/ #ifndef TOONS_H #define TOONS_H #include "system.h" struct ToonScreenInfo { Bitmap *save_buffer; void (*update_function)(void); void (*prepare_backbuffer_function)(void); boolean (*redraw_needed_function)(void); struct ToonInfo *toons; int num_toons; int startx, starty; int width, height; int frame_delay_value; }; struct ToonInfo { Bitmap *bitmap; int src_x, src_y; int width, height; int anim_frames; int anim_start_frame; int anim_delay; int anim_mode; int step_offset; int step_delay; char *direction; char *position; }; int getAnimationFrame(int, int, int, int, int); void InitToonScreen(Bitmap *, void (*update_function)(void), void (*prepare_backbuffer_function)(void), boolean (*redraw_needed_function)(void), struct ToonInfo *, int, int, int, int, int, int); void InitAnimation(void); void StopAnimation(void); void DoAnimation(void); #endif /* TOONS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/random.c0000644000175000017500000002447010471575154020461 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * random.c * ***********************************************************/ /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * This is derived from the Berkeley source: * @(#)random.c 5.5 (Berkeley) 7/6/88 * It was reworked for the GNU C Library by Roland McGrath. */ #include #include #include #include "random.h" /* An improved random number generation package. In addition to the standard rand()/srand() like interface, this package also has a special state info interface. The initstate() routine is called with a seed, an array of bytes, and a count of how many bytes are being passed in; this array is then initialized to contain information for random number generation with that much state information. Good sizes for the amount of state information are 32, 64, 128, and 256 bytes. The state can be switched by calling the setstate() function with the same array as was initiallized with initstate(). By default, the package runs with 128 bytes of state information and generates far better random numbers than a linear congruential generator. If the amount of state information is less than 32 bytes, a simple linear congruential R.N.G. is used. Internally, the state information is treated as an array of longs; the zeroeth element of the array is the type of R.N.G. being used (small integer); the remainder of the array is the state information for the R.N.G. Thus, 32 bytes of state information will give 7 longs worth of state information, which will allow a degree seven polynomial. (Note: The zeroeth word of state information also has some other information stored in it; see setstate for details). The random number generation technique is a linear feedback shift register approach, employing trinomials (since there are fewer terms to sum up that way). In this approach, the least significant bit of all the numbers in the state table will act as a linear feedback shift register, and will have period 2^deg - 1 (where deg is the degree of the polynomial being used, assuming that the polynomial is irreducible and primitive). The higher order bits will have longer periods, since their values are also influenced by pseudo-random carries out of the lower bits. The total period of the generator is approximately deg*(2**deg - 1); thus doubling the amount of state information has a vast influence on the period of the generator. Note: The deg*(2**deg - 1) is an approximation only good for large deg, when the period of the shift register is the dominant factor. With deg equal to seven, the period is actually much longer than the 7*(2**7 - 1) predicted by this formula. */ /* For each of the currently supported random number generators, we have a break value on the amount of state information (you need at least thi bytes of state info to support this random number generator), a degree for the polynomial (actually a trinomial) that the R.N.G. is based on, and separation between the two lower order coefficients of the trinomial. */ /* Linear congruential. */ #define TYPE_0 0 #define BREAK_0 8 #define DEG_0 0 #define SEP_0 0 /* x**7 + x**3 + 1. */ #define TYPE_1 1 #define BREAK_1 32 #define DEG_1 7 #define SEP_1 3 /* x**15 + x + 1. */ #define TYPE_2 2 #define BREAK_2 64 #define DEG_2 15 #define SEP_2 1 /* x**31 + x**3 + 1. */ #define TYPE_3 3 #define BREAK_3 128 #define DEG_3 31 #define SEP_3 3 /* x**63 + x + 1. */ #define TYPE_4 4 #define BREAK_4 256 #define DEG_4 63 #define SEP_4 1 /* Array versions of the above information to make code run faster. Relies on fact that TYPE_i == i. */ #define MAX_TYPES 5 /* Max number of types above. */ /* Initially, everything is set up as if from: initstate(1, randtbl, 128); Note that this initialization takes advantage of the fact that srandom advances the front and rear pointers 10*rand_deg times, and hence the rear pointer which starts at 0 will also end up at zero; thus the zeroeth element of the state information, which contains info about the current position of the rear pointer is just (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ static long int randtbl_0[DEG_3 + 1] = { TYPE_3, -851904987, -43806228, -2029755270, 1390239686, -1912102820, -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, -1714531963, 1800685987, -2015299881, 654595283, -1149023258, -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, -607508183, -205999574, -1696891592, 1492211999, -1528267240, -952028296, -189082757, 362343714, 1424981831, 2039449641, }; static long int randtbl_1[DEG_3 + 1] = { TYPE_3, -851904987, -43806228, -2029755270, 1390239686, -1912102820, -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, -1714531963, 1800685987, -2015299881, 654595283, -1149023258, -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, -607508183, -205999574, -1696891592, 1492211999, -1528267240, -952028296, -189082757, 362343714, 1424981831, 2039449641, }; /* FPTR and RPTR are two pointers into the state info, a front and a rear pointer. These two pointers are always rand_sep places aparts, as they cycle through the state information. (Yes, this does mean we could get away with just one pointer, but the code for random is more efficient this way). The pointers are left positioned as they would be from the call: initstate(1, randtbl, 128); (The position of the rear pointer, rptr, is really 0 (as explained above in the initialization of randtbl) because the state table pointer is set to point to randtbl[1] (as explained below).) */ static long int *fptr[2] = { &randtbl_0[SEP_3 + 1], &randtbl_1[SEP_3 + 1] }; static long int *rptr[2] = { &randtbl_0[1], &randtbl_1[1] }; /* The following things are the pointer to the state information table, the type of the current generator, the degree of the current polynomial being used, and the separation between the two pointers. Note that for efficiency of random, we remember the first location of the state information, not the zeroeth. Hence it is valid to access state[-1], which is used to store the type of the R.N.G. Also, we remember the last location, since this is more efficient than indexing every time to find the address of the last element to see if the front and rear pointers have wrapped. */ static long int *state[2] = { &randtbl_0[1], &randtbl_1[1] }; static int rand_type[2] = { TYPE_3, TYPE_3 }; static int rand_deg[2] = { DEG_3, DEG_3 }; static int rand_sep[2] = { SEP_3, SEP_3 }; static long int *end_ptr[2] = { &randtbl_0[sizeof(randtbl_0) / sizeof(randtbl_0[0])], &randtbl_1[sizeof(randtbl_1) / sizeof(randtbl_1[0])] }; /* Initialize the random number generator based on the given seed. If the type is the trivial no-state-information type, just remember the seed. Otherwise, initializes state[] based on the given "seed" via a linear congruential generator. Then, the pointers are set to known locations that are exactly rand_sep places apart. Lastly, it cycles the state information a given number of times to get rid of any initial dependencies introduced by the L.C.R.N.G. Note that the initialization of randtbl[] for default usage relies on values produced by this routine. */ void srandom_linux_libc(int nr, unsigned int x) { state[nr][0] = x; if (rand_type[nr] != TYPE_0) { register long int i; for (i = 1; i < rand_deg[nr]; ++i) state[nr][i] = (1103515145 * state[nr][i - 1]) + 12345; fptr[nr] = &state[nr][rand_sep[nr]]; rptr[nr] = &state[nr][0]; for (i = 0; i < 10 * rand_deg[nr]; ++i) random_linux_libc(nr); } } /* If we are using the trivial TYPE_0 R.N.G., just do the old linear congruential bit. Otherwise, we do our fancy trinomial stuff, which is the same in all ther other cases due to all the global variables that have been set up. The basic operation is to add the number at the rear pointer into the one at the front pointer. Then both pointers are advanced to the next location cyclically in the table. The value returned is the sum generated, reduced to 31 bits by throwing away the "least random" low bit. Note: The code takes advantage of the fact that both the front and rear pointers can't wrap on the same call by not testing the rear pointer if the front one has wrapped. Returns a 31-bit random number. */ long int random_linux_libc(int nr) { if (rand_type[nr] == TYPE_0) { state[nr][0] = ((state[nr][0] * 1103515245) + 12345) & LONG_MAX; return state[nr][0]; } else { long int i; *fptr[nr] += *rptr[nr]; /* Chucking least random bit. */ i = (*fptr[nr] >> 1) & LONG_MAX; fptr[nr]++; if (fptr[nr] >= end_ptr[nr]) { fptr[nr] = state[nr]; rptr[nr]++; } else { rptr[nr]++; if (rptr[nr] >= end_ptr[nr]) rptr[nr] = state[nr]; } return i; } } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/msdos.h0000644000175000017500000005524610471574464020343 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * msdos.h * ***********************************************************/ #ifndef MSDOS_H #define MSDOS_H #include #include "allegro.h" /* symbol 'window' is defined in DJGPP cross-compiler in libc.a(conio.o) */ #define window window_internal /* symbol 'font' is defined in "allegro.h" */ #define font font_internal /* system dependent definitions */ #define TARGET_STRING "DOS" /* allegro defines TRUE as -1 */ #ifdef TRUE #undef TRUE #undef FALSE #endif #define TRUE 1 #define FALSE 0 #define XRES 800 #define YRES 600 /* allegro defines some macros that bother the rest of the program */ #ifdef joy_x #undef joy_x #undef joy_y #undef joy_left #undef joy_right #undef joy_up #undef joy_down #undef joy_b1 #undef joy_b2 #endif /* additional Allegro keyboard mapping */ /* The following are all undefined in Allegro */ #define NEW_KEY_BACKSLASH 86 #define NEW_KEY_1_PAD 101 #define NEW_KEY_2_PAD 102 #define NEW_KEY_3_PAD 103 #define NEW_KEY_4_PAD 104 #define NEW_KEY_5_PAD 105 #define NEW_KEY_6_PAD 106 #define NEW_KEY_7_PAD 107 #define NEW_KEY_8_PAD 108 #define NEW_KEY_9_PAD 109 #define NEW_KEY_0_PAD 110 #define NEW_KEY_STOP_PAD 111 #define NEW_KEY_EQUALS_PAD 112 #define NEW_KEY_SLASH_PAD 113 #define NEW_KEY_ASTERISK_PAD 114 #define NEW_KEY_ENTER_PAD 115 /* X11 keyboard mapping (from 'keysymdef.h') */ #define XK_VoidSymbol 0xFFFFFF /* void symbol */ /* * TTY Functions, cleverly chosen to map to ascii, for convenience of * programming, but could have been arbitrary (at the cost of lookup * tables in client code. */ #define XK_BackSpace 0xFF08 /* back space, back char */ #define XK_Tab 0xFF09 #define XK_Linefeed 0xFF0A /* Linefeed, LF */ #define XK_Clear 0xFF0B #define XK_Return 0xFF0D /* Return, enter */ #define XK_Pause 0xFF13 /* Pause, hold */ #define XK_Scroll_Lock 0xFF14 #define XK_Sys_Req 0xFF15 #define XK_Escape 0xFF1B #define XK_Delete 0xFFFF /* Delete, rubout */ /* International & multi-key character composition */ #define XK_Multi_key 0xFF20 /* Multi-key character compose */ #define XK_SingleCandidate 0xFF3C #define XK_MultipleCandidate 0xFF3D #define XK_PreviousCandidate 0xFF3E /* Cursor control & motion */ #define XK_Home 0xFF50 #define XK_Left 0xFF51 /* Move left, left arrow */ #define XK_Up 0xFF52 /* Move up, up arrow */ #define XK_Right 0xFF53 /* Move right, right arrow */ #define XK_Down 0xFF54 /* Move down, down arrow */ #define XK_Prior 0xFF55 /* Prior, previous */ #define XK_Page_Up 0xFF55 #define XK_Next 0xFF56 /* Next */ #define XK_Page_Down 0xFF56 #define XK_End 0xFF57 /* EOL */ #define XK_Begin 0xFF58 /* BOL */ /* Misc Functions */ #define XK_Select 0xFF60 /* Select, mark */ #define XK_Print 0xFF61 #define XK_Execute 0xFF62 /* Execute, run, do */ #define XK_Insert 0xFF63 /* Insert, insert here */ #define XK_Undo 0xFF65 /* Undo, oops */ #define XK_Redo 0xFF66 /* redo, again */ #define XK_Menu 0xFF67 #define XK_Find 0xFF68 /* Find, search */ #define XK_Cancel 0xFF69 /* Cancel, stop, abort, exit */ #define XK_Help 0xFF6A /* Help */ #define XK_Break 0xFF6B #define XK_Mode_switch 0xFF7E /* Character set switch */ #define XK_script_switch 0xFF7E /* Alias for mode_switch */ #define XK_Num_Lock 0xFF7F /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ #define XK_KP_Space 0xFF80 /* space */ #define XK_KP_Tab 0xFF89 #define XK_KP_Enter 0xFF8D /* enter */ #define XK_KP_F1 0xFF91 /* PF1, KP_A, ... */ #define XK_KP_F2 0xFF92 #define XK_KP_F3 0xFF93 #define XK_KP_F4 0xFF94 #define XK_KP_Home 0xFF95 #define XK_KP_Left 0xFF96 #define XK_KP_Up 0xFF97 #define XK_KP_Right 0xFF98 #define XK_KP_Down 0xFF99 #define XK_KP_Prior 0xFF9A #define XK_KP_Page_Up 0xFF9A #define XK_KP_Next 0xFF9B #define XK_KP_Page_Down 0xFF9B #define XK_KP_End 0xFF9C #define XK_KP_Begin 0xFF9D #define XK_KP_Insert 0xFF9E #define XK_KP_Delete 0xFF9F #define XK_KP_Equal 0xFFBD /* equals */ #define XK_KP_Multiply 0xFFAA #define XK_KP_Add 0xFFAB #define XK_KP_Separator 0xFFAC /* separator, often comma */ #define XK_KP_Subtract 0xFFAD #define XK_KP_Decimal 0xFFAE #define XK_KP_Divide 0xFFAF #define XK_KP_0 0xFFB0 #define XK_KP_1 0xFFB1 #define XK_KP_2 0xFFB2 #define XK_KP_3 0xFFB3 #define XK_KP_4 0xFFB4 #define XK_KP_5 0xFFB5 #define XK_KP_6 0xFFB6 #define XK_KP_7 0xFFB7 #define XK_KP_8 0xFFB8 #define XK_KP_9 0xFFB9 /* * Auxilliary Functions; note the duplicate definitions for left and right * function keys; Sun keyboards and a few other manufactures have such * function key groups on the left and/or right sides of the keyboard. * We've not found a keyboard with more than 35 function keys total. */ #define XK_F1 0xFFBE #define XK_F2 0xFFBF #define XK_F3 0xFFC0 #define XK_F4 0xFFC1 #define XK_F5 0xFFC2 #define XK_F6 0xFFC3 #define XK_F7 0xFFC4 #define XK_F8 0xFFC5 #define XK_F9 0xFFC6 #define XK_F10 0xFFC7 #define XK_F11 0xFFC8 #define XK_L1 0xFFC8 #define XK_F12 0xFFC9 #define XK_L2 0xFFC9 #define XK_F13 0xFFCA #define XK_L3 0xFFCA #define XK_F14 0xFFCB #define XK_L4 0xFFCB #define XK_F15 0xFFCC #define XK_L5 0xFFCC #define XK_F16 0xFFCD #define XK_L6 0xFFCD #define XK_F17 0xFFCE #define XK_L7 0xFFCE #define XK_F18 0xFFCF #define XK_L8 0xFFCF #define XK_F19 0xFFD0 #define XK_L9 0xFFD0 #define XK_F20 0xFFD1 #define XK_L10 0xFFD1 #define XK_F21 0xFFD2 #define XK_R1 0xFFD2 #define XK_F22 0xFFD3 #define XK_R2 0xFFD3 #define XK_F23 0xFFD4 #define XK_R3 0xFFD4 #define XK_F24 0xFFD5 #define XK_R4 0xFFD5 #define XK_F25 0xFFD6 #define XK_R5 0xFFD6 #define XK_F26 0xFFD7 #define XK_R6 0xFFD7 #define XK_F27 0xFFD8 #define XK_R7 0xFFD8 #define XK_F28 0xFFD9 #define XK_R8 0xFFD9 #define XK_F29 0xFFDA #define XK_R9 0xFFDA #define XK_F30 0xFFDB #define XK_R10 0xFFDB #define XK_F31 0xFFDC #define XK_R11 0xFFDC #define XK_F32 0xFFDD #define XK_R12 0xFFDD #define XK_F33 0xFFDE #define XK_R13 0xFFDE #define XK_F34 0xFFDF #define XK_R14 0xFFDF #define XK_F35 0xFFE0 #define XK_R15 0xFFE0 /* Modifiers */ #define XK_Shift_L 0xFFE1 /* Left shift */ #define XK_Shift_R 0xFFE2 /* Right shift */ #define XK_Control_L 0xFFE3 /* Left control */ #define XK_Control_R 0xFFE4 /* Right control */ #define XK_Caps_Lock 0xFFE5 /* Caps lock */ #define XK_Shift_Lock 0xFFE6 /* Shift lock */ #define XK_Meta_L 0xFFE7 /* Left meta */ #define XK_Meta_R 0xFFE8 /* Right meta */ #define XK_Alt_L 0xFFE9 /* Left alt */ #define XK_Alt_R 0xFFEA /* Right alt */ #define XK_Super_L 0xFFEB /* Left super */ #define XK_Super_R 0xFFEC /* Right super */ #define XK_Hyper_L 0xFFED /* Left hyper */ #define XK_Hyper_R 0xFFEE /* Right hyper */ /* * Latin 1 * Byte 3 = 0 */ #define XK_space 0x020 #define XK_exclam 0x021 #define XK_quotedbl 0x022 #define XK_numbersign 0x023 #define XK_dollar 0x024 #define XK_percent 0x025 #define XK_ampersand 0x026 #define XK_apostrophe 0x027 #define XK_quoteright 0x027 /* deprecated */ #define XK_parenleft 0x028 #define XK_parenright 0x029 #define XK_asterisk 0x02a #define XK_plus 0x02b #define XK_comma 0x02c #define XK_minus 0x02d #define XK_period 0x02e #define XK_slash 0x02f #define XK_0 0x030 #define XK_1 0x031 #define XK_2 0x032 #define XK_3 0x033 #define XK_4 0x034 #define XK_5 0x035 #define XK_6 0x036 #define XK_7 0x037 #define XK_8 0x038 #define XK_9 0x039 #define XK_colon 0x03a #define XK_semicolon 0x03b #define XK_less 0x03c #define XK_equal 0x03d #define XK_greater 0x03e #define XK_question 0x03f #define XK_at 0x040 #define XK_A 0x041 #define XK_B 0x042 #define XK_C 0x043 #define XK_D 0x044 #define XK_E 0x045 #define XK_F 0x046 #define XK_G 0x047 #define XK_H 0x048 #define XK_I 0x049 #define XK_J 0x04a #define XK_K 0x04b #define XK_L 0x04c #define XK_M 0x04d #define XK_N 0x04e #define XK_O 0x04f #define XK_P 0x050 #define XK_Q 0x051 #define XK_R 0x052 #define XK_S 0x053 #define XK_T 0x054 #define XK_U 0x055 #define XK_V 0x056 #define XK_W 0x057 #define XK_X 0x058 #define XK_Y 0x059 #define XK_Z 0x05a #define XK_bracketleft 0x05b #define XK_backslash 0x05c #define XK_bracketright 0x05d #define XK_asciicircum 0x05e #define XK_underscore 0x05f #define XK_grave 0x060 #define XK_quoteleft 0x060 /* deprecated */ #define XK_a 0x061 #define XK_b 0x062 #define XK_c 0x063 #define XK_d 0x064 #define XK_e 0x065 #define XK_f 0x066 #define XK_g 0x067 #define XK_h 0x068 #define XK_i 0x069 #define XK_j 0x06a #define XK_k 0x06b #define XK_l 0x06c #define XK_m 0x06d #define XK_n 0x06e #define XK_o 0x06f #define XK_p 0x070 #define XK_q 0x071 #define XK_r 0x072 #define XK_s 0x073 #define XK_t 0x074 #define XK_u 0x075 #define XK_v 0x076 #define XK_w 0x077 #define XK_x 0x078 #define XK_y 0x079 #define XK_z 0x07a #define XK_braceleft 0x07b #define XK_bar 0x07c #define XK_braceright 0x07d #define XK_asciitilde 0x07e #define XK_nobreakspace 0x0a0 #define XK_exclamdown 0x0a1 #define XK_cent 0x0a2 #define XK_sterling 0x0a3 #define XK_currency 0x0a4 #define XK_yen 0x0a5 #define XK_brokenbar 0x0a6 #define XK_section 0x0a7 #define XK_diaeresis 0x0a8 #define XK_copyright 0x0a9 #define XK_ordfeminine 0x0aa #define XK_guillemotleft 0x0ab /* left angle quotation mark */ #define XK_notsign 0x0ac #define XK_hyphen 0x0ad #define XK_registered 0x0ae #define XK_macron 0x0af #define XK_degree 0x0b0 #define XK_plusminus 0x0b1 #define XK_twosuperior 0x0b2 #define XK_threesuperior 0x0b3 #define XK_acute 0x0b4 #define XK_mu 0x0b5 #define XK_paragraph 0x0b6 #define XK_periodcentered 0x0b7 #define XK_cedilla 0x0b8 #define XK_onesuperior 0x0b9 #define XK_masculine 0x0ba #define XK_guillemotright 0x0bb /* right angle quotation mark */ #define XK_onequarter 0x0bc #define XK_onehalf 0x0bd #define XK_threequarters 0x0be #define XK_questiondown 0x0bf #define XK_Agrave 0x0c0 #define XK_Aacute 0x0c1 #define XK_Acircumflex 0x0c2 #define XK_Atilde 0x0c3 #define XK_Adiaeresis 0x0c4 #define XK_Aring 0x0c5 #define XK_AE 0x0c6 #define XK_Ccedilla 0x0c7 #define XK_Egrave 0x0c8 #define XK_Eacute 0x0c9 #define XK_Ecircumflex 0x0ca #define XK_Ediaeresis 0x0cb #define XK_Igrave 0x0cc #define XK_Iacute 0x0cd #define XK_Icircumflex 0x0ce #define XK_Idiaeresis 0x0cf #define XK_ETH 0x0d0 #define XK_Eth 0x0d0 /* deprecated */ #define XK_Ntilde 0x0d1 #define XK_Ograve 0x0d2 #define XK_Oacute 0x0d3 #define XK_Ocircumflex 0x0d4 #define XK_Otilde 0x0d5 #define XK_Odiaeresis 0x0d6 #define XK_multiply 0x0d7 #define XK_Ooblique 0x0d8 #define XK_Ugrave 0x0d9 #define XK_Uacute 0x0da #define XK_Ucircumflex 0x0db #define XK_Udiaeresis 0x0dc #define XK_Yacute 0x0dd #define XK_THORN 0x0de #define XK_Thorn 0x0de /* deprecated */ #define XK_ssharp 0x0df #define XK_agrave 0x0e0 #define XK_aacute 0x0e1 #define XK_acircumflex 0x0e2 #define XK_atilde 0x0e3 #define XK_adiaeresis 0x0e4 #define XK_aring 0x0e5 #define XK_ae 0x0e6 #define XK_ccedilla 0x0e7 #define XK_egrave 0x0e8 #define XK_eacute 0x0e9 #define XK_ecircumflex 0x0ea #define XK_ediaeresis 0x0eb #define XK_igrave 0x0ec #define XK_iacute 0x0ed #define XK_icircumflex 0x0ee #define XK_idiaeresis 0x0ef #define XK_eth 0x0f0 #define XK_ntilde 0x0f1 #define XK_ograve 0x0f2 #define XK_oacute 0x0f3 #define XK_ocircumflex 0x0f4 #define XK_otilde 0x0f5 #define XK_odiaeresis 0x0f6 #define XK_division 0x0f7 #define XK_oslash 0x0f8 #define XK_ugrave 0x0f9 #define XK_uacute 0x0fa #define XK_ucircumflex 0x0fb #define XK_udiaeresis 0x0fc #define XK_yacute 0x0fd #define XK_thorn 0x0fe #define XK_ydiaeresis 0x0ff /* end of X11 keyboard mapping */ #define screen myscreen #define XFlush(a) #define XGetImage(a,b,c,d,e,f,g,h) ((XImage *) NULL) #define XDisplayName(a) ((char *) NULL) #define XFreeColors(a,b,c,d,e) #define XSelectInput(a,b,c) #define XDefaultDepth(a,b) (8) #define XSetWMProperties(a,b,c,d,e,f,g,h,i) #define MAX_EVENT_BUFFER 256 #define MAX_SCANCODES 128 #define True 1 #define False 0 #define None 0L #define DUMMY_FILE ((void *) -1) #define DUMMY_MASK (-1) #define KeyPressMask (1L << 0) #define KeyReleaseMask (1L << 1) #define ButtonPressMask (1L << 2) #define ButtonReleaseMask (1L << 3) #define ButtonMotionMask (1L << 13) #define ExposureMask (1L << 15) #define StructureNotifyMask (1L << 17) #define FocusChangeMask (1L << 21) #define KeyPress 2 #define KeyRelease 3 #define ButtonPress 4 #define ButtonRelease 5 #define MotionNotify 6 #define FocusIn 9 #define FocusOut 10 #define Expose 12 #define UnmapNotify 18 #define MapNotify 19 #define ClientMessage 33 #define LineSolid 0 #define LineOnOffDash 1 #define LineDoubleDash 2 #define CapNotLast 0 #define CapButt 1 #define CapRound 2 #define CapProjecting 3 #define JoinMiter 0 #define JoinRound 1 #define JoinBevel 2 #define GCForeground (1L << 2) #define GCBackground (1L << 3) #define GCLineWidth (1L << 4) #define GCLineStyle (1L << 5) #define GCCapStyle (1L << 6) #define GCJoinStyle (1L << 7) #define GCGraphicsExposures (1L << 16) #define GCClipMask (1L << 19) #define NormalState 1 /* most applications want to start this way */ #define InputHint (1L << 0) #define StateHint (1L << 1) #define IconPixmapHint (1L << 2) #define IconMaskHint (1L << 5) #define PSize (1L << 3) /* program specified size */ #define PMinSize (1L << 4) /* program specified minimum size */ #define PMaxSize (1L << 5) /* program specified maximum size */ #define PCX_Success 0 #define PCX_OpenFailed -1 #define PCX_ReadFailed -2 #define PCX_FileInvalid -3 #define PCX_NoMemory -4 #define PCX_ColorFailed -5 #define BitmapSuccess 0 #define BitmapOpenFailed 1 #define BitmapFileInvalid 2 #define BitmapNoMemory 3 #define ZPixmap 2 /* depth == drawable depth */ #define DefaultScreen(dpy) (((_XPrivDisplay)dpy)->default_screen) #define DefaultColormap(dpy, scr) (ScreenOfDisplay(dpy,scr)->cmap) #define ScreenOfDisplay(dpy, scr) (&((_XPrivDisplay)dpy)->screens[scr]) #define BlackPixel(dpy, scr) (ScreenOfDisplay(dpy,scr)->black_pixel) #define WhitePixel(dpy, scr) (ScreenOfDisplay(dpy,scr)->white_pixel) #define RootWindow(dpy, scr) (ScreenOfDisplay(dpy,scr)->root) #define AllPlanes ((unsigned long)~0L) #define DefaultVisual(dpy, scr) (NULL) #define DefaultDepth(dpy, scr) (NULL) #define XDisplayWidth(dpy, scr) (XRES) #define XDisplayHeight(dpy, scr) (YRES) #define XGetPixel(ximage, x, y) \ ((*((ximage)->f.get_pixel))((ximage), (x), (y))) typedef unsigned long Pixel; /* Index into colormap */ typedef unsigned long XID; typedef XID Window; typedef XID Drawable; typedef XID Pixmap; typedef XID Colormap; typedef XID KeySym; typedef XID GContext; typedef struct _XDisplay Display; typedef long Visual; typedef long XVisualInfo; typedef long Atom; typedef int Status; typedef int Bool; typedef int XComposeStatus; /* we don't need the real type */ typedef struct _XGC { GContext gid; /* protocol ID for graphics context */ } *GC; typedef struct { Colormap cmap; /* default color map */ Window root; /* root window id */ unsigned long white_pixel; /* white pixel value */ unsigned long black_pixel; /* black pixel value */ int x; int y; unsigned int width; unsigned int height; BITMAP *video_bitmap; } Screen; typedef struct _XDisplay { int default_screen; /* default screen for operations */ Screen *screens; /* pointer to list of screens */ BITMAP *mouse_ptr; } *_XPrivDisplay; typedef struct _XImage { struct funcs { unsigned long (*get_pixel) (struct _XImage *, int, int); } f; } XImage; typedef struct { long flags; /* marks which fields in this structure are defined */ int width, height; /* should set so old wm's don't mess up */ int min_width, min_height; int max_width, max_height; } XSizeHints; typedef struct { long flags; /* marks which fields in this structure are defined */ Bool input; /* does this application rely on the window manager to get keyboard input? */ int initial_state; /* see below */ Pixmap icon_pixmap; /* pixmap to be used as icon */ Pixmap icon_mask; /* icon mask bitmap */ } XWMHints; typedef struct { char *res_name; char *res_class; } XClassHint; typedef struct { unsigned char *value; /* same as Property routines */ } XTextProperty; typedef struct { unsigned long foreground; /* foreground pixel */ unsigned long background; /* background pixel */ Bool graphics_exposures; /* boolean, should exposures be generated */ Pixmap clip_mask; /* bitmap clipping; other calls for rects */ int clip_x_origin; /* x origin for clipping */ int clip_y_origin; /* y origin for clipping */ unsigned long value_mask; int line_width; /* line width */ int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash */ int cap_style; /* CapNotLast, CapButt, CapRound, CapProjecting */ int join_style; /* JoinMiter, JoinRound, JoinBevel */ } XGCValues; typedef struct { int type; int x, y; int width, height; } XExposeEvent; typedef struct { int type; /* of event */ int x, y; /* pointer x, y coordinates in event window */ unsigned int button; /* detail */ } XButtonEvent; typedef struct { int type; int x, y; /* pointer x, y coordinates in event window */ } XMotionEvent; typedef struct { int type; /* of event */ unsigned int state; /* key or button mask */ } XKeyEvent; typedef struct { int type; /* FocusIn or FocusOut */ } XFocusChangeEvent; typedef struct { int type; /* ClientMessage */ } XClientMessageEvent; typedef union _XEvent { int type; /* must not be changed; first element */ XExposeEvent xexpose; XButtonEvent xbutton; XMotionEvent xmotion; XKeyEvent xkey; } XEvent; Pixel AllegroAllocColorCell(int, int, int); void XMapWindow(Display *, Window); Display *XOpenDisplay(char *); Window XCreateSimpleWindow(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long); Status XStringListToTextProperty(char **, int, XTextProperty *); void XFree(void *); GC XCreateGC(Display *, Drawable, unsigned long, XGCValues *); void XSetClipMask(Display *, GC, Pixmap); void XSetClipOrigin(Display *, GC, int, int); void XFillRectangle(Display *, Drawable, GC, int, int, unsigned int, unsigned int); Pixmap XCreatePixmap(Display *, Drawable, unsigned int, unsigned int, unsigned int); void XSync(Display *, Bool); void XCopyArea(Display *, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int); int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *); int XReadBitmapFile(Display *, Drawable, char *, unsigned int *, unsigned int *, Pixmap *, int *, int *); void XFreePixmap(Display *, Pixmap); void XFreeGC(Display *, GC); void XUnmapWindow(Display *, Window); void XCloseDisplay(Display *); void XNextEvent(Display *, XEvent *); int XPending(Display *); KeySym XLookupKeysym(XKeyEvent *, int); int XLookupString(XKeyEvent *, char *, int, KeySym *, XComposeStatus *); void XSetForeground(Display *, GC, unsigned long); void XDrawLine(Display *, Drawable, GC, int, int, int, int); void XDestroyImage(XImage *); void XDestroyWindow(Display *, Window); Bool XQueryPointer(Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *); void XAutoRepeatOn(Display *); void XAutoRepeatOff(Display *); void AllegroDrawLine(Drawable, int, int, int, int, Pixel); Pixel AllegroGetPixel(Drawable, int, int); void AllegroZoomBitmap(Drawable, Drawable, int, int, int, int); void MSDOSOpenAudio(void); void MSDOSCloseAudio(void); void NetworkServer(int, int); void MSDOSInitJoysticks(); boolean MSDOSReadJoystick(int, int *, int *, boolean *, boolean *); #endif /* MSDOS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/toons.c0000644000175000017500000002650510673060670020340 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * toons.c * ***********************************************************/ #include "toons.h" #include "misc.h" /* values for toon animation */ #define ANIM_START 0 #define ANIM_CONTINUE 1 #define ANIM_STOP 2 static struct ToonScreenInfo screen_info; /* ========================================================================= */ /* generic animation frame calculation */ /* ========================================================================= */ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, int sync_frame) { int frame = 0; sync_frame += start_frame * delay; if (mode & ANIM_LOOP) /* looping animation */ { frame = (sync_frame % (delay * num_frames)) / delay; } else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */ { frame = sync_frame / delay; if (frame > num_frames - 1) frame = num_frames - 1; } else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */ { int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1); frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame); } else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */ { int max_anim_frames = 2 * num_frames; frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame - 1); } else if (mode & ANIM_RANDOM) /* play frames in random order */ { /* note: expect different frames for the same delay cycle! */ if (gfx.anim_random_frame < 0) frame = GetSimpleRandom(num_frames); else frame = gfx.anim_random_frame % num_frames; } else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY)) { frame = sync_frame % num_frames; } if (mode & ANIM_REVERSE) /* use reverse animation direction */ frame = num_frames - frame - 1; return frame; } /* ========================================================================= */ /* toon animation functions */ /* ========================================================================= */ static int get_toon_direction(char *direction_string_raw) { char *direction_string = getStringToLower(direction_string_raw); int direction = (strEqual(direction_string, "left") ? MV_LEFT : strEqual(direction_string, "right") ? MV_RIGHT : strEqual(direction_string, "up") ? MV_UP : strEqual(direction_string, "down") ? MV_DOWN : MV_NONE); free(direction_string); return direction; } void InitToonScreen(Bitmap *save_buffer, void (*update_function)(void), void (*prepare_backbuffer_function)(void), boolean (*redraw_needed_function)(void), struct ToonInfo *toons, int num_toons, int startx, int starty, int width, int height, int frame_delay_value) { screen_info.save_buffer = save_buffer; screen_info.update_function = update_function; screen_info.prepare_backbuffer_function = prepare_backbuffer_function; screen_info.redraw_needed_function = redraw_needed_function; screen_info.toons = toons; screen_info.num_toons = num_toons; screen_info.startx = startx; screen_info.starty = starty; screen_info.width = width; screen_info.height = height; screen_info.frame_delay_value = frame_delay_value; } void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y, int pad_x, int pad_y) { int pad_dest_x = dest_x - pad_x; int pad_dest_y = dest_y - pad_y; int pad_width = width + 2 * pad_x; int pad_height = height + 2 * pad_y; #if 1 int buffer_x = 0; int buffer_y = 0; #else int buffer_x = DOOR_GFX_PAGEX3; int buffer_y = DOOR_GFX_PAGEY1; #endif #if 0 printf("::: (%d, %d), (%d, %d), (%d, %d), (%d, %d) -> (%d, %d), (%d, %d), (%d, %d)\n", src_x, src_y, width, height, dest_x, dest_y, pad_x, pad_y, pad_dest_x, pad_dest_y, pad_width, pad_height, buffer_x, buffer_y); #endif /* correct values to avoid off-screen blitting (start position) */ if (pad_dest_x < screen_info.startx) { pad_width -= (screen_info.startx - pad_dest_x); pad_dest_x = screen_info.startx; } if (pad_dest_y < screen_info.starty) { pad_height -= (screen_info.starty - pad_dest_y); pad_dest_y = screen_info.starty; } /* correct values to avoid off-screen blitting (blit size) */ if (pad_width > screen_info.width) pad_width = screen_info.width; if (pad_height > screen_info.height) pad_height = screen_info.height; /* special method to avoid flickering interference with BackToFront() */ BlitBitmap(backbuffer, screen_info.save_buffer, pad_dest_x, pad_dest_y, pad_width, pad_height, buffer_x, buffer_y); SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x - src_x, dest_y - src_y); BlitBitmapMasked(toon_bitmap, backbuffer, src_x, src_y, width, height, dest_x, dest_y); BlitBitmap(backbuffer, window, pad_dest_x, pad_dest_y, pad_width, pad_height, pad_dest_x, pad_dest_y); screen_info.update_function(); BlitBitmap(screen_info.save_buffer, backbuffer, buffer_x, buffer_y, pad_width, pad_height, pad_dest_x, pad_dest_y); FlushDisplay(); } boolean AnimateToon(int toon_nr, boolean restart) { static unsigned long animation_frame_counter = 0; static int pos_x = 0, pos_y = 0; static int delta_x = 0, delta_y = 0; static int frame = 0; static boolean horiz_move, vert_move; static unsigned long anim_delay = 0; static unsigned long anim_delay_value = 0; static int width,height; static int pad_x,pad_y; static int cut_x,cut_y; static int src_x, src_y; static int dest_x, dest_y; struct ToonInfo *anim = &screen_info.toons[toon_nr]; Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap; GC anim_clip_gc = anim_bitmap->stored_clip_gc; int direction = get_toon_direction(anim->direction); if (restart) { horiz_move = (direction & (MV_LEFT | MV_RIGHT)); vert_move = (direction & (MV_UP | MV_DOWN)); anim_delay_value = anim->step_delay * screen_info.frame_delay_value; frame = getAnimationFrame(anim->anim_frames, anim->anim_delay, anim->anim_mode, anim->anim_start_frame, animation_frame_counter++); if (horiz_move) { int pos_bottom = screen_info.height - anim->height; if (strEqual(anim->position, "top")) pos_y = 0; else if (strEqual(anim->position, "bottom")) pos_y = pos_bottom; else if (strEqual(anim->position, "upper")) pos_y = GetSimpleRandom(pos_bottom / 2); else if (strEqual(anim->position, "lower")) pos_y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2); else pos_y = GetSimpleRandom(pos_bottom); if (direction == MV_RIGHT) { delta_x = anim->step_offset; pos_x = -anim->width + delta_x; } else { delta_x = -anim->step_offset; pos_x = screen_info.width + delta_x; } delta_y = 0; } else { int pos_right = screen_info.width - anim->width; if (strEqual(anim->position, "left")) pos_x = 0; else if (strEqual(anim->position, "right")) pos_x = pos_right; else pos_x = GetSimpleRandom(pos_right); if (direction == MV_DOWN) { delta_y = anim->step_offset; pos_y = -anim->height + delta_y; } else { delta_y = -anim->step_offset; pos_y = screen_info.height + delta_y; } delta_x = 0; } } if (pos_x <= -anim->width - anim->step_offset || pos_x >= screen_info.width + anim->step_offset || pos_y <= -anim->height - anim->step_offset || pos_y >= screen_info.height + anim->step_offset) return TRUE; if (!DelayReached(&anim_delay, anim_delay_value)) { if (screen_info.redraw_needed_function() && !restart) DrawAnim(anim_bitmap, anim_clip_gc, src_x + cut_x, src_y + cut_y, width, height, screen_info.startx + dest_x, screen_info.starty + dest_y, pad_x, pad_y); return FALSE; } if (pos_x < -anim->width) pos_x = -anim->width; else if (pos_x > screen_info.width) pos_x = screen_info.width; if (pos_y < -anim->height) pos_y = -anim->height; else if (pos_y > screen_info.height) pos_y = screen_info.height; pad_x = (horiz_move ? anim->step_offset : 0); pad_y = (vert_move ? anim->step_offset : 0); src_x = anim->src_x + frame * anim->width; src_y = anim->src_y; dest_x = pos_x; dest_y = pos_y; cut_x = cut_y = 0; width = anim->width; height = anim->height; if (pos_x < 0) { dest_x = 0; width += pos_x; cut_x = -pos_x; } else if (pos_x > screen_info.width - anim->width) width -= (pos_x - (screen_info.width - anim->width)); if (pos_y < 0) { dest_y = 0; height += pos_y; cut_y = -pos_y; } else if (pos_y > screen_info.height - anim->height) height -= (pos_y - (screen_info.height - anim->height)); DrawAnim(anim_bitmap, anim_clip_gc, src_x + cut_x, src_y + cut_y, width, height, screen_info.startx + dest_x, screen_info.starty + dest_y, pad_x, pad_y); pos_x += delta_x; pos_y += delta_y; frame = getAnimationFrame(anim->anim_frames, anim->anim_delay, anim->anim_mode, anim->anim_start_frame, animation_frame_counter++); return FALSE; } void HandleAnimation(int mode) { static unsigned long animstart_delay = -1; static unsigned long animstart_delay_value = 0; static boolean anim_running = FALSE; static boolean anim_restart = TRUE; static boolean reset_delay = TRUE; static int toon_nr = 0; if (!setup.toons || screen_info.num_toons == 0) return; /* this may happen after reloading graphics and redefining "num_toons" */ if (toon_nr >= screen_info.num_toons) anim_restart = TRUE; switch(mode) { case ANIM_START: screen_info.prepare_backbuffer_function(); anim_running = TRUE; anim_restart = TRUE; reset_delay = TRUE; return; case ANIM_CONTINUE: if (!anim_running) return; break; case ANIM_STOP: if (anim_running) { #if 1 redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER); screen_info.update_function(); #endif anim_running = FALSE; } return; default: break; } if (reset_delay) { animstart_delay = Counter(); animstart_delay_value = GetSimpleRandom(3000); reset_delay = FALSE; } if (anim_restart) { if (!DelayReached(&animstart_delay, animstart_delay_value)) return; toon_nr = GetSimpleRandom(screen_info.num_toons); } anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart); } void InitAnimation() { HandleAnimation(ANIM_START); } void StopAnimation() { HandleAnimation(ANIM_STOP); } void DoAnimation() { HandleAnimation(ANIM_CONTINUE); } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/x11.h0000644000175000017500000002305111355446175017613 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * x11.h * ***********************************************************/ #ifndef X11_H #define X11_H #if !defined(PLATFORM_MSDOS) #define XK_MISCELLANY #define XK_LATIN1 #include #include #include #include #include #include #endif /* system dependent definitions */ /* MS-DOS header file also defines "TARGET_STRING" */ #ifndef TARGET_STRING #define TARGET_STRING "X11" #endif #if defined(PLATFORM_UNIX) /* This triggers some stuff that is needed because X11 (XSetClipOrigin(), to be precise) is often very slow when preparing a masked XCopyArea() for big Pixmaps. To prevent this, small (tile-sized) mask Pixmaps are created which will then be set much faster with XSetClipOrigin() and speed things up a lot. */ #define TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND #endif #define FULLSCREEN_STATUS FULLSCREEN_NOT_AVAILABLE #define CURSOR_MAX_WIDTH 32 #define CURSOR_MAX_HEIGHT 32 /* X11 type definitions */ typedef struct X11DrawableInfo Bitmap; typedef struct X11DrawableInfo DrawWindow; typedef struct X11DrawableInfo DrawBuffer; /* "Pixel" is already defined */ /* "Cursor" is already defined */ typedef KeySym Key; typedef unsigned int KeyMod; typedef XEvent Event; typedef XButtonEvent ButtonEvent; typedef XMotionEvent MotionEvent; typedef XKeyEvent KeyEvent; typedef XExposeEvent ExposeEvent; typedef XFocusChangeEvent FocusChangeEvent; typedef XClientMessageEvent ClientMessageEvent; /* structure definitions */ struct X11DrawableInfo { char *source_filename; unsigned int width, height; Drawable drawable; Drawable clip_mask; GC gc; /* GC for normal drawing (inheritated from 'window') */ GC line_gc[2]; /* GC for foreground and background line drawing */ GC stored_clip_gc; /* GC for masked drawing (used for whole Pixmap) */ GC clip_gc; /* can be 'stored_clip_gc' or one-tile-only clip GC */ }; struct MouseCursorInfo { int width, height; int hot_x, hot_y; char data[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; char mask[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; }; /* X11 symbol definitions */ #define BLACK_PIXEL BlackPixel(display, screen) #define WHITE_PIXEL WhitePixel(display, screen) #define EVENT_BUTTONPRESS ButtonPress #define EVENT_BUTTONRELEASE ButtonRelease #define EVENT_MOTIONNOTIFY MotionNotify #define EVENT_KEYPRESS KeyPress #define EVENT_KEYRELEASE KeyRelease #define EVENT_EXPOSE Expose #define EVENT_FOCUSIN FocusIn #define EVENT_FOCUSOUT FocusOut #define EVENT_CLIENTMESSAGE ClientMessage #define EVENT_MAPNOTIFY MapNotify #define EVENT_UNMAPNOTIFY UnmapNotify #define KSYM_UNDEFINED XK_VoidSymbol #define KSYM_Return XK_Return #define KSYM_Escape XK_Escape #define KSYM_Left XK_Left #define KSYM_Right XK_Right #define KSYM_Up XK_Up #define KSYM_Down XK_Down #ifdef XK_KP_Left #define KSYM_KP_Left XK_KP_Left #define KSYM_KP_Right XK_KP_Right #define KSYM_KP_Up XK_KP_Up #define KSYM_KP_Down XK_KP_Down #endif #ifdef XK_KP_Enter #define KSYM_KP_Enter XK_KP_Enter #define KSYM_KP_Add XK_KP_Add #define KSYM_KP_Subtract XK_KP_Subtract #define KSYM_KP_Multiply XK_KP_Multiply #define KSYM_KP_Divide XK_KP_Divide #define KSYM_KP_Separator XK_KP_Separator #endif #define KSYM_Shift_L XK_Shift_L #define KSYM_Shift_R XK_Shift_R #define KSYM_Control_L XK_Control_L #define KSYM_Control_R XK_Control_R #define KSYM_Meta_L XK_Meta_L #define KSYM_Meta_R XK_Meta_R #define KSYM_Alt_L XK_Alt_L #define KSYM_Alt_R XK_Alt_R #define KSYM_Super_L XK_Super_L #define KSYM_Super_R XK_Super_R #define KSYM_Mode_switch XK_Mode_switch #define KSYM_Multi_key XK_Multi_key #define KSYM_BackSpace XK_BackSpace #define KSYM_Delete XK_Delete #define KSYM_Insert XK_Insert #define KSYM_Tab XK_Tab #define KSYM_Home XK_Home #define KSYM_End XK_End #define KSYM_Page_Up XK_Page_Up #define KSYM_Page_Down XK_Page_Down #define KSYM_Menu XK_Menu #define KSYM_space XK_space #define KSYM_exclam XK_exclam #define KSYM_quotedbl XK_quotedbl #define KSYM_numbersign XK_numbersign #define KSYM_dollar XK_dollar #define KSYM_percent XK_percent #define KSYM_ampersand XK_ampersand #define KSYM_apostrophe XK_apostrophe #define KSYM_parenleft XK_parenleft #define KSYM_parenright XK_parenright #define KSYM_asterisk XK_asterisk #define KSYM_plus XK_plus #define KSYM_comma XK_comma #define KSYM_minus XK_minus #define KSYM_period XK_period #define KSYM_slash XK_slash #define KSYM_colon XK_colon #define KSYM_semicolon XK_semicolon #define KSYM_less XK_less #define KSYM_equal XK_equal #define KSYM_greater XK_greater #define KSYM_question XK_question #define KSYM_at XK_at #define KSYM_bracketleft XK_bracketleft #define KSYM_backslash XK_backslash #define KSYM_bracketright XK_bracketright #define KSYM_asciicircum XK_asciicircum #define KSYM_underscore XK_underscore #define KSYM_grave XK_grave #define KSYM_quoteleft XK_quoteleft #define KSYM_braceleft XK_braceleft #define KSYM_bar XK_bar #define KSYM_braceright XK_braceright #define KSYM_asciitilde XK_asciitilde #define KSYM_degree XK_degree #define KSYM_Adiaeresis XK_Adiaeresis #define KSYM_Odiaeresis XK_Odiaeresis #define KSYM_Udiaeresis XK_Udiaeresis #define KSYM_adiaeresis XK_adiaeresis #define KSYM_odiaeresis XK_odiaeresis #define KSYM_udiaeresis XK_udiaeresis #define KSYM_ssharp XK_ssharp #define KSYM_A XK_A #define KSYM_B XK_B #define KSYM_C XK_C #define KSYM_D XK_D #define KSYM_E XK_E #define KSYM_F XK_F #define KSYM_G XK_G #define KSYM_H XK_H #define KSYM_I XK_I #define KSYM_J XK_J #define KSYM_K XK_K #define KSYM_L XK_L #define KSYM_M XK_M #define KSYM_N XK_N #define KSYM_O XK_O #define KSYM_P XK_P #define KSYM_Q XK_Q #define KSYM_R XK_R #define KSYM_S XK_S #define KSYM_T XK_T #define KSYM_U XK_U #define KSYM_V XK_V #define KSYM_W XK_W #define KSYM_X XK_X #define KSYM_Y XK_Y #define KSYM_Z XK_Z #define KSYM_a XK_a #define KSYM_b XK_b #define KSYM_c XK_c #define KSYM_d XK_d #define KSYM_e XK_e #define KSYM_f XK_f #define KSYM_g XK_g #define KSYM_h XK_h #define KSYM_i XK_i #define KSYM_j XK_j #define KSYM_k XK_k #define KSYM_l XK_l #define KSYM_m XK_m #define KSYM_n XK_n #define KSYM_o XK_o #define KSYM_p XK_p #define KSYM_q XK_q #define KSYM_r XK_r #define KSYM_s XK_s #define KSYM_t XK_t #define KSYM_u XK_u #define KSYM_v XK_v #define KSYM_w XK_w #define KSYM_x XK_x #define KSYM_y XK_y #define KSYM_z XK_z #define KSYM_0 XK_0 #define KSYM_1 XK_1 #define KSYM_2 XK_2 #define KSYM_3 XK_3 #define KSYM_4 XK_4 #define KSYM_5 XK_5 #define KSYM_6 XK_6 #define KSYM_7 XK_7 #define KSYM_8 XK_8 #define KSYM_9 XK_9 #define KSYM_KP_0 XK_KP_0 #define KSYM_KP_1 XK_KP_1 #define KSYM_KP_2 XK_KP_2 #define KSYM_KP_3 XK_KP_3 #define KSYM_KP_4 XK_KP_4 #define KSYM_KP_5 XK_KP_5 #define KSYM_KP_6 XK_KP_6 #define KSYM_KP_7 XK_KP_7 #define KSYM_KP_8 XK_KP_8 #define KSYM_KP_9 XK_KP_9 #define KSYM_F1 XK_F1 #define KSYM_F2 XK_F2 #define KSYM_F3 XK_F3 #define KSYM_F4 XK_F4 #define KSYM_F5 XK_F5 #define KSYM_F6 XK_F6 #define KSYM_F7 XK_F7 #define KSYM_F8 XK_F8 #define KSYM_F9 XK_F9 #define KSYM_F10 XK_F10 #define KSYM_F11 XK_F11 #define KSYM_F12 XK_F12 #define KSYM_F13 XK_F13 #define KSYM_F14 XK_F14 #define KSYM_F15 XK_F15 #define KSYM_F16 XK_F16 #define KSYM_F17 XK_F17 #define KSYM_F18 XK_F18 #define KSYM_F19 XK_F19 #define KSYM_F20 XK_F20 #define KSYM_F21 XK_F21 #define KSYM_F22 XK_F22 #define KSYM_F23 XK_F23 #define KSYM_F24 XK_F24 #define KSYM_FKEY_FIRST KSYM_F1 #define KSYM_FKEY_LAST KSYM_F24 #define KSYM_NUM_FKEYS (KSYM_FKEY_LAST - KSYM_FKEY_FIRST + 1) #define KMOD_None None #define KMOD_Shift_L 0x0001 #define KMOD_Shift_R 0x0002 #define KMOD_Control_L 0x0040 #define KMOD_Control_R 0x0080 #define KMOD_Meta_L 0x0400 #define KMOD_Meta_R 0x0800 #define KMOD_Alt_L 0x0100 #define KMOD_Alt_R 0x0200 #define KMOD_Shift (KMOD_Shift_L | KMOD_Shift_R) #define KMOD_Control (KMOD_Control_L | KMOD_Control_R) #define KMOD_Meta (KMOD_Meta_L | KMOD_Meta_R) #define KMOD_Alt (KMOD_Alt_L | KMOD_Alt_R) /* X11 function definitions */ void X11InitVideoDisplay(void); void X11InitVideoBuffer(DrawBuffer **, DrawWindow **); void X11CloseWindow(DrawWindow *); void X11ZoomBitmap(Bitmap *, Bitmap *); Bitmap *X11LoadImage(char *); void X11CreateBitmapContent(Bitmap *, int, int, int); void X11FreeBitmapPointers(Bitmap *); void X11CopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int); void X11FillRectangle(Bitmap *, int, int, int, int, Pixel); void X11FadeRectangle(Bitmap *, int, int, int, int, int, int, int, void (*draw_border_function)(void)); void X11DrawSimpleLine(Bitmap *, int, int, int, int, Pixel); Pixel X11GetPixel(Bitmap *, int, int); Pixel X11GetPixelFromRGB(unsigned int, unsigned int, unsigned int); void X11DestroyImage(XImage *); #if defined(TARGET_X11_NATIVE) void X11SetMouseCursor(struct MouseCursorInfo *); #endif #endif /* X11_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/gadgets.h0000644000175000017500000002322010540053474020605 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * gadgets.h * ***********************************************************/ #ifndef GADGETS_H #define GADGETS_H #include "system.h" #define GADGET_FRAME_DELAY_FIRST 250 /* delay after first click */ #define GADGET_FRAME_DELAY 100 /* delay for pressed butten */ /* gadget types */ #define GD_TYPE_NORMAL_BUTTON (1 << 0) #define GD_TYPE_TEXT_BUTTON (1 << 1) #define GD_TYPE_CHECK_BUTTON (1 << 2) #define GD_TYPE_RADIO_BUTTON (1 << 3) #define GD_TYPE_DRAWING_AREA (1 << 4) #define GD_TYPE_TEXT_INPUT_ALPHANUMERIC (1 << 5) #define GD_TYPE_TEXT_INPUT_NUMERIC (1 << 6) #define GD_TYPE_TEXT_AREA (1 << 7) #define GD_TYPE_SELECTBOX (1 << 8) #define GD_TYPE_SCROLLBAR_VERTICAL (1 << 9) #define GD_TYPE_SCROLLBAR_HORIZONTAL (1 << 10) #define GD_TYPE_BUTTON (GD_TYPE_NORMAL_BUTTON | \ GD_TYPE_TEXT_BUTTON | \ GD_TYPE_CHECK_BUTTON | \ GD_TYPE_RADIO_BUTTON) #define GD_TYPE_SCROLLBAR (GD_TYPE_SCROLLBAR_VERTICAL | \ GD_TYPE_SCROLLBAR_HORIZONTAL) #define GD_TYPE_TEXT_INPUT (GD_TYPE_TEXT_INPUT_ALPHANUMERIC | \ GD_TYPE_TEXT_INPUT_NUMERIC) /* gadget events */ #define GD_EVENT_PRESSED (1 << 0) #define GD_EVENT_RELEASED (1 << 1) #define GD_EVENT_MOVING (1 << 2) #define GD_EVENT_REPEATED (1 << 3) #define GD_EVENT_OFF_BORDERS (1 << 4) #define GD_EVENT_TEXT_RETURN (1 << 5) #define GD_EVENT_TEXT_LEAVING (1 << 6) #define GD_EVENT_INFO_ENTERING (1 << 7) #define GD_EVENT_INFO_LEAVING (1 << 8) /* gadget button states */ #define GD_BUTTON_UNPRESSED 0 #define GD_BUTTON_PRESSED 1 /* gadget structure constants */ #define MAX_GADGET_TEXTSIZE 1024 #define MAX_INFO_TEXTSIZE 1024 /* gadget creation tags */ #define GDI_END 0 #define GDI_CUSTOM_ID 1 #define GDI_CUSTOM_TYPE_ID 2 #define GDI_X 3 #define GDI_Y 4 #define GDI_WIDTH 5 #define GDI_HEIGHT 6 #define GDI_TYPE 7 #define GDI_STATE 8 #define GDI_CHECKED 9 #define GDI_RADIO_NR 10 #define GDI_NUMBER_VALUE 11 #define GDI_NUMBER_MIN 12 #define GDI_NUMBER_MAX 13 #define GDI_TEXT_VALUE 14 #define GDI_TEXT_SIZE 15 #define GDI_TEXT_FONT 16 #define GDI_TEXT_FONT_ACTIVE 17 #define GDI_SELECTBOX_OPTIONS 18 #define GDI_SELECTBOX_INDEX 19 #define GDI_DESIGN_UNPRESSED 20 #define GDI_DESIGN_PRESSED 21 #define GDI_ALT_DESIGN_UNPRESSED 22 #define GDI_ALT_DESIGN_PRESSED 23 #define GDI_BORDER_SIZE 24 #define GDI_BORDER_SIZE_SELECTBUTTON 25 #define GDI_DESIGN_WIDTH 26 #define GDI_DECORATION_DESIGN 27 #define GDI_DECORATION_POSITION 28 #define GDI_DECORATION_SIZE 29 #define GDI_DECORATION_SHIFTING 30 #define GDI_EVENT_MASK 31 #define GDI_EVENT 32 #define GDI_CALLBACK_INFO 33 #define GDI_CALLBACK_ACTION 34 #define GDI_AREA_SIZE 35 #define GDI_ITEM_SIZE 36 #define GDI_SCROLLBAR_ITEMS_MAX 37 #define GDI_SCROLLBAR_ITEMS_VISIBLE 38 #define GDI_SCROLLBAR_ITEM_POSITION 39 #define GDI_WHEEL_AREA_X 40 #define GDI_WHEEL_AREA_Y 41 #define GDI_WHEEL_AREA_WIDTH 42 #define GDI_WHEEL_AREA_HEIGHT 43 #define GDI_INFO_TEXT 44 #define GDI_ACTIVE 45 #define GDI_DIRECT_DRAW 46 typedef void (*gadget_function)(void *); struct GadgetBorder { int xsize, ysize; /* size of gadget border */ int xsize_selectbutton; /* for selectbox gadgets */ int width; /* for selectbox/text input gadgets */ }; struct GadgetDesign { Bitmap *bitmap; /* Bitmap with gadget surface */ int x, y; /* position of rectangle in Bitmap */ }; struct GadgetDecoration { struct GadgetDesign design; /* decoration design structure */ int x, y; /* position of deco on the gadget */ int width, height; /* width and height of decoration */ int xshift, yshift; /* deco shifting when gadget pressed */ }; struct GadgetEvent { unsigned long type; /* event type */ int button; /* button number for button events */ int x, y; /* gadget position at event time */ boolean off_borders; /* mouse pointer outside gadget? */ int item_x, item_y, item_position; /* new item position */ }; struct GadgetDrawingArea { int area_xsize, area_ysize; /* size of drawing area (in items) */ int item_xsize, item_ysize; /* size of each item in drawing area */ }; struct GadgetTextButton { char value[MAX_GADGET_TEXTSIZE + 1]; /* text written on the button */ int size; /* maximal size of button text */ }; struct GadgetTextInput { char value[MAX_GADGET_TEXTSIZE + 1]; /* text string in input field */ char last_value[MAX_GADGET_TEXTSIZE + 1];/* last text string in input field */ int cursor_position; /* actual text cursor position */ int number_value; /* integer value, if numeric */ int number_min; /* minimal allowed numeric value */ int number_max; /* maximal allowed numeric value */ int size; /* maximal size of input text */ }; struct GadgetTextArea { char value[MAX_GADGET_TEXTSIZE + 1]; /* text string in input field */ char last_value[MAX_GADGET_TEXTSIZE + 1];/* last text string in input field */ int cursor_position; /* actual text cursor position */ int cursor_x; /* actual x cursor position */ int cursor_y; /* actual y cursor position */ int cursor_x_preferred; /* "preferred" x cursor position */ int size; /* maximal size of input text */ int xsize, ysize; /* size of text area (in chars) */ }; struct GadgetSelectbox { struct ValueTextInfo *options; /* pointer to text/value array */ int index; /* index of actual text string */ int size; /* maximal size of text strings */ /* automatically determined values */ int x, y; /* open selectbox position */ int width, height; /* open selectbox size */ int num_values; /* number of text strings */ Pixel inverse_color; /* color for highlighting */ /* runtime values */ boolean open; /* opening state of selectbox */ boolean stay_open; /* open after button release */ int current_index; /* index of text while selecting */ }; struct GadgetScrollbar { int items_max; /* number of items to access */ int items_visible; /* number of visible items */ int item_position; /* actual item position */ int size_min; /* minimal scrollbar size */ int size_max; /* this is either width or height */ int size_max_cmp; /* needed for minimal scrollbar size */ int size; /* scrollbar size on screen */ int position; /* scrollbar position on screen */ int position_max; /* bottom/right scrollbar position */ int drag_position; /* drag position on scrollbar */ int correction; /* scrollbar position correction */ }; struct GadgetWheelArea { int x, y; /* active area for wheel (start) */ int width, height; /* active area for wheel (size) */ }; struct GadgetInfo { int id; /* internal gadget identifier */ int custom_id; /* custom gadget identifier */ int custom_type_id; /* custom gadget type identifier */ char info_text[MAX_INFO_TEXTSIZE + 1];/* short popup info text */ int x, y; /* gadget position */ int width, height; /* gadget size */ unsigned int type; /* type (button, text input, ...) */ unsigned int state; /* state (pressed, released, ...) */ boolean checked; /* check/radio button state */ int radio_nr; /* number of radio button series */ boolean mapped; /* gadget is mapped on the screen */ boolean active; /* gadget is active */ boolean direct_draw; /* directly draw to frontbuffer */ int font; /* font to use when inactive */ int font_active; /* font to use when active */ struct GadgetBorder border; /* gadget border design */ struct GadgetDesign design[2]; /* 0: normal; 1: pressed */ struct GadgetDesign alt_design[2]; /* alternative design */ struct GadgetDecoration deco; /* decoration on top of gadget */ unsigned int event_mask; /* possible events for this gadget */ struct GadgetEvent event; /* actual gadget event */ gadget_function callback_info; /* function for pop-up info text */ gadget_function callback_action; /* function for gadget action */ struct GadgetDrawingArea drawing; /* fields for drawing area gadget */ struct GadgetTextButton textbutton; /* fields for text button gadget */ struct GadgetTextInput textinput; /* fields for text input gadget */ struct GadgetTextArea textarea; /* fields for text area gadget */ struct GadgetSelectbox selectbox; /* fields for selectbox gadget */ struct GadgetScrollbar scrollbar; /* fields for scrollbar gadget */ struct GadgetWheelArea wheelarea; /* fields for scroll wheel area */ struct GadgetInfo *next; /* next list entry */ }; void InitGadgetsSoundCallback(void (*activating_function)(void), void (*selecting_function)(void)); struct GadgetInfo *CreateGadget(int, ...); void FreeGadget(struct GadgetInfo *); void ModifyGadget(struct GadgetInfo *, int, ...); void RedrawGadget(struct GadgetInfo *); void MapGadget(struct GadgetInfo *); void UnmapGadget(struct GadgetInfo *); void UnmapAllGadgets(); void RemapAllGadgets(); boolean anyTextInputGadgetActive(); boolean anyTextAreaGadgetActive(); boolean anySelectboxGadgetActive(); boolean anyScrollbarGadgetActive(); boolean anyTextGadgetActive(); void ClickOnGadget(struct GadgetInfo *, int); boolean HandleGadgets(int, int, int); boolean HandleGadgetsKeyInput(Key); #endif /* GADGETS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/random.h0000644000175000017500000000152510471574520020456 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * random.h * ***********************************************************/ #ifndef RANDOM_H #define RANDOM_H void srandom_linux_libc(int, unsigned int); long int random_linux_libc(int); #endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/msdos.c0000644000175000017500000006212011162175035020310 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * msdos.c * ***********************************************************/ #include "system.h" #if defined(PLATFORM_MSDOS) #include "sound.h" #include "joystick.h" #include "misc.h" #include "setup.h" #include "pcx.h" #define AllegroDefaultScreen() (display->screens[display->default_screen]) /* allegro driver declarations */ DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1) DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8) DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB) DECLARE_MIDI_DRIVER_LIST() DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD) /* allegro global variables */ extern volatile int key_shifts; extern int num_joysticks; extern JOYSTICK_INFO joy[]; extern int i_love_bill; /* internal variables of msdos.c */ static boolean keyboard_auto_repeat = TRUE; static int key_press_state[MAX_SCANCODES]; static XEvent event_buffer[MAX_EVENT_BUFFER]; static int pending_events; static boolean joystick_event; static boolean mouse_installed = FALSE; static int last_mouse_pos; static int last_mouse_b; static int last_joystick_state; static BITMAP* video_bitmap; static RGB global_colormap[MAX_COLORS]; static int global_colormap_entries_used = 0; boolean wait_for_vsync; static BITMAP *Read_PCX_to_AllegroBitmap(char *); static void allegro_init_drivers() { int i; for (i = 0; i < MAX_EVENT_BUFFER; i++) event_buffer[i].type = 0; for (i = 0; i < MAX_SCANCODES; i++) key_press_state[i] = KeyReleaseMask; last_mouse_pos = mouse_pos; last_mouse_b = 0; pending_events = 0; clear_keybuf(); /* enable Windows friendly timer mode (already default under Windows) */ i_love_bill = TRUE; install_keyboard(); install_timer(); if (install_mouse() > 0) mouse_installed = TRUE; last_joystick_state = 0; joystick_event = FALSE; } static boolean allegro_init_audio() { reserve_voices(NUM_MIXER_CHANNELS, 0); if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) == -1) if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1) return FALSE; return TRUE; } static boolean hide_mouse(Display *display, int x, int y, unsigned int width, unsigned int height) { if (mouse_x + display->mouse_ptr->w < x || mouse_x > x + width) return FALSE; if (mouse_y + display->mouse_ptr->h < y || mouse_y > y + height) return FALSE; show_mouse(NULL); return TRUE; } static void unhide_mouse(Display *display) { if (mouse_installed) show_mouse(video_bitmap); } static KeySym ScancodeToKeySym(byte scancode) { switch(scancode) { case KEY_ESC: return XK_Escape; case KEY_1: return XK_1; case KEY_2: return XK_2; case KEY_3: return XK_3; case KEY_4: return XK_4; case KEY_5: return XK_5; case KEY_6: return XK_6; case KEY_7: return XK_7; case KEY_8: return XK_8; case KEY_9: return XK_9; case KEY_0: return XK_0; case KEY_MINUS: return XK_minus; case KEY_EQUALS: return XK_equal; case KEY_BACKSPACE: return XK_BackSpace; case KEY_TAB: return XK_Tab; case KEY_Q: return XK_q; case KEY_W: return XK_w; case KEY_E: return XK_e; case KEY_R: return XK_r; case KEY_T: return XK_t; case KEY_Y: return XK_y; case KEY_U: return XK_u; case KEY_I: return XK_i; case KEY_O: return XK_o; case KEY_P: return XK_p; case KEY_OPENBRACE: return XK_braceleft; case KEY_CLOSEBRACE: return XK_braceright; case KEY_ENTER: return XK_Return; case KEY_LCONTROL: return XK_Control_L; case KEY_A: return XK_a; case KEY_S: return XK_s; case KEY_D: return XK_d; case KEY_F: return XK_f; case KEY_G: return XK_g; case KEY_H: return XK_h; case KEY_J: return XK_j; case KEY_K: return XK_k; case KEY_L: return XK_l; case KEY_COLON: return XK_colon; case KEY_QUOTE: return XK_apostrophe; case KEY_TILDE: return XK_asciitilde; case KEY_LSHIFT: return XK_Shift_L; case KEY_BACKSLASH: return XK_backslash; case KEY_Z: return XK_z; case KEY_X: return XK_x; case KEY_C: return XK_c; case KEY_V: return XK_v; case KEY_B: return XK_b; case KEY_N: return XK_n; case KEY_M: return XK_m; case KEY_COMMA: return XK_comma; case KEY_STOP: return XK_period; case KEY_SLASH: return XK_slash; case KEY_RSHIFT: return XK_Shift_R; case KEY_ASTERISK: return XK_KP_Multiply; case KEY_ALT: return XK_Alt_L; case KEY_SPACE: return XK_space; case KEY_CAPSLOCK: return XK_Caps_Lock; case KEY_F1: return XK_F1; case KEY_F2: return XK_F2; case KEY_F3: return XK_F3; case KEY_F4: return XK_F4; case KEY_F5: return XK_F5; case KEY_F6: return XK_F6; case KEY_F7: return XK_F7; case KEY_F8: return XK_F8; case KEY_F9: return XK_F9; case KEY_F10: return XK_F10; case KEY_NUMLOCK: return XK_Num_Lock; case KEY_SCRLOCK: return XK_Scroll_Lock; case KEY_HOME: return XK_Home; case KEY_UP: return XK_Up; case KEY_PGUP: return XK_Page_Up; case KEY_MINUS_PAD: return XK_KP_Subtract; case KEY_LEFT: return XK_Left; case KEY_5_PAD: return XK_KP_5; case KEY_RIGHT: return XK_Right; case KEY_PLUS_PAD: return XK_KP_Add; case KEY_END: return XK_End; case KEY_DOWN: return XK_Down; case KEY_PGDN: return XK_Page_Down; case KEY_INSERT: return XK_Insert; case KEY_DEL: return XK_Delete; case KEY_PRTSCR: return XK_Print; case KEY_F11: return XK_F11; case KEY_F12: return XK_F12; case KEY_LWIN: return XK_Meta_L; case KEY_RWIN: return XK_Meta_R; case KEY_MENU: return XK_Menu; case KEY_PAD: return XK_VoidSymbol; case KEY_RCONTROL: return XK_Control_R; case KEY_ALTGR: return XK_Alt_R; case KEY_SLASH2: return XK_KP_Divide; case KEY_PAUSE: return XK_Pause; case NEW_KEY_BACKSLASH: return XK_backslash; case NEW_KEY_1_PAD: return XK_KP_1; case NEW_KEY_2_PAD: return XK_KP_2; case NEW_KEY_3_PAD: return XK_KP_3; case NEW_KEY_4_PAD: return XK_KP_4; case NEW_KEY_5_PAD: return XK_KP_5; case NEW_KEY_6_PAD: return XK_KP_6; case NEW_KEY_7_PAD: return XK_KP_7; case NEW_KEY_8_PAD: return XK_KP_8; case NEW_KEY_9_PAD: return XK_KP_9; case NEW_KEY_0_PAD: return XK_KP_0; case NEW_KEY_STOP_PAD: return XK_KP_Separator; case NEW_KEY_EQUALS_PAD: return XK_KP_Equal; case NEW_KEY_SLASH_PAD: return XK_KP_Divide; case NEW_KEY_ASTERISK_PAD: return XK_KP_Multiply; case NEW_KEY_ENTER_PAD: return XK_KP_Enter; default: return XK_VoidSymbol; } } Pixel AllegroAllocColorCell(int r, int g, int b) { byte pixel_mapping = 0; int i; r >>= 10; g >>= 10; b >>= 10; /* try to use existing colors from the global colormap */ for (i = 0; i < global_colormap_entries_used; i++) { if (r == global_colormap[i].r && g == global_colormap[i].g && b == global_colormap[i].b) /* color found */ { pixel_mapping = i; break; } } if (i == global_colormap_entries_used) /* color not found */ { if (global_colormap_entries_used < MAX_COLORS) global_colormap_entries_used++; i = global_colormap_entries_used - 1; global_colormap[i].r = r; global_colormap[i].g = g; global_colormap[i].b = b; set_palette(global_colormap); pixel_mapping = i; } return pixel_mapping; } void XMapWindow(Display *display, Window window) { int x, y; unsigned int width, height; boolean mouse_off; x = AllegroDefaultScreen().x; y = AllegroDefaultScreen().y; width = AllegroDefaultScreen().width; height = AllegroDefaultScreen().height; mouse_off = hide_mouse(display, x, y, width, height); blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height); if (mouse_off) unhide_mouse(display); } Display *XOpenDisplay(char *display_name) { Screen *screen; Display *display; BITMAP *mouse_bitmap = NULL; char *mouse_filename = getCustomImageFilename(program.msdos_cursor_filename); if ((mouse_bitmap = Read_PCX_to_AllegroBitmap(mouse_filename)) == NULL) return NULL; screen = malloc(sizeof(Screen)); display = malloc(sizeof(Display)); screen[0].cmap = 0; screen[0].root = 0; screen[0].white_pixel = AllegroAllocColorCell(0xFFFF, 0xFFFF, 0xFFFF); screen[0].black_pixel = AllegroAllocColorCell(0x0000, 0x0000, 0x0000); screen[0].video_bitmap = NULL; display->default_screen = 0; display->screens = screen; display->mouse_ptr = mouse_bitmap; allegro_init(); allegro_init_drivers(); set_color_depth(8); /* force Windows 95 to switch to fullscreen mode */ set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0); rest(200); set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0); return display; } Window XCreateSimpleWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, unsigned long border, unsigned long background) { video_bitmap = create_video_bitmap(XRES, YRES); clear_to_color(video_bitmap, background); AllegroDefaultScreen().video_bitmap = video_bitmap; AllegroDefaultScreen().x = x; AllegroDefaultScreen().y = y; AllegroDefaultScreen().width = XRES; AllegroDefaultScreen().height = YRES; set_mouse_sprite(display->mouse_ptr); #if 0 set_mouse_sprite_focus(1, 1); #endif set_mouse_speed(1, 1); set_mouse_range(AllegroDefaultScreen().x + 1, AllegroDefaultScreen().y + 1, AllegroDefaultScreen().x + video.width + 1, AllegroDefaultScreen().y + video.height + 1); show_video_bitmap(video_bitmap); return (Window)video_bitmap; } Status XStringListToTextProperty(char **list, int count, XTextProperty *text_prop_return) { char *string; if (count >= 1) { string = malloc(strlen(list[0] + 1)); strcpy(string, list[0]); text_prop_return->value = (unsigned char *)string; return 1; } else text_prop_return = NULL; return 0; } void XFree(void *data) { checked_free(data); } GC XCreateGC(Display *display, Drawable d, unsigned long value_mask, XGCValues *values) { XGCValues *gcv; gcv = malloc(sizeof(XGCValues)); gcv->foreground = values->foreground; gcv->background = values->background; gcv->graphics_exposures = values->graphics_exposures; gcv->clip_mask = values->clip_mask; gcv->clip_x_origin = values->clip_x_origin; gcv->clip_y_origin = values->clip_y_origin; gcv->value_mask = value_mask; return (GC)gcv; } void XSetClipMask(Display *display, GC gc, Pixmap pixmap) { XGCValues *gcv = (XGCValues *)gc; gcv->clip_mask = pixmap; gcv->value_mask |= GCClipMask; } void XSetClipOrigin(Display *display, GC gc, int x, int y) { XGCValues *gcv = (XGCValues *)gc; gcv->clip_x_origin = x; gcv->clip_x_origin = y; } void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height) { boolean mouse_off = FALSE; if ((BITMAP *)d == video_bitmap) { x += AllegroDefaultScreen().x; y += AllegroDefaultScreen().y; freeze_mouse_flag = TRUE; mouse_off = hide_mouse(display, x, y, width, height); } rectfill((BITMAP *)d, x, y, x + width - 1, y + height - 1, ((XGCValues *)gc)->foreground); if (mouse_off) unhide_mouse(display); freeze_mouse_flag = FALSE; } Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width, unsigned int height, unsigned int depth) { BITMAP *bitmap = NULL; if (gfx_capabilities & GFX_HW_VRAM_BLIT && width == gfx.scrollbuffer_width && height == gfx.scrollbuffer_height) bitmap = create_video_bitmap(width, height); if (bitmap == NULL) bitmap = create_bitmap(width, height); return (Pixmap)bitmap; } void XSync(Display *display, Bool discard_events) { wait_for_vsync = TRUE; } inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y) { boolean mouse_off = FALSE; if ((BITMAP *)src == video_bitmap) { src_x += AllegroDefaultScreen().x; src_y += AllegroDefaultScreen().y; } if ((BITMAP *)dest == video_bitmap) { dest_x += AllegroDefaultScreen().x; dest_y += AllegroDefaultScreen().y; freeze_mouse_flag = TRUE; mouse_off = hide_mouse(display, dest_x, dest_y, width, height); } if (wait_for_vsync) { wait_for_vsync = FALSE; vsync(); } if (((XGCValues *)gc)->value_mask & GCClipMask) masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y, width, height); else blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y, width, height); if (mouse_off) unhide_mouse(display); freeze_mouse_flag = FALSE; } static BITMAP *Image_to_AllegroBitmap(Image *image) { BITMAP *bitmap; byte *src_ptr = image->data; byte pixel_mapping[MAX_COLORS]; unsigned int depth = 8; int i, x, y; if (image->type == IMAGETYPE_TRUECOLOR && depth == 8) Error(ERR_EXIT, "cannot handle true-color images on 8-bit display"); /* allocate new allegro bitmap structure */ if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL) { errno_pcx = PCX_NoMemory; return NULL; } clear(bitmap); /* try to use existing colors from the global colormap */ for (i = 0; i < MAX_COLORS; i++) { if (!image->rgb.color_used[i]) continue; pixel_mapping[i] = AllegroAllocColorCell(image->rgb.red[i], image->rgb.green[i], image->rgb.blue[i]); } /* copy bitmap data */ for (y = 0; y < image->height; y++) for (x = 0; x < image->width; x++) putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]); return bitmap; } static BITMAP *Read_PCX_to_AllegroBitmap(char *filename) { BITMAP *bitmap; Image *image; /* read the graphic file in PCX format to internal image structure */ if ((image = Read_PCX_to_Image(filename)) == NULL) return NULL; /* convert internal image structure to allegro bitmap structure */ if ((bitmap = Image_to_AllegroBitmap(image)) == NULL) return NULL; set_palette(global_colormap); return bitmap; } int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, Pixmap *pixmap, Pixmap *pixmap_mask) { BITMAP *bitmap; if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL) return errno_pcx; *pixmap = (Pixmap)bitmap; /* pixmap_mask will never be used in Allegro (which uses masked_blit()), so use non-NULL dummy pointer to empty Pixmap */ *pixmap_mask = (Pixmap)DUMMY_MASK; return PCX_Success; } int XReadBitmapFile(Display *display, Drawable d, char *filename, unsigned int *width_return, unsigned int *height_return, Pixmap *bitmap_return, int *x_hot_return, int *y_hot_return) { BITMAP *bitmap; if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL) return BitmapOpenFailed; *width_return = bitmap->w; *height_return = bitmap->h; *x_hot_return = -1; *y_hot_return = -1; *bitmap_return = (Pixmap)bitmap; return BitmapSuccess; } void XFreePixmap(Display *display, Pixmap pixmap) { if (pixmap != DUMMY_MASK && (is_memory_bitmap((BITMAP *)pixmap) || is_screen_bitmap((BITMAP *)pixmap))) destroy_bitmap((BITMAP *)pixmap); } void XFreeGC(Display *display, GC gc) { XGCValues *gcv = (XGCValues *)gc; checked_free(gcv); } void XUnmapWindow(Display *display, Window window) { } void XCloseDisplay(Display *display) { BITMAP *bitmap = video_bitmap; if (is_screen_bitmap(bitmap)) destroy_bitmap(bitmap); checked_free(display->screens); checked_free(display); /* return to text mode (or DOS box on Windows screen) */ set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); } void XNextEvent(Display *display, XEvent *event_return) { while (!pending_events) XPending(display); memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent)); pending_events--; } static void NewKeyEvent(int key_press_state, KeySym keysym) { XKeyEvent *xkey; if (pending_events >= MAX_EVENT_BUFFER) return; pending_events++; xkey = (XKeyEvent *)&event_buffer[pending_events]; xkey->type = key_press_state; xkey->state = (unsigned int)keysym; } #define HANDLE_RAW_KB_ALL_KEYS 0 #define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY 1 static int modifier_scancode[] = { KEY_LSHIFT, KEY_RSHIFT, KEY_LCONTROL, KEY_RCONTROL, KEY_ALT, KEY_ALTGR, KEY_LWIN, KEY_RWIN, KEY_CAPSLOCK, KEY_NUMLOCK, KEY_SCRLOCK, -1 }; static void HandleKeyboardRaw(int mode) { int i; for (i = 0; i < MAX_SCANCODES; i++) { int scancode, new_state, event_type; char key_pressed; if (mode == HANDLE_RAW_KB_MODIFIER_KEYS_ONLY) { if ((scancode = modifier_scancode[i]) == -1) return; } else scancode = i; key_pressed = key[scancode]; new_state = (key_pressed ? KeyPressMask : KeyReleaseMask); event_type = (key_pressed ? KeyPress : KeyRelease); if (key_press_state[i] == new_state) /* state not changed */ continue; key_press_state[i] = new_state; NewKeyEvent(event_type, ScancodeToKeySym(scancode)); } } static void HandleKeyboardEvent() { if (keypressed()) { int key_info = readkey(); int scancode = (key_info >> 8); int ascii = (key_info & 0xff); KeySym keysym = ScancodeToKeySym(scancode); if (scancode == KEY_PAD) { /* keys on the numeric keypad return just scancode 'KEY_PAD' for some reason, so we must handle them separately */ if (ascii >= '0' && ascii <= '9') keysym = XK_KP_0 + (KeySym)(ascii - '0'); else if (ascii == '.') keysym = XK_KP_Separator; } else if (ascii >= ' ' && ascii <= 'Z') keysym = XK_space + (KeySym)(ascii - ' '); else if (ascii == '^') keysym = XK_asciicircum; else if (ascii == '_') keysym = XK_underscore; else if (ascii == 'Ä') keysym = XK_Adiaeresis; else if (ascii == 'Ö') keysym = XK_Odiaeresis; else if (ascii == 'Ü') keysym = XK_Udiaeresis; else if (ascii == 'ä') keysym = XK_adiaeresis; else if (ascii == 'ö') keysym = XK_odiaeresis; else if (ascii == 'ü') keysym = XK_udiaeresis; else if (ascii == 'ß') keysym = XK_ssharp; NewKeyEvent(KeyPress, keysym); } else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG)) { /* the allegro function keypressed() does not give us single pressed modifier keys, so we must detect them with the internal global allegro variable 'key_shifts' and then handle them separately */ HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY); } } int XPending(Display *display) { XButtonEvent *xbutton; XMotionEvent *xmotion; int i; /* When using 'HandleKeyboardRaw()', keyboard input is also stored in the allegro keyboard input buffer and would be available a second time by calling 'HandleKeyboardEvent()'. To avoid double keyboard events, the allegro function 'clear_keybuf()' must be called each time when switching from calling 'HandleKeyboardRaw()' to calling 'HandleKeyboardEvent()' to get keyboard input, which is actually done by 'XAutoRepeatOn()' which sets keyboard_auto_repeat to TRUE. */ /* keyboard event */ if (keyboard_auto_repeat) HandleKeyboardEvent(); else HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS); /* mouse motion event */ if (mouse_pos != last_mouse_pos) { last_mouse_pos = mouse_pos; pending_events++; xmotion = (XMotionEvent *)&event_buffer[pending_events]; xmotion->type = MotionNotify; xmotion->x = mouse_x - AllegroDefaultScreen().x; xmotion->y = mouse_y - AllegroDefaultScreen().y; } /* mouse button event */ if (mouse_b != last_mouse_b) { for (i = 0; i < 3; i++) /* check all three mouse buttons */ { int bitmask = (1 << i); if ((last_mouse_b & bitmask) != (mouse_b & bitmask)) { int mapping[3] = { 1, 3, 2 }; pending_events++; xbutton = (XButtonEvent *)&event_buffer[pending_events]; xbutton->type = (mouse_b & bitmask ? ButtonPress : ButtonRelease); xbutton->button = mapping[i]; xbutton->x = mouse_x - AllegroDefaultScreen().x; xbutton->y = mouse_y - AllegroDefaultScreen().y; } } last_mouse_b = mouse_b; } return pending_events; } KeySym XLookupKeysym(XKeyEvent *key_event, int index) { return key_event->state; } int XLookupString(XKeyEvent *key_event, char *buffer, int buffer_size, KeySym *key, XComposeStatus *compose) { *key = key_event->state; return 0; } void XSetForeground(Display *display, GC gc, unsigned long pixel) { XGCValues *gcv = (XGCValues *)gc; gcv->foreground = pixel; } void XDrawLine(Display *display, Drawable d, GC gc, int x1, int y1, int x2, int y2) { XGCValues *gcv = (XGCValues *)gc; boolean mouse_off = FALSE; if ((BITMAP *)d == video_bitmap) { x1 += AllegroDefaultScreen().x; y1 += AllegroDefaultScreen().y; x2 += AllegroDefaultScreen().x; y2 += AllegroDefaultScreen().y; freeze_mouse_flag = TRUE; mouse_off = hide_mouse(display, MIN(x1, x2), MIN(y1, y2), MAX(x1, x2) - MIN(x1, x2), MAX(y1, y2) - MIN(y1, y2)); } line((BITMAP *)d, x1, y1, x2, y2, gcv->foreground); if (mouse_off) unhide_mouse(display); freeze_mouse_flag = FALSE; } void XDestroyImage(XImage *ximage) { } void XDestroyWindow(Display *display, Window window) { } Bool XQueryPointer(Display *display, Window window, Window *root, Window *child, int *root_x, int *root_y, int *win_x, int *win_y, unsigned int *mask) { *win_x = mouse_x - AllegroDefaultScreen().x; *win_y = mouse_y - AllegroDefaultScreen().y; return True; } void XAutoRepeatOn(Display *display) { keyboard_auto_repeat = TRUE; clear_keybuf(); } void XAutoRepeatOff(Display *display) { keyboard_auto_repeat = FALSE; } void AllegroDrawLine(Drawable d, int from_x, int from_y, int to_x, int to_y, Pixel color) { boolean mouse_off = FALSE; if ((BITMAP *)d == video_bitmap) { int dx = AllegroDefaultScreen().x; int dy = AllegroDefaultScreen().y; int x1, y1, x2, y2; from_x += dx; from_y += dy; to_x += dx; to_y += dy; x1 = (from_x < to_x ? from_x : to_x); y1 = (from_y < to_y ? from_y : to_y); x2 = (from_x < to_x ? to_x : from_x); y2 = (from_y < to_y ? to_y : from_y); freeze_mouse_flag = TRUE; mouse_off = hide_mouse(display, x1, y1, x2 - x1 + 1, y2 - y1 + 1); } line((BITMAP *)d, from_x, from_y, to_x, to_y, color); if (mouse_off) unhide_mouse(display); freeze_mouse_flag = FALSE; } Pixel AllegroGetPixel(Drawable d, int x, int y) { return getpixel((BITMAP *)d, x, y); } void AllegroZoomBitmap(Drawable src, Drawable dst, int src_width, int src_height, int dst_width, int dst_height) { stretch_blit((BITMAP *)src, (BITMAP *)dst, 0, 0, src_width, src_height, 0, 0, dst_width, dst_height); } void MSDOSOpenAudio(void) { if (allegro_init_audio()) { audio.sound_available = TRUE; audio.music_available = TRUE; audio.loops_available = TRUE; audio.sound_enabled = TRUE; audio.num_channels = NUM_MIXER_CHANNELS; audio.music_channel = MUSIC_CHANNEL; audio.first_sound_channel = FIRST_SOUND_CHANNEL; Mixer_InitChannels(); } } void MSDOSCloseAudio(void) { /* nothing to be done here */ } void NetworkServer(int port, int serveronly) { Error(ERR_WARN, "networking not supported in DOS version"); } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ void MSDOSInitJoysticks() { int i; /* start from scratch */ remove_joystick(); /* try to access two joysticks; if that fails, try to access just one */ if (install_joystick(JOY_TYPE_2PADS) == 0 || install_joystick(JOY_TYPE_AUTODETECT) == 0) joystick.status = JOYSTICK_ACTIVATED; for (i = 0; i < MAX_PLAYERS; i++) { char *device_name = setup.input[i].joy.device_name; int joystick_nr = getJoystickNrFromDeviceName(device_name); if (joystick_nr >= num_joysticks) joystick_nr = -1; /* misuse joystick file descriptor variable to store joystick number */ joystick.fd[i] = joystick_nr; } } boolean MSDOSReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { /* the allegro global variable 'num_joysticks' contains the number of joysticks found at initialization under MS-DOS / Windows */ if (nr < 0 || nr >= num_joysticks) return FALSE; poll_joystick(); if (x != NULL) *x = joy[nr].stick[0].axis[0].pos; if (y != NULL) *y = joy[nr].stick[0].axis[1].pos; if (b1 != NULL) *b1 = joy[nr].button[0].b; if (b2 != NULL) *b2 = joy[nr].button[1].b; return TRUE; } #endif /* PLATFORM_MSDOS */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/platform.h0000644000175000017500000001141210574042345021015 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * platform.h * ***********************************************************/ #ifndef PLATFORM_H #define PLATFORM_H /* ========================================================================= */ /* define main platform keywords */ /* ========================================================================= */ #if defined(MSDOS) #define PLATFORM_MSDOS #define PLATFORM_STRING "DOS" #elif defined(WIN32) || defined(_WIN32) #define PLATFORM_WIN32 #define PLATFORM_STRING "Windows" #else #define PLATFORM_UNIX #define PLATFORM_STRING "Unix" #endif /* ========================================================================= */ /* define additional platform keywords */ /* ========================================================================= */ #if defined(_AIX) #define PLATFORM_AIX #undef PLATFORM_STRING #define PLATFORM_STRING "AIX" #endif #if defined(AMIGA) || defined(__AMIGA) || defined(__amigados__) #define PLATFORM_AMIGA #undef PLATFORM_STRING #define PLATFORM_STRING "AmigaOS" #endif #if defined(__BEOS__) #define PLATFORM_BEOS #undef PLATFORM_STRING #define PLATFORM_STRING "BeOS" #endif #if defined(bsdi) || defined(__bsdi) || defined(__bsdi__) #define PLATFORM_BSDI #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "BSDI" #endif #if defined(_arch_dreamcast) #define PLATFORM_DREAMCAST #undef PLATFORM_STRING #define PLATFORM_STRING "Dreamcast" #endif #if defined(__FreeBSD__) || defined(__DragonFly__) #define PLATFORM_FREEBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "FreeBSD" #endif #if defined(hpux) || defined(__hpux) || defined(__hpux__) #define PLATFORM_HPUX #undef PLATFORM_STRING #define PLATFORM_STRING "HP-UX" #endif #if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE) #define PLATFORM_IRIX #undef PLATFORM_STRING #define PLATFORM_STRING "IRIX" #endif #if defined(linux) || defined(__linux) || defined(__linux__) #define PLATFORM_LINUX #undef PLATFORM_STRING #define PLATFORM_STRING "Linux" #endif #if defined(__APPLE__) && defined(__MACH__) #define PLATFORM_MACOSX #undef PLATFORM_STRING #define PLATFORM_STRING "Mac OS X" #endif #if defined(__NetBSD__) #define PLATFORM_NETBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "NetBSD" #endif #if defined(NeXT) #define PLATFORM_NEXT #undef PLATFORM_STRING #define PLATFORM_STRING "NeXT" #endif #if defined(__OpenBSD__) #define PLATFORM_OPENBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "OpenBSD" #endif #if defined(__OS2__) #define PLATFORM_OS2 #undef PLATFORM_STRING #define PLATFORM_STRING "OS/2" #endif #if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE) #define PLATFORM_OSF #undef PLATFORM_STRING #define PLATFORM_STRING "OSF/1" #endif #if defined(__QNXNTO__) #define PLATFORM_QNX #undef PLATFORM_STRING #define PLATFORM_STRING "QNX" #endif #if defined(riscos) || defined(__riscos) || defined(__riscos__) #define PLATFORM_RISCOS #undef PLATFORM_STRING #define PLATFORM_STRING "RISC OS" #endif #if defined(sparc) || defined(sun) || defined(__SVR4) #define PLATFORM_SOLARIS #undef PLATFORM_STRING #define PLATFORM_STRING "Solaris" #endif #if defined(_WIN32_WCE) #define PLATFORM_WINDOWS_CE #undef PLATFORM_STRING #define PLATFORM_STRING "Windows CE" #endif /* ========================================================================= */ /* define additional target keywords */ /* ========================================================================= */ #if defined(PLATFORM_MSDOS) #ifndef TARGET_ALLEGRO #define TARGET_ALLEGRO #endif #ifndef TARGET_X11 #define TARGET_X11 #endif #endif #if defined(PLATFORM_UNIX) && defined(TARGET_X11) #define TARGET_X11_NATIVE #endif /* ========================================================================= */ /* this should better go into "system.h" or "features.h" (yet to be created) */ /* ========================================================================= */ #if defined(PLATFORM_UNIX) || defined(TARGET_SDL) #define NETWORK_AVALIABLE #endif #endif /* PLATFORM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/types.h0000644000175000017500000000327611362413305020340 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * types.h * ***********************************************************/ #ifndef TYPES_H #define TYPES_H #include #include #include #include #include typedef int boolean; #if !defined(PLATFORM_WIN32) typedef unsigned char byte; #endif #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif #ifdef AUTO #undef AUTO #endif #define TRUE 1 #define FALSE 0 #define AUTO -1 #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef ABS #define ABS(a) ((a) < 0 ? -(a) : (a)) #endif #ifndef SIGN #define SIGN(a) ((a) < 0 ? -1 : ((a) > 0 ? 1 : 0)) #endif #ifndef ODD #define ODD(a) (((a) & 1) == 1) #endif #ifndef EVEN #define EVEN(a) (((a) & 1) == 0) #endif #define SIZEOF_ARRAY(array, type) (sizeof(array) / sizeof(type)) #define SIZEOF_ARRAY_INT(array) SIZEOF_ARRAY(array, int) struct ListNode { char *key; void *content; struct ListNode *next; }; typedef struct ListNode ListNode; #endif /* TYPES_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/snapshot.h0000644000175000017500000000222011337610201021013 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * snapshot.h * ***********************************************************/ #ifndef SNAPSHOT_H #define SNAPSHOT_H #include "system.h" #include "misc.h" /* needed for comfortably saving engine snapshot buffers */ #define ARGS_ADDRESS_AND_SIZEOF(x) (&(x)), (sizeof(x)) struct EngineSnapshotNodeInfo { void *buffer_orig; void *buffer_copy; int size; }; void SaveEngineSnapshotBuffer(void *buffer, int size); void LoadEngineSnapshotBuffers(); void FreeEngineSnapshotBuffers(); #endif /* SNAPSHOT_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/setup.c0000644000175000017500000033171611353466460020344 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * setup.c * ***********************************************************/ #include #include #include #include #include #include "platform.h" #if !defined(PLATFORM_WIN32) #include #include #endif #include "setup.h" #include "joystick.h" #include "text.h" #include "misc.h" #include "hash.h" #define NUM_LEVELCLASS_DESC 8 static char *levelclass_desc[NUM_LEVELCLASS_DESC] = { "Tutorial Levels", "Classic Originals", "Contributions", "Private Levels", "Boulderdash", "Emerald Mine", "Supaplex", "DX Boulderdash" }; #define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ IS_LEVELCLASS_BD(n) ? FC_YELLOW : \ IS_LEVELCLASS_EM(n) ? FC_YELLOW : \ IS_LEVELCLASS_SP(n) ? FC_YELLOW : \ IS_LEVELCLASS_DX(n) ? FC_YELLOW : \ IS_LEVELCLASS_SB(n) ? FC_YELLOW : \ IS_LEVELCLASS_CONTRIB(n) ? FC_GREEN : \ IS_LEVELCLASS_PRIVATE(n) ? FC_RED : \ FC_BLUE) #define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ IS_LEVELCLASS_CLASSICS(n) ? 1 : \ IS_LEVELCLASS_BD(n) ? 2 : \ IS_LEVELCLASS_EM(n) ? 3 : \ IS_LEVELCLASS_SP(n) ? 4 : \ IS_LEVELCLASS_DX(n) ? 5 : \ IS_LEVELCLASS_SB(n) ? 6 : \ IS_LEVELCLASS_CONTRIB(n) ? 7 : \ IS_LEVELCLASS_PRIVATE(n) ? 8 : \ 9) #define ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \ IS_ARTWORKCLASS_CONTRIB(n) ? FC_GREEN : \ IS_ARTWORKCLASS_PRIVATE(n) ? FC_RED : \ IS_ARTWORKCLASS_LEVEL(n) ? FC_YELLOW : \ FC_BLUE) #define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ? 0 : \ IS_ARTWORKCLASS_LEVEL(n) ? 1 : \ IS_ARTWORKCLASS_CONTRIB(n) ? 2 : \ IS_ARTWORKCLASS_PRIVATE(n) ? 3 : \ 9) #define TOKEN_VALUE_POSITION_SHORT 32 #define TOKEN_VALUE_POSITION_DEFAULT 40 #define TOKEN_COMMENT_POSITION_DEFAULT 60 #define MAX_COOKIE_LEN 256 static void setTreeInfoToDefaults(TreeInfo *, int); static TreeInfo *getTreeInfoCopy(TreeInfo *ti); static int compareTreeInfoEntries(const void *, const void *); static int token_value_position = TOKEN_VALUE_POSITION_DEFAULT; static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT; static SetupFileHash *artworkinfo_cache_old = NULL; static SetupFileHash *artworkinfo_cache_new = NULL; static boolean use_artworkinfo_cache = TRUE; /* ------------------------------------------------------------------------- */ /* file functions */ /* ------------------------------------------------------------------------- */ static char *getLevelClassDescription(TreeInfo *ti) { int position = ti->sort_priority / 100; if (position >= 0 && position < NUM_LEVELCLASS_DESC) return levelclass_desc[position]; else return "Unknown Level Class"; } static char *getUserLevelDir(char *level_subdir) { static char *userlevel_dir = NULL; char *data_dir = getUserGameDataDir(); char *userlevel_subdir = LEVELS_DIRECTORY; checked_free(userlevel_dir); if (level_subdir != NULL) userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); else userlevel_dir = getPath2(data_dir, userlevel_subdir); return userlevel_dir; } static char *getScoreDir(char *level_subdir) { static char *score_dir = NULL; char *data_dir = getCommonDataDir(); char *score_subdir = SCORES_DIRECTORY; checked_free(score_dir); if (level_subdir != NULL) score_dir = getPath3(data_dir, score_subdir, level_subdir); else score_dir = getPath2(data_dir, score_subdir); return score_dir; } static char *getLevelSetupDir(char *level_subdir) { static char *levelsetup_dir = NULL; char *data_dir = getUserGameDataDir(); char *levelsetup_subdir = LEVELSETUP_DIRECTORY; checked_free(levelsetup_dir); if (level_subdir != NULL) levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir); else levelsetup_dir = getPath2(data_dir, levelsetup_subdir); return levelsetup_dir; } static char *getCacheDir() { static char *cache_dir = NULL; if (cache_dir == NULL) cache_dir = getPath2(getUserGameDataDir(), CACHE_DIRECTORY); return cache_dir; } static char *getLevelDirFromTreeInfo(TreeInfo *node) { static char *level_dir = NULL; if (node == NULL) return options.level_directory; checked_free(level_dir); level_dir = getPath2((node->in_user_dir ? getUserLevelDir(NULL) : options.level_directory), node->fullpath); return level_dir; } char *getCurrentLevelDir() { return getLevelDirFromTreeInfo(leveldir_current); } static char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; char *data_dir = getUserGameDataDir(); char *tape_subdir = TAPES_DIRECTORY; checked_free(tape_dir); if (level_subdir != NULL) tape_dir = getPath3(data_dir, tape_subdir, level_subdir); else tape_dir = getPath2(data_dir, tape_subdir); return tape_dir; } static char *getSolutionTapeDir() { static char *tape_dir = NULL; char *data_dir = getCurrentLevelDir(); char *tape_subdir = TAPES_DIRECTORY; checked_free(tape_dir); tape_dir = getPath2(data_dir, tape_subdir); return tape_dir; } static char *getDefaultGraphicsDir(char *graphics_subdir) { static char *graphics_dir = NULL; if (graphics_subdir == NULL) return options.graphics_directory; checked_free(graphics_dir); graphics_dir = getPath2(options.graphics_directory, graphics_subdir); return graphics_dir; } static char *getDefaultSoundsDir(char *sounds_subdir) { static char *sounds_dir = NULL; if (sounds_subdir == NULL) return options.sounds_directory; checked_free(sounds_dir); sounds_dir = getPath2(options.sounds_directory, sounds_subdir); return sounds_dir; } static char *getDefaultMusicDir(char *music_subdir) { static char *music_dir = NULL; if (music_subdir == NULL) return options.music_directory; checked_free(music_dir); music_dir = getPath2(options.music_directory, music_subdir); return music_dir; } static char *getClassicArtworkSet(int type) { return (type == TREE_TYPE_GRAPHICS_DIR ? GFX_CLASSIC_SUBDIR : type == TREE_TYPE_SOUNDS_DIR ? SND_CLASSIC_SUBDIR : type == TREE_TYPE_MUSIC_DIR ? MUS_CLASSIC_SUBDIR : ""); } static char *getClassicArtworkDir(int type) { return (type == TREE_TYPE_GRAPHICS_DIR ? getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR) : type == TREE_TYPE_SOUNDS_DIR ? getDefaultSoundsDir(SND_CLASSIC_SUBDIR) : type == TREE_TYPE_MUSIC_DIR ? getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : ""); } static char *getUserGraphicsDir() { static char *usergraphics_dir = NULL; if (usergraphics_dir == NULL) usergraphics_dir = getPath2(getUserGameDataDir(), GRAPHICS_DIRECTORY); return usergraphics_dir; } static char *getUserSoundsDir() { static char *usersounds_dir = NULL; if (usersounds_dir == NULL) usersounds_dir = getPath2(getUserGameDataDir(), SOUNDS_DIRECTORY); return usersounds_dir; } static char *getUserMusicDir() { static char *usermusic_dir = NULL; if (usermusic_dir == NULL) usermusic_dir = getPath2(getUserGameDataDir(), MUSIC_DIRECTORY); return usermusic_dir; } static char *getSetupArtworkDir(TreeInfo *ti) { static char *artwork_dir = NULL; checked_free(artwork_dir); artwork_dir = getPath2(ti->basepath, ti->fullpath); return artwork_dir; } char *setLevelArtworkDir(TreeInfo *ti) { char **artwork_path_ptr, **artwork_set_ptr; TreeInfo *level_artwork; if (ti == NULL || leveldir_current == NULL) return NULL; artwork_path_ptr = LEVELDIR_ARTWORK_PATH_PTR(leveldir_current, ti->type); artwork_set_ptr = LEVELDIR_ARTWORK_SET_PTR( leveldir_current, ti->type); checked_free(*artwork_path_ptr); if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr))) { *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork)); } else { /* No (or non-existing) artwork configured in "levelinfo.conf". This would normally result in using the artwork configured in the setup menu. But if an artwork subdirectory exists (which might contain custom artwork or an artwork configuration file), this level artwork must be treated as relative to the default "classic" artwork, not to the artwork that is currently configured in the setup menu. Update: For "special" versions of R'n'D (like "R'n'D jue"), do not use the "default" artwork (which would be "jue0" for "R'n'D jue"), but use the real "classic" artwork from the original R'n'D (like "gfx_classic"). */ char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type)); checked_free(*artwork_set_ptr); if (fileExists(dir)) { *artwork_path_ptr = getStringCopy(getClassicArtworkDir(ti->type)); *artwork_set_ptr = getStringCopy(getClassicArtworkSet(ti->type)); } else { *artwork_path_ptr = getStringCopy(UNDEFINED_FILENAME); *artwork_set_ptr = NULL; } free(dir); } return *artwork_set_ptr; } inline static char *getLevelArtworkSet(int type) { if (leveldir_current == NULL) return NULL; return LEVELDIR_ARTWORK_SET(leveldir_current, type); } inline static char *getLevelArtworkDir(int type) { if (leveldir_current == NULL) return UNDEFINED_FILENAME; return LEVELDIR_ARTWORK_PATH(leveldir_current, type); } char *getTapeFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getTapeDir(leveldir_current->subdir), basename); return filename; } char *getSolutionTapeFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getSolutionTapeDir(), basename); if (!fileExists(filename)) { static char *filename_sln = NULL; checked_free(filename_sln); sprintf(basename, "%03d.sln", nr); filename_sln = getPath2(getSolutionTapeDir(), basename); if (fileExists(filename_sln)) return filename_sln; } return filename; } char *getScoreFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); filename = getPath2(getScoreDir(leveldir_current->subdir), basename); return filename; } char *getSetupFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getSetupDir(), SETUP_FILENAME); return filename; } char *getEditorSetupFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), EDITORSETUP_FILENAME); if (fileExists(filename)) return filename; checked_free(filename); filename = getPath2(getSetupDir(), EDITORSETUP_FILENAME); return filename; } char *getHelpAnimFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME); return filename; } char *getHelpTextFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME); return filename; } char *getLevelSetInfoFilename() { static char *filename = NULL; char *basenames[] = { "README", "README.TXT", "README.txt", "Readme", "Readme.txt", "readme", "readme.txt", NULL }; int i; for (i = 0; basenames[i] != NULL; i++) { checked_free(filename); filename = getPath2(getCurrentLevelDir(), basenames[i]); if (fileExists(filename)) return filename; } return NULL; } char *getLevelSetTitleMessageBasename(int nr, boolean initial) { static char basename[32]; sprintf(basename, "%s_%d.txt", (initial ? "titlemessage_initial" : "titlemessage"), nr + 1); return basename; } char *getLevelSetTitleMessageFilename(int nr, boolean initial) { static char *filename = NULL; char *basename; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getLevelSetTitleMessageBasename(nr, initial); if (!gfx.override_level_graphics) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* 2nd try: look for message file in current level set directory */ filename = getPath2(getCurrentLevelDir(), basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL) { /* 3rd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 4th try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 5th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 6th try: look for default artwork in old default artwork directory */ filename = getPath2(options.graphics_directory, basename); if (fileExists(filename)) return filename; return NULL; /* cannot find specified artwork file anywhere */ } static char *getCorrectedArtworkBasename(char *basename) { char *basename_corrected = basename; #if defined(PLATFORM_MSDOS) if (program.filename_prefix != NULL) { int prefix_len = strlen(program.filename_prefix); if (strncmp(basename, program.filename_prefix, prefix_len) == 0) basename_corrected = &basename[prefix_len]; /* if corrected filename is still longer than standard MS-DOS filename size (8 characters + 1 dot + 3 characters file extension), shorten filename by writing file extension after 8th basename character */ if (strlen(basename_corrected) > 8 + 1 + 3) { static char *msdos_filename = NULL; checked_free(msdos_filename); msdos_filename = getStringCopy(basename_corrected); strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1); basename_corrected = msdos_filename; } } #endif return basename_corrected; } char *getCustomImageFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_graphics) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getPath2(options.graphics_directory, basename); if (fileExists(filename)) return filename; #if defined(CREATE_SPECIAL_EDITION) free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.graphics_directory, GFX_FALLBACK_FILENAME); if (fileExists(filename)) return filename; #endif return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomSoundFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_sounds) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_SOUNDS) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultSoundsDir(SND_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getPath2(options.sounds_directory, basename); if (fileExists(filename)) return filename; #if defined(CREATE_SPECIAL_EDITION) free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME); if (fileExists(filename)) return filename; #endif return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomMusicFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.mus_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultMusicDir(MUS_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getPath2(options.music_directory, basename); if (fileExists(filename)) return filename; #if defined(CREATE_SPECIAL_EDITION) free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME); if (fileExists(filename)) return filename; #endif return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomArtworkFilename(char *basename, int type) { if (type == ARTWORK_TYPE_GRAPHICS) return getCustomImageFilename(basename); else if (type == ARTWORK_TYPE_SOUNDS) return getCustomSoundFilename(basename); else if (type == ARTWORK_TYPE_MUSIC) return getCustomMusicFilename(basename); else return UNDEFINED_FILENAME; } char *getCustomArtworkConfigFilename(int type) { return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type); } char *getCustomArtworkLevelConfigFilename(int type) { static char *filename = NULL; checked_free(filename); filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type)); return filename; } char *getCustomMusicDirectory(void) { static char *directory = NULL; boolean skip_setup_artwork = FALSE; checked_free(directory); if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY); if (fileExists(directory)) return directory; free(directory); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL) { /* 2nd try: look for special artwork configured in level series config */ directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR)); if (fileExists(directory)) return directory; free(directory); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ directory = getStringCopy(getSetupArtworkDir(artwork.mus_current)); if (fileExists(directory)) return directory; free(directory); } /* 4th try: look for default artwork in new default artwork directory */ directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR)); if (fileExists(directory)) return directory; free(directory); /* 5th try: look for default artwork in old default artwork directory */ directory = getStringCopy(options.music_directory); if (fileExists(directory)) return directory; return NULL; /* cannot find specified artwork file anywhere */ } void InitTapeDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE); createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); } void InitScoreDirectory(char *level_subdir) { createDirectory(getCommonDataDir(), "common data", PERMS_PUBLIC); createDirectory(getScoreDir(NULL), "main score", PERMS_PUBLIC); createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); } static void SaveUserLevelInfo(); void InitUserLevelDirectory(char *level_subdir) { if (!fileExists(getUserLevelDir(level_subdir))) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE); createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); SaveUserLevelInfo(); } } void InitLevelSetupDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE); createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE); } void InitCacheDirectory() { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE); } /* ------------------------------------------------------------------------- */ /* some functions to handle lists of level and artwork directories */ /* ------------------------------------------------------------------------- */ TreeInfo *newTreeInfo() { return checked_calloc(sizeof(TreeInfo)); } TreeInfo *newTreeInfo_setDefaults(int type) { TreeInfo *ti = newTreeInfo(); setTreeInfoToDefaults(ti, type); return ti; } void pushTreeInfo(TreeInfo **node_first, TreeInfo *node_new) { node_new->next = *node_first; *node_first = node_new; } int numTreeInfo(TreeInfo *node) { int num = 0; while (node) { num++; node = node->next; } return num; } boolean validLevelSeries(TreeInfo *node) { return (node != NULL && !node->node_group && !node->parent_link); } TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node) { if (node == NULL) return NULL; if (node->node_group) /* enter level group (step down into tree) */ return getFirstValidTreeInfoEntry(node->node_group); else if (node->parent_link) /* skip start entry of level group */ { if (node->next) /* get first real level series entry */ return getFirstValidTreeInfoEntry(node->next); else /* leave empty level group and go on */ return getFirstValidTreeInfoEntry(node->node_parent->next); } else /* this seems to be a regular level series */ return node; } TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *node) { if (node == NULL) return NULL; if (node->node_parent == NULL) /* top level group */ return *node->node_top; else /* sub level group */ return node->node_parent->node_group; } int numTreeInfoInGroup(TreeInfo *node) { return numTreeInfo(getTreeInfoFirstGroupEntry(node)); } int posTreeInfo(TreeInfo *node) { TreeInfo *node_cmp = getTreeInfoFirstGroupEntry(node); int pos = 0; while (node_cmp) { if (node_cmp == node) return pos; pos++; node_cmp = node_cmp->next; } return 0; } TreeInfo *getTreeInfoFromPos(TreeInfo *node, int pos) { TreeInfo *node_default = node; int pos_cmp = 0; while (node) { if (pos_cmp == pos) return node; pos_cmp++; node = node->next; } return node_default; } TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier) { if (identifier == NULL) return NULL; while (node) { if (node->node_group) { TreeInfo *node_group; node_group = getTreeInfoFromIdentifier(node->node_group, identifier); if (node_group) return node_group; } else if (!node->parent_link) { if (strEqual(identifier, node->identifier)) return node; } node = node->next; } return NULL; } TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent, TreeInfo *node, boolean skip_sets_without_levels) { TreeInfo *node_new; if (node == NULL) return NULL; if (!node->parent_link && !node->level_group && skip_sets_without_levels && node->levels == 0) return cloneTreeNode(node_top, node_parent, node->next, skip_sets_without_levels); #if 1 node_new = getTreeInfoCopy(node); /* copy complete node */ #else node_new = newTreeInfo(); *node_new = *node; /* copy complete node */ #endif node_new->node_top = node_top; /* correct top node link */ node_new->node_parent = node_parent; /* correct parent node link */ if (node->level_group) node_new->node_group = cloneTreeNode(node_top, node_new, node->node_group, skip_sets_without_levels); node_new->next = cloneTreeNode(node_top, node_parent, node->next, skip_sets_without_levels); return node_new; } void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets) { TreeInfo *ti_cloned = cloneTreeNode(ti_new, NULL, ti, skip_empty_sets); *ti_new = ti_cloned; } static boolean adjustTreeGraphicsForEMC(TreeInfo *node) { boolean settings_changed = FALSE; while (node) { if (node->graphics_set_ecs && !setup.prefer_aga_graphics && !strEqual(node->graphics_set, node->graphics_set_ecs)) { setString(&node->graphics_set, node->graphics_set_ecs); settings_changed = TRUE; } else if (node->graphics_set_aga && setup.prefer_aga_graphics && !strEqual(node->graphics_set, node->graphics_set_aga)) { setString(&node->graphics_set, node->graphics_set_aga); settings_changed = TRUE; } if (node->node_group != NULL) settings_changed |= adjustTreeGraphicsForEMC(node->node_group); node = node->next; } return settings_changed; } void dumpTreeInfo(TreeInfo *node, int depth) { int i; printf("Dumping TreeInfo:\n"); while (node) { for (i = 0; i < (depth + 1) * 3; i++) printf(" "); printf("subdir == '%s' ['%s', '%s'] [%d])\n", node->subdir, node->fullpath, node->basepath, node->in_user_dir); if (node->node_group != NULL) dumpTreeInfo(node->node_group, depth + 1); node = node->next; } } void sortTreeInfoBySortFunction(TreeInfo **node_first, int (*compare_function)(const void *, const void *)) { int num_nodes = numTreeInfo(*node_first); TreeInfo **sort_array; TreeInfo *node = *node_first; int i = 0; if (num_nodes == 0) return; /* allocate array for sorting structure pointers */ sort_array = checked_calloc(num_nodes * sizeof(TreeInfo *)); /* writing structure pointers to sorting array */ while (i < num_nodes && node) /* double boundary check... */ { sort_array[i] = node; i++; node = node->next; } /* sorting the structure pointers in the sorting array */ qsort(sort_array, num_nodes, sizeof(TreeInfo *), compare_function); /* update the linkage of list elements with the sorted node array */ for (i = 0; i < num_nodes - 1; i++) sort_array[i]->next = sort_array[i + 1]; sort_array[num_nodes - 1]->next = NULL; /* update the linkage of the main list anchor pointer */ *node_first = sort_array[0]; free(sort_array); /* now recursively sort the level group structures */ node = *node_first; while (node) { if (node->node_group != NULL) sortTreeInfoBySortFunction(&node->node_group, compare_function); node = node->next; } } void sortTreeInfo(TreeInfo **node_first) { sortTreeInfoBySortFunction(node_first, compareTreeInfoEntries); } /* ========================================================================= */ /* some stuff from "files.c" */ /* ========================================================================= */ #if defined(PLATFORM_WIN32) #ifndef S_IRGRP #define S_IRGRP S_IRUSR #endif #ifndef S_IROTH #define S_IROTH S_IRUSR #endif #ifndef S_IWGRP #define S_IWGRP S_IWUSR #endif #ifndef S_IWOTH #define S_IWOTH S_IWUSR #endif #ifndef S_IXGRP #define S_IXGRP S_IXUSR #endif #ifndef S_IXOTH #define S_IXOTH S_IXUSR #endif #ifndef S_IRWXG #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #endif #ifndef S_ISGID #define S_ISGID 0 #endif #endif /* PLATFORM_WIN32 */ /* file permissions for newly written files */ #define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) #define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) #define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) #define MODE_W_PRIVATE (S_IWUSR) #define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) #define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) #define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) #define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) #define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) #define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) char *getHomeDir() { static char *dir = NULL; #if defined(PLATFORM_WIN32) if (dir == NULL) { dir = checked_malloc(MAX_PATH + 1); if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir))) strcpy(dir, "."); } #elif defined(PLATFORM_UNIX) if (dir == NULL) { if ((dir = getenv("HOME")) == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) != NULL) dir = getStringCopy(pwd->pw_dir); else dir = "."; } } #else dir = "."; #endif return dir; } char *getCommonDataDir(void) { static char *common_data_dir = NULL; #if defined(PLATFORM_WIN32) if (common_data_dir == NULL) { char *dir = checked_malloc(MAX_PATH + 1); if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir)) && !strEqual(dir, "")) /* empty for Windows 95/98 */ common_data_dir = getPath2(dir, program.userdata_subdir); else common_data_dir = options.rw_base_directory; } #else if (common_data_dir == NULL) common_data_dir = options.rw_base_directory; #endif return common_data_dir; } char *getPersonalDataDir(void) { static char *personal_data_dir = NULL; #if defined(PLATFORM_MACOSX) if (personal_data_dir == NULL) personal_data_dir = getPath2(getHomeDir(), "Documents"); #else if (personal_data_dir == NULL) personal_data_dir = getHomeDir(); #endif return personal_data_dir; } char *getUserGameDataDir(void) { static char *user_game_data_dir = NULL; if (user_game_data_dir == NULL) user_game_data_dir = getPath2(getPersonalDataDir(), program.userdata_subdir); return user_game_data_dir; } void updateUserGameDataDir() { #if defined(PLATFORM_MACOSX) char *userdata_dir_old = getPath2(getHomeDir(), program.userdata_subdir_unix); char *userdata_dir_new = getUserGameDataDir(); /* do not free() this */ /* convert old Unix style game data directory to Mac OS X style, if needed */ if (fileExists(userdata_dir_old) && !fileExists(userdata_dir_new)) { if (rename(userdata_dir_old, userdata_dir_new) != 0) { Error(ERR_WARN, "cannot move game data directory '%s' to '%s'", userdata_dir_old, userdata_dir_new); /* continue using Unix style data directory -- this should not happen */ program.userdata_path = getPath2(getPersonalDataDir(), program.userdata_subdir_unix); } } free(userdata_dir_old); #endif } char *getSetupDir() { return getUserGameDataDir(); } static mode_t posix_umask(mode_t mask) { #if defined(PLATFORM_UNIX) return umask(mask); #else return 0; #endif } static int posix_mkdir(const char *pathname, mode_t mode) { #if defined(PLATFORM_WIN32) return mkdir(pathname); #else return mkdir(pathname, mode); #endif } static boolean posix_process_running_setgid() { #if defined(PLATFORM_UNIX) return (getgid() != getegid()); #else return FALSE; #endif } void createDirectory(char *dir, char *text, int permission_class) { /* leave "other" permissions in umask untouched, but ensure group parts of USERDATA_DIR_MODE are not masked */ mode_t dir_mode = (permission_class == PERMS_PRIVATE ? DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); mode_t last_umask = posix_umask(0); mode_t group_umask = ~(dir_mode & S_IRWXG); int running_setgid = posix_process_running_setgid(); /* if we're setgid, protect files against "other" */ /* else keep umask(0) to make the dir world-writable */ if (running_setgid) posix_umask(last_umask & group_umask); else dir_mode |= MODE_W_ALL; if (!fileExists(dir)) if (posix_mkdir(dir, dir_mode) != 0) Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); if (permission_class == PERMS_PUBLIC && !running_setgid) chmod(dir, dir_mode); posix_umask(last_umask); /* restore previous umask */ } void InitUserDataDirectory() { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); } void SetFilePermissions(char *filename, int permission_class) { int running_setgid = posix_process_running_setgid(); int perms = (permission_class == PERMS_PRIVATE ? FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); if (permission_class == PERMS_PUBLIC && !running_setgid) perms |= MODE_W_ALL; chmod(filename, perms); } char *getCookie(char *file_type) { static char cookie[MAX_COOKIE_LEN + 1]; if (strlen(program.cookie_prefix) + 1 + strlen(file_type) + strlen("_FILE_VERSION_x.x") > MAX_COOKIE_LEN) return "[COOKIE ERROR]"; /* should never happen */ sprintf(cookie, "%s_%s_FILE_VERSION_%d.%d", program.cookie_prefix, file_type, program.version_major, program.version_minor); return cookie; } int getFileVersionFromCookieString(const char *cookie) { const char *ptr_cookie1, *ptr_cookie2; const char *pattern1 = "_FILE_VERSION_"; const char *pattern2 = "?.?"; const int len_cookie = strlen(cookie); const int len_pattern1 = strlen(pattern1); const int len_pattern2 = strlen(pattern2); const int len_pattern = len_pattern1 + len_pattern2; int version_major, version_minor; if (len_cookie <= len_pattern) return -1; ptr_cookie1 = &cookie[len_cookie - len_pattern]; ptr_cookie2 = &cookie[len_cookie - len_pattern2]; if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0) return -1; if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' || ptr_cookie2[1] != '.' || ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') return -1; version_major = ptr_cookie2[0] - '0'; version_minor = ptr_cookie2[2] - '0'; return VERSION_IDENT(version_major, version_minor, 0, 0); } boolean checkCookieString(const char *cookie, const char *template) { const char *pattern = "_FILE_VERSION_?.?"; const int len_cookie = strlen(cookie); const int len_template = strlen(template); const int len_pattern = strlen(pattern); if (len_cookie != len_template) return FALSE; if (strncmp(cookie, template, len_cookie - len_pattern) != 0) return FALSE; return TRUE; } /* ------------------------------------------------------------------------- */ /* setup file list and hash handling functions */ /* ------------------------------------------------------------------------- */ char *getFormattedSetupEntry(char *token, char *value) { int i; static char entry[MAX_LINE_LEN]; /* if value is an empty string, just return token without value */ if (*value == '\0') return token; /* start with the token and some spaces to format output line */ sprintf(entry, "%s:", token); for (i = strlen(entry); i < token_value_position; i++) strcat(entry, " "); /* continue with the token's value */ strcat(entry, value); return entry; } SetupFileList *newSetupFileList(char *token, char *value) { SetupFileList *new = checked_malloc(sizeof(SetupFileList)); new->token = getStringCopy(token); new->value = getStringCopy(value); new->next = NULL; return new; } void freeSetupFileList(SetupFileList *list) { if (list == NULL) return; checked_free(list->token); checked_free(list->value); if (list->next) freeSetupFileList(list->next); free(list); } char *getListEntry(SetupFileList *list, char *token) { if (list == NULL) return NULL; if (strEqual(list->token, token)) return list->value; else return getListEntry(list->next, token); } SetupFileList *setListEntry(SetupFileList *list, char *token, char *value) { if (list == NULL) return NULL; if (strEqual(list->token, token)) { checked_free(list->value); list->value = getStringCopy(value); return list; } else if (list->next == NULL) return (list->next = newSetupFileList(token, value)); else return setListEntry(list->next, token, value); } SetupFileList *addListEntry(SetupFileList *list, char *token, char *value) { if (list == NULL) return NULL; if (list->next == NULL) return (list->next = newSetupFileList(token, value)); else return addListEntry(list->next, token, value); } #ifdef DEBUG static void printSetupFileList(SetupFileList *list) { if (!list) return; printf("token: '%s'\n", list->token); printf("value: '%s'\n", list->value); printSetupFileList(list->next); } #endif #ifdef DEBUG DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char); DEFINE_HASHTABLE_SEARCH(search_hash_entry, char, char); DEFINE_HASHTABLE_CHANGE(change_hash_entry, char, char); DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char); #else #define insert_hash_entry hashtable_insert #define search_hash_entry hashtable_search #define change_hash_entry hashtable_change #define remove_hash_entry hashtable_remove #endif unsigned int get_hash_from_key(void *key) { /* djb2 This algorithm (k=33) was first reported by Dan Bernstein many years ago in 'comp.lang.c'. Another version of this algorithm (now favored by Bernstein) uses XOR: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why it works better than many other constants, prime or not) has never been adequately explained. If you just want to have a good hash function, and cannot wait, djb2 is one of the best string hash functions i know. It has excellent distribution and speed on many different sets of keys and table sizes. You are not likely to do better with one of the "well known" functions such as PJW, K&R, etc. Ozan (oz) Yigit [http://www.cs.yorku.ca/~oz/hash.html] */ char *str = (char *)key; unsigned int hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash; } static int keys_are_equal(void *key1, void *key2) { return (strEqual((char *)key1, (char *)key2)); } SetupFileHash *newSetupFileHash() { SetupFileHash *new_hash = create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); if (new_hash == NULL) Error(ERR_EXIT, "create_hashtable() failed -- out of memory"); return new_hash; } void freeSetupFileHash(SetupFileHash *hash) { if (hash == NULL) return; hashtable_destroy(hash, 1); /* 1 == also free values stored in hash */ } char *getHashEntry(SetupFileHash *hash, char *token) { if (hash == NULL) return NULL; return search_hash_entry(hash, token); } void setHashEntry(SetupFileHash *hash, char *token, char *value) { char *value_copy; if (hash == NULL) return; value_copy = getStringCopy(value); /* change value; if it does not exist, insert it as new */ if (!change_hash_entry(hash, token, value_copy)) if (!insert_hash_entry(hash, getStringCopy(token), value_copy)) Error(ERR_EXIT, "cannot insert into hash -- aborting"); } char *removeHashEntry(SetupFileHash *hash, char *token) { if (hash == NULL) return NULL; return remove_hash_entry(hash, token); } #if 0 static void printSetupFileHash(SetupFileHash *hash) { BEGIN_HASH_ITERATION(hash, itr) { printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr)); printf("value: '%s'\n", HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(hash, itr) } #endif #define ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE 1 #define CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING 0 #define CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH 0 static boolean token_value_separator_found = FALSE; #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING static boolean token_value_separator_warning = FALSE; #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH static boolean token_already_exists_warning = FALSE; #endif static boolean getTokenValueFromSetupLineExt(char *line, char **token_ptr, char **value_ptr, char *filename, char *line_raw, int line_nr, boolean separator_required) { static char line_copy[MAX_LINE_LEN + 1], line_raw_copy[MAX_LINE_LEN + 1]; char *token, *value, *line_ptr; /* when externally invoked via ReadTokenValueFromLine(), copy line buffers */ if (line_raw == NULL) { strncpy(line_copy, line, MAX_LINE_LEN); line_copy[MAX_LINE_LEN] = '\0'; line = line_copy; strcpy(line_raw_copy, line_copy); line_raw = line_raw_copy; } /* cut trailing comment from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '#') { *line_ptr = '\0'; break; } } /* cut trailing whitespaces from input line */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* ignore empty lines */ if (*line == '\0') return FALSE; /* cut leading whitespaces from token */ for (token = line; *token; token++) if (*token != ' ' && *token != '\t') break; /* start with empty value as reliable default */ value = ""; token_value_separator_found = FALSE; /* find end of token to determine start of value */ for (line_ptr = token; *line_ptr; line_ptr++) { #if 1 /* first look for an explicit token/value separator, like ':' or '=' */ if (*line_ptr == ':' || *line_ptr == '=') #else if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') #endif { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE /* fallback: if no token/value separator found, also allow whitespaces */ if (!token_value_separator_found && !separator_required) { for (line_ptr = token; *line_ptr; line_ptr++) { if (*line_ptr == ' ' || *line_ptr == '\t') { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_found) { if (!token_value_separator_warning) { Error(ERR_INFO_LINE, "-"); if (filename != NULL) { Error(ERR_WARN, "missing token/value separator(s) in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); } else { Error(ERR_WARN, "missing token/value separator(s):"); } token_value_separator_warning = TRUE; } if (filename != NULL) Error(ERR_INFO, "- line %d: '%s'", line_nr, line_raw); else Error(ERR_INFO, "- line: '%s'", line_raw); } #endif } #endif /* cut trailing whitespaces from token */ for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--) if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* cut leading whitespaces from value */ for (; *value; value++) if (*value != ' ' && *value != '\t') break; #if 0 if (*value == '\0') value = "true"; /* treat tokens without value as "true" */ #endif *token_ptr = token; *value_ptr = value; return TRUE; } boolean getTokenValueFromSetupLine(char *line, char **token, char **value) { /* while the internal (old) interface does not require a token/value separator (for downwards compatibility with existing files which don't use them), it is mandatory for the external (new) interface */ return getTokenValueFromSetupLineExt(line, token, value, NULL, NULL, 0, TRUE); } #if 1 static boolean loadSetupFileData(void *setup_file_data, char *filename, boolean top_recursion_level, boolean is_hash) { static SetupFileHash *include_filename_hash = NULL; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char *token, *value, *line_ptr; void *insert_ptr = NULL; boolean read_continued_line = FALSE; FILE *file; int line_nr = 0, token_count = 0, include_count = 0; #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING token_value_separator_warning = FALSE; #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH token_already_exists_warning = FALSE; #endif if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot open configuration file '%s'", filename); return FALSE; } /* use "insert pointer" to store list end for constant insertion complexity */ if (!is_hash) insert_ptr = setup_file_data; /* on top invocation, create hash to mark included files (to prevent loops) */ if (top_recursion_level) include_filename_hash = newSetupFileHash(); /* mark this file as already included (to prevent including it again) */ setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true"); while (!feof(file)) { /* read next line of input file */ if (!fgets(line, MAX_LINE_LEN, file)) break; /* check if line was completely read and is terminated by line break */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line_nr++; /* cut trailing line break (this can be newline and/or carriage return) */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* copy raw input line for later use (mainly debugging output) */ strcpy(line_raw, line); if (read_continued_line) { #if 0 /* !!! ??? WHY ??? !!! */ /* cut leading whitespaces from input line */ for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ' && *line_ptr != '\t') break; #endif /* append new line to existing line, if there is enough space */ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) strcat(previous_line, line_ptr); strcpy(line, previous_line); /* copy storage buffer to line */ read_continued_line = FALSE; } /* if the last character is '\', continue at next line */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ strcpy(previous_line, line); /* copy line to storage buffer */ read_continued_line = TRUE; continue; } if (!getTokenValueFromSetupLineExt(line, &token, &value, filename, line_raw, line_nr, FALSE)) continue; if (*token) { if (strEqual(token, "include")) { if (getHashEntry(include_filename_hash, value) == NULL) { char *basepath = getBasePath(filename); char *basename = getBaseName(value); char *filename_include = getPath2(basepath, basename); #if 0 Error(ERR_INFO, "[including file '%s']", filename_include); #endif loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash); free(basepath); free(basename); free(filename_include); include_count++; } else { Error(ERR_WARN, "ignoring already processed file '%s'", value); } } else { if (is_hash) { #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH char *old_value = getHashEntry((SetupFileHash *)setup_file_data, token); if (old_value != NULL) { if (!token_already_exists_warning) { Error(ERR_INFO_LINE, "-"); Error(ERR_WARN, "duplicate token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); token_already_exists_warning = TRUE; } Error(ERR_INFO, "- token: '%s' (in line %d)", token, line_nr); Error(ERR_INFO, " old value: '%s'", old_value); Error(ERR_INFO, " new value: '%s'", value); } #endif setHashEntry((SetupFileHash *)setup_file_data, token, value); } else { insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value); } token_count++; } } } fclose(file); #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_warning) Error(ERR_INFO_LINE, "-"); #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH if (token_already_exists_warning) Error(ERR_INFO_LINE, "-"); #endif if (token_count == 0 && include_count == 0) Error(ERR_WARN, "configuration file '%s' is empty", filename); if (top_recursion_level) freeSetupFileHash(include_filename_hash); return TRUE; } #else static boolean loadSetupFileData(void *setup_file_data, char *filename, boolean top_recursion_level, boolean is_hash) { static SetupFileHash *include_filename_hash = NULL; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char *token, *value, *line_ptr; void *insert_ptr = NULL; boolean read_continued_line = FALSE; FILE *file; int line_nr = 0; int token_count = 0; #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING token_value_separator_warning = FALSE; #endif if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot open configuration file '%s'", filename); return FALSE; } /* use "insert pointer" to store list end for constant insertion complexity */ if (!is_hash) insert_ptr = setup_file_data; /* on top invocation, create hash to mark included files (to prevent loops) */ if (top_recursion_level) include_filename_hash = newSetupFileHash(); /* mark this file as already included (to prevent including it again) */ setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true"); while (!feof(file)) { /* read next line of input file */ if (!fgets(line, MAX_LINE_LEN, file)) break; /* check if line was completely read and is terminated by line break */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line_nr++; /* cut trailing line break (this can be newline and/or carriage return) */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* copy raw input line for later use (mainly debugging output) */ strcpy(line_raw, line); if (read_continued_line) { /* cut leading whitespaces from input line */ for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ' && *line_ptr != '\t') break; /* append new line to existing line, if there is enough space */ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) strcat(previous_line, line_ptr); strcpy(line, previous_line); /* copy storage buffer to line */ read_continued_line = FALSE; } /* if the last character is '\', continue at next line */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ strcpy(previous_line, line); /* copy line to storage buffer */ read_continued_line = TRUE; continue; } /* cut trailing comment from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '#') { *line_ptr = '\0'; break; } } /* cut trailing whitespaces from input line */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* ignore empty lines */ if (*line == '\0') continue; /* cut leading whitespaces from token */ for (token = line; *token; token++) if (*token != ' ' && *token != '\t') break; /* start with empty value as reliable default */ value = ""; token_value_separator_found = FALSE; /* find end of token to determine start of value */ for (line_ptr = token; *line_ptr; line_ptr++) { #if 1 /* first look for an explicit token/value separator, like ':' or '=' */ if (*line_ptr == ':' || *line_ptr == '=') #else if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') #endif { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE /* fallback: if no token/value separator found, also allow whitespaces */ if (!token_value_separator_found) { for (line_ptr = token; *line_ptr; line_ptr++) { if (*line_ptr == ' ' || *line_ptr == '\t') { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_found) { if (!token_value_separator_warning) { Error(ERR_INFO_LINE, "-"); Error(ERR_WARN, "missing token/value separator(s) in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); token_value_separator_warning = TRUE; } Error(ERR_INFO, "- line %d: '%s'", line_nr, line_raw); } #endif } #endif /* cut trailing whitespaces from token */ for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--) if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* cut leading whitespaces from value */ for (; *value; value++) if (*value != ' ' && *value != '\t') break; #if 0 if (*value == '\0') value = "true"; /* treat tokens without value as "true" */ #endif if (*token) { if (strEqual(token, "include")) { if (getHashEntry(include_filename_hash, value) == NULL) { char *basepath = getBasePath(filename); char *basename = getBaseName(value); char *filename_include = getPath2(basepath, basename); #if 0 Error(ERR_INFO, "[including file '%s']", filename_include); #endif loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash); free(basepath); free(basename); free(filename_include); } else { Error(ERR_WARN, "ignoring already processed file '%s'", value); } } else { if (is_hash) setHashEntry((SetupFileHash *)setup_file_data, token, value); else insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value); token_count++; } } } fclose(file); #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_warning) Error(ERR_INFO_LINE, "-"); #endif if (token_count == 0) Error(ERR_WARN, "configuration file '%s' is empty", filename); if (top_recursion_level) freeSetupFileHash(include_filename_hash); return TRUE; } #endif void saveSetupFileHash(SetupFileHash *hash, char *filename) { FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write configuration file '%s'", filename); return; } BEGIN_HASH_ITERATION(hash, itr) { fprintf(file, "%s\n", getFormattedSetupEntry(HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr))); } END_HASH_ITERATION(hash, itr) fclose(file); } SetupFileList *loadSetupFileList(char *filename) { SetupFileList *setup_file_list = newSetupFileList("", ""); SetupFileList *first_valid_list_entry; if (!loadSetupFileData(setup_file_list, filename, TRUE, FALSE)) { freeSetupFileList(setup_file_list); return NULL; } first_valid_list_entry = setup_file_list->next; /* free empty list header */ setup_file_list->next = NULL; freeSetupFileList(setup_file_list); return first_valid_list_entry; } SetupFileHash *loadSetupFileHash(char *filename) { SetupFileHash *setup_file_hash = newSetupFileHash(); if (!loadSetupFileData(setup_file_hash, filename, TRUE, TRUE)) { freeSetupFileHash(setup_file_hash); return NULL; } return setup_file_hash; } void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash, char *filename, char *identifier) { char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER); if (value == NULL) Error(ERR_WARN, "config file '%s' has no file identifier", filename); else if (!checkCookieString(value, identifier)) Error(ERR_WARN, "config file '%s' has wrong file identifier", filename); } /* ========================================================================= */ /* setup file stuff */ /* ========================================================================= */ #define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series" #define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level" #define TOKEN_STR_HANDICAP_LEVEL "handicap_level" /* level directory info */ #define LEVELINFO_TOKEN_IDENTIFIER 0 #define LEVELINFO_TOKEN_NAME 1 #define LEVELINFO_TOKEN_NAME_SORTING 2 #define LEVELINFO_TOKEN_AUTHOR 3 #define LEVELINFO_TOKEN_YEAR 4 #define LEVELINFO_TOKEN_IMPORTED_FROM 5 #define LEVELINFO_TOKEN_IMPORTED_BY 6 #define LEVELINFO_TOKEN_TESTED_BY 7 #define LEVELINFO_TOKEN_LEVELS 8 #define LEVELINFO_TOKEN_FIRST_LEVEL 9 #define LEVELINFO_TOKEN_SORT_PRIORITY 10 #define LEVELINFO_TOKEN_LATEST_ENGINE 11 #define LEVELINFO_TOKEN_LEVEL_GROUP 12 #define LEVELINFO_TOKEN_READONLY 13 #define LEVELINFO_TOKEN_GRAPHICS_SET_ECS 14 #define LEVELINFO_TOKEN_GRAPHICS_SET_AGA 15 #define LEVELINFO_TOKEN_GRAPHICS_SET 16 #define LEVELINFO_TOKEN_SOUNDS_SET 17 #define LEVELINFO_TOKEN_MUSIC_SET 18 #define LEVELINFO_TOKEN_FILENAME 19 #define LEVELINFO_TOKEN_FILETYPE 20 #define LEVELINFO_TOKEN_SPECIAL_FLAGS 21 #define LEVELINFO_TOKEN_HANDICAP 22 #define LEVELINFO_TOKEN_SKIP_LEVELS 23 #define NUM_LEVELINFO_TOKENS 24 static LevelDirTree ldi; static struct TokenInfo levelinfo_tokens[] = { /* level directory info */ { TYPE_STRING, &ldi.identifier, "identifier" }, { TYPE_STRING, &ldi.name, "name" }, { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, { TYPE_STRING, &ldi.year, "year" }, { TYPE_STRING, &ldi.imported_from, "imported_from" }, { TYPE_STRING, &ldi.imported_by, "imported_by" }, { TYPE_STRING, &ldi.tested_by, "tested_by" }, { TYPE_INTEGER, &ldi.levels, "levels" }, { TYPE_INTEGER, &ldi.first_level, "first_level" }, { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, { TYPE_BOOLEAN, &ldi.latest_engine, "latest_engine" }, { TYPE_BOOLEAN, &ldi.level_group, "level_group" }, { TYPE_BOOLEAN, &ldi.readonly, "readonly" }, { TYPE_STRING, &ldi.graphics_set_ecs, "graphics_set.ecs" }, { TYPE_STRING, &ldi.graphics_set_aga, "graphics_set.aga" }, { TYPE_STRING, &ldi.graphics_set, "graphics_set" }, { TYPE_STRING, &ldi.sounds_set, "sounds_set" }, { TYPE_STRING, &ldi.music_set, "music_set" }, { TYPE_STRING, &ldi.level_filename, "filename" }, { TYPE_STRING, &ldi.level_filetype, "filetype" }, { TYPE_STRING, &ldi.special_flags, "special_flags" }, { TYPE_BOOLEAN, &ldi.handicap, "handicap" }, { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" } }; static struct TokenInfo artworkinfo_tokens[] = { /* artwork directory info */ { TYPE_STRING, &ldi.identifier, "identifier" }, { TYPE_STRING, &ldi.subdir, "subdir" }, { TYPE_STRING, &ldi.name, "name" }, { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, { TYPE_STRING, &ldi.basepath, "basepath" }, { TYPE_STRING, &ldi.fullpath, "fullpath" }, { TYPE_BOOLEAN, &ldi.in_user_dir, "in_user_dir" }, { TYPE_INTEGER, &ldi.color, "color" }, { TYPE_STRING, &ldi.class_desc, "class_desc" }, { -1, NULL, NULL }, }; static void setTreeInfoToDefaults(TreeInfo *ti, int type) { ti->type = type; ti->node_top = (ti->type == TREE_TYPE_LEVEL_DIR ? &leveldir_first : ti->type == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first : ti->type == TREE_TYPE_SOUNDS_DIR ? &artwork.snd_first : ti->type == TREE_TYPE_MUSIC_DIR ? &artwork.mus_first : NULL); ti->node_parent = NULL; ti->node_group = NULL; ti->next = NULL; ti->cl_first = -1; ti->cl_cursor = -1; ti->subdir = NULL; ti->fullpath = NULL; ti->basepath = NULL; ti->identifier = NULL; ti->name = getStringCopy(ANONYMOUS_NAME); ti->name_sorting = NULL; ti->author = getStringCopy(ANONYMOUS_NAME); ti->year = NULL; ti->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ ti->latest_engine = FALSE; /* default: get from level */ ti->parent_link = FALSE; ti->in_user_dir = FALSE; ti->user_defined = FALSE; ti->color = 0; ti->class_desc = NULL; ti->infotext = getStringCopy(TREE_INFOTEXT(ti->type)); if (ti->type == TREE_TYPE_LEVEL_DIR) { ti->imported_from = NULL; ti->imported_by = NULL; ti->tested_by = NULL; ti->graphics_set_ecs = NULL; ti->graphics_set_aga = NULL; ti->graphics_set = NULL; ti->sounds_set = NULL; ti->music_set = NULL; ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); ti->level_filename = NULL; ti->level_filetype = NULL; ti->special_flags = NULL; ti->levels = 0; ti->first_level = 0; ti->last_level = 0; ti->level_group = FALSE; ti->handicap_level = 0; ti->readonly = TRUE; ti->handicap = TRUE; ti->skip_levels = FALSE; } } static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) { if (parent == NULL) { Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL"); setTreeInfoToDefaults(ti, TREE_TYPE_UNDEFINED); return; } /* copy all values from the parent structure */ ti->type = parent->type; ti->node_top = parent->node_top; ti->node_parent = parent; ti->node_group = NULL; ti->next = NULL; ti->cl_first = -1; ti->cl_cursor = -1; ti->subdir = NULL; ti->fullpath = NULL; ti->basepath = NULL; ti->identifier = NULL; ti->name = getStringCopy(ANONYMOUS_NAME); ti->name_sorting = NULL; ti->author = getStringCopy(parent->author); ti->year = getStringCopy(parent->year); ti->sort_priority = parent->sort_priority; ti->latest_engine = parent->latest_engine; ti->parent_link = FALSE; ti->in_user_dir = parent->in_user_dir; ti->user_defined = parent->user_defined; ti->color = parent->color; ti->class_desc = getStringCopy(parent->class_desc); ti->infotext = getStringCopy(parent->infotext); if (ti->type == TREE_TYPE_LEVEL_DIR) { ti->imported_from = getStringCopy(parent->imported_from); ti->imported_by = getStringCopy(parent->imported_by); ti->tested_by = getStringCopy(parent->tested_by); ti->graphics_set_ecs = NULL; ti->graphics_set_aga = NULL; ti->graphics_set = NULL; ti->sounds_set = NULL; ti->music_set = NULL; ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); ti->level_filename = NULL; ti->level_filetype = NULL; ti->special_flags = getStringCopy(parent->special_flags); ti->levels = 0; ti->first_level = 0; ti->last_level = 0; ti->level_group = FALSE; ti->handicap_level = 0; #if 1 ti->readonly = parent->readonly; #else ti->readonly = TRUE; #endif ti->handicap = TRUE; ti->skip_levels = FALSE; } } static TreeInfo *getTreeInfoCopy(TreeInfo *ti) { TreeInfo *ti_copy = newTreeInfo(); /* copy all values from the original structure */ ti_copy->type = ti->type; ti_copy->node_top = ti->node_top; ti_copy->node_parent = ti->node_parent; ti_copy->node_group = ti->node_group; ti_copy->next = ti->next; ti_copy->cl_first = ti->cl_first; ti_copy->cl_cursor = ti->cl_cursor; ti_copy->subdir = getStringCopy(ti->subdir); ti_copy->fullpath = getStringCopy(ti->fullpath); ti_copy->basepath = getStringCopy(ti->basepath); ti_copy->identifier = getStringCopy(ti->identifier); ti_copy->name = getStringCopy(ti->name); ti_copy->name_sorting = getStringCopy(ti->name_sorting); ti_copy->author = getStringCopy(ti->author); ti_copy->year = getStringCopy(ti->year); ti_copy->imported_from = getStringCopy(ti->imported_from); ti_copy->imported_by = getStringCopy(ti->imported_by); ti_copy->tested_by = getStringCopy(ti->tested_by); ti_copy->graphics_set_ecs = getStringCopy(ti->graphics_set_ecs); ti_copy->graphics_set_aga = getStringCopy(ti->graphics_set_aga); ti_copy->graphics_set = getStringCopy(ti->graphics_set); ti_copy->sounds_set = getStringCopy(ti->sounds_set); ti_copy->music_set = getStringCopy(ti->music_set); ti_copy->graphics_path = getStringCopy(ti->graphics_path); ti_copy->sounds_path = getStringCopy(ti->sounds_path); ti_copy->music_path = getStringCopy(ti->music_path); ti_copy->level_filename = getStringCopy(ti->level_filename); ti_copy->level_filetype = getStringCopy(ti->level_filetype); ti_copy->special_flags = getStringCopy(ti->special_flags); ti_copy->levels = ti->levels; ti_copy->first_level = ti->first_level; ti_copy->last_level = ti->last_level; ti_copy->sort_priority = ti->sort_priority; ti_copy->latest_engine = ti->latest_engine; ti_copy->level_group = ti->level_group; ti_copy->parent_link = ti->parent_link; ti_copy->in_user_dir = ti->in_user_dir; ti_copy->user_defined = ti->user_defined; ti_copy->readonly = ti->readonly; ti_copy->handicap = ti->handicap; ti_copy->skip_levels = ti->skip_levels; ti_copy->color = ti->color; ti_copy->class_desc = getStringCopy(ti->class_desc); ti_copy->handicap_level = ti->handicap_level; ti_copy->infotext = getStringCopy(ti->infotext); return ti_copy; } static void freeTreeInfo(TreeInfo *ti) { if (ti == NULL) return; checked_free(ti->subdir); checked_free(ti->fullpath); checked_free(ti->basepath); checked_free(ti->identifier); checked_free(ti->name); checked_free(ti->name_sorting); checked_free(ti->author); checked_free(ti->year); checked_free(ti->class_desc); checked_free(ti->infotext); if (ti->type == TREE_TYPE_LEVEL_DIR) { checked_free(ti->imported_from); checked_free(ti->imported_by); checked_free(ti->tested_by); checked_free(ti->graphics_set_ecs); checked_free(ti->graphics_set_aga); checked_free(ti->graphics_set); checked_free(ti->sounds_set); checked_free(ti->music_set); checked_free(ti->graphics_path); checked_free(ti->sounds_path); checked_free(ti->music_path); checked_free(ti->level_filename); checked_free(ti->level_filetype); checked_free(ti->special_flags); } checked_free(ti); } void setSetupInfo(struct TokenInfo *token_info, int token_nr, char *token_value) { int token_type = token_info[token_nr].type; void *setup_value = token_info[token_nr].value; if (token_value == NULL) return; /* set setup field to corresponding token value */ switch (token_type) { case TYPE_BOOLEAN: case TYPE_SWITCH: *(boolean *)setup_value = get_boolean_from_string(token_value); break; case TYPE_SWITCH3: *(int *)setup_value = get_switch3_from_string(token_value); break; case TYPE_KEY: *(Key *)setup_value = getKeyFromKeyName(token_value); break; case TYPE_KEY_X11: *(Key *)setup_value = getKeyFromX11KeyName(token_value); break; case TYPE_INTEGER: *(int *)setup_value = get_integer_from_string(token_value); break; case TYPE_STRING: checked_free(*(char **)setup_value); *(char **)setup_value = getStringCopy(token_value); break; default: break; } } static int compareTreeInfoEntries(const void *object1, const void *object2) { const TreeInfo *entry1 = *((TreeInfo **)object1); const TreeInfo *entry2 = *((TreeInfo **)object2); int class_sorting1, class_sorting2; int compare_result; if (entry1->type == TREE_TYPE_LEVEL_DIR) { class_sorting1 = LEVELSORTING(entry1); class_sorting2 = LEVELSORTING(entry2); } else { class_sorting1 = ARTWORKSORTING(entry1); class_sorting2 = ARTWORKSORTING(entry2); } if (entry1->parent_link || entry2->parent_link) compare_result = (entry1->parent_link ? -1 : +1); else if (entry1->sort_priority == entry2->sort_priority) { char *name1 = getStringToLower(entry1->name_sorting); char *name2 = getStringToLower(entry2->name_sorting); compare_result = strcmp(name1, name2); free(name1); free(name2); } else if (class_sorting1 == class_sorting2) compare_result = entry1->sort_priority - entry2->sort_priority; else compare_result = class_sorting1 - class_sorting2; return compare_result; } static void createParentTreeInfoNode(TreeInfo *node_parent) { TreeInfo *ti_new; if (node_parent == NULL) return; ti_new = newTreeInfo(); setTreeInfoToDefaults(ti_new, node_parent->type); ti_new->node_parent = node_parent; ti_new->parent_link = TRUE; setString(&ti_new->identifier, node_parent->identifier); setString(&ti_new->name, ".. (parent directory)"); setString(&ti_new->name_sorting, ti_new->name); setString(&ti_new->subdir, ".."); setString(&ti_new->fullpath, node_parent->fullpath); ti_new->sort_priority = node_parent->sort_priority; ti_new->latest_engine = node_parent->latest_engine; setString(&ti_new->class_desc, getLevelClassDescription(ti_new)); pushTreeInfo(&node_parent->node_group, ti_new); } /* -------------------------------------------------------------------------- */ /* functions for handling level and custom artwork info cache */ /* -------------------------------------------------------------------------- */ static void LoadArtworkInfoCache() { InitCacheDirectory(); if (artworkinfo_cache_old == NULL) { char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); /* try to load artwork info hash from already existing cache file */ artworkinfo_cache_old = loadSetupFileHash(filename); /* if no artwork info cache file was found, start with empty hash */ if (artworkinfo_cache_old == NULL) artworkinfo_cache_old = newSetupFileHash(); free(filename); } if (artworkinfo_cache_new == NULL) artworkinfo_cache_new = newSetupFileHash(); } static void SaveArtworkInfoCache() { char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); InitCacheDirectory(); saveSetupFileHash(artworkinfo_cache_new, filename); free(filename); } static char *getCacheTokenPrefix(char *prefix1, char *prefix2) { static char *prefix = NULL; checked_free(prefix); prefix = getStringCat2WithSeparator(prefix1, prefix2, "."); return prefix; } /* (identical to above function, but separate string buffer needed -- nasty) */ static char *getCacheToken(char *prefix, char *suffix) { static char *token = NULL; checked_free(token); token = getStringCat2WithSeparator(prefix, suffix, "."); return token; } static char *getFileTimestampString(char *filename) { #if 1 return getStringCopy(i_to_a(getFileTimestampEpochSeconds(filename))); #else struct stat file_status; if (stat(filename, &file_status) != 0) /* cannot stat file */ return getStringCopy(i_to_a(0)); return getStringCopy(i_to_a(file_status.st_mtime)); #endif } static boolean modifiedFileTimestamp(char *filename, char *timestamp_string) { struct stat file_status; if (timestamp_string == NULL) return TRUE; if (stat(filename, &file_status) != 0) /* cannot stat file */ return TRUE; return (file_status.st_mtime != atoi(timestamp_string)); } static TreeInfo *getArtworkInfoCacheEntry(LevelDirTree *level_node, int type) { char *identifier = level_node->subdir; char *type_string = ARTWORK_DIRECTORY(type); char *token_prefix = getCacheTokenPrefix(type_string, identifier); char *token_main = getCacheToken(token_prefix, "CACHED"); char *cache_entry = getHashEntry(artworkinfo_cache_old, token_main); boolean cached = (cache_entry != NULL && strEqual(cache_entry, "true")); TreeInfo *artwork_info = NULL; if (!use_artworkinfo_cache) return NULL; if (cached) { int i; artwork_info = newTreeInfo(); setTreeInfoToDefaults(artwork_info, type); /* set all structure fields according to the token/value pairs */ ldi = *artwork_info; for (i = 0; artworkinfo_tokens[i].type != -1; i++) { char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); char *value = getHashEntry(artworkinfo_cache_old, token); setSetupInfo(artworkinfo_tokens, i, value); /* check if cache entry for this item is invalid or incomplete */ if (value == NULL) { #if 1 Error(ERR_WARN, "cache entry '%s' invalid", token); #endif cached = FALSE; } } *artwork_info = ldi; } if (cached) { char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); /* check if corresponding "levelinfo.conf" file has changed */ token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); cache_entry = getHashEntry(artworkinfo_cache_old, token_main); if (modifiedFileTimestamp(filename_levelinfo, cache_entry)) cached = FALSE; /* check if corresponding ".conf" file has changed */ token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); cache_entry = getHashEntry(artworkinfo_cache_old, token_main); if (modifiedFileTimestamp(filename_artworkinfo, cache_entry)) cached = FALSE; #if 0 if (!cached) printf("::: '%s': INVALIDATED FROM CACHE BY TIMESTAMP\n", identifier); #endif checked_free(filename_levelinfo); checked_free(filename_artworkinfo); } if (!cached && artwork_info != NULL) { freeTreeInfo(artwork_info); return NULL; } return artwork_info; } static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, LevelDirTree *level_node, int type) { char *identifier = level_node->subdir; char *type_string = ARTWORK_DIRECTORY(type); char *token_prefix = getCacheTokenPrefix(type_string, identifier); char *token_main = getCacheToken(token_prefix, "CACHED"); boolean set_cache_timestamps = TRUE; int i; setHashEntry(artworkinfo_cache_new, token_main, "true"); if (set_cache_timestamps) { char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); char *timestamp_levelinfo = getFileTimestampString(filename_levelinfo); char *timestamp_artworkinfo = getFileTimestampString(filename_artworkinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_artworkinfo); checked_free(filename_levelinfo); checked_free(filename_artworkinfo); checked_free(timestamp_levelinfo); checked_free(timestamp_artworkinfo); } ldi = *artwork_info; for (i = 0; artworkinfo_tokens[i].type != -1; i++) { char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); char *value = getSetupValue(artworkinfo_tokens[i].type, artworkinfo_tokens[i].value); if (value != NULL) setHashEntry(artworkinfo_cache_new, token, value); } } /* -------------------------------------------------------------------------- */ /* functions for loading level info and custom artwork info */ /* -------------------------------------------------------------------------- */ /* forward declaration for recursive call by "LoadLevelInfoFromLevelDir()" */ static void LoadLevelInfoFromLevelDir(TreeInfo **, TreeInfo *, char *); static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, TreeInfo *node_parent, char *level_directory, char *directory_name) { #if 0 static unsigned long progress_delay = 0; unsigned long progress_delay_value = 100; /* (in milliseconds) */ #endif char *directory_path = getPath2(level_directory, directory_name); char *filename = getPath2(directory_path, LEVELINFO_FILENAME); SetupFileHash *setup_file_hash; LevelDirTree *leveldir_new = NULL; int i; /* unless debugging, silently ignore directories without "levelinfo.conf" */ if (!options.debug && !fileExists(filename)) { free(directory_path); free(filename); return FALSE; } setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash == NULL) { Error(ERR_WARN, "ignoring level directory '%s'", directory_path); free(directory_path); free(filename); return FALSE; } leveldir_new = newTreeInfo(); if (node_parent) setTreeInfoToDefaultsFromParent(leveldir_new, node_parent); else setTreeInfoToDefaults(leveldir_new, TREE_TYPE_LEVEL_DIR); leveldir_new->subdir = getStringCopy(directory_name); checkSetupFileHashIdentifier(setup_file_hash, filename, getCookie("LEVELINFO")); /* set all structure fields according to the token/value pairs */ ldi = *leveldir_new; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) setSetupInfo(levelinfo_tokens, i, getHashEntry(setup_file_hash, levelinfo_tokens[i].text)); *leveldir_new = ldi; if (strEqual(leveldir_new->name, ANONYMOUS_NAME)) setString(&leveldir_new->name, leveldir_new->subdir); if (leveldir_new->identifier == NULL) leveldir_new->identifier = getStringCopy(leveldir_new->subdir); if (leveldir_new->name_sorting == NULL) leveldir_new->name_sorting = getStringCopy(leveldir_new->name); if (node_parent == NULL) /* top level group */ { leveldir_new->basepath = getStringCopy(level_directory); leveldir_new->fullpath = getStringCopy(leveldir_new->subdir); } else /* sub level group */ { leveldir_new->basepath = getStringCopy(node_parent->basepath); leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name); } #if 0 if (leveldir_new->levels < 1) leveldir_new->levels = 1; #endif leveldir_new->last_level = leveldir_new->first_level + leveldir_new->levels - 1; leveldir_new->in_user_dir = (!strEqual(leveldir_new->basepath, options.level_directory)); #if 0 printf("::: '%s' -> %d\n", leveldir_new->identifier, leveldir_new->in_user_dir); #endif /* adjust some settings if user's private level directory was detected */ if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED && leveldir_new->in_user_dir && (strEqual(leveldir_new->subdir, getLoginName()) || strEqual(leveldir_new->name, getLoginName()) || strEqual(leveldir_new->author, getRealName()))) { leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START; leveldir_new->readonly = FALSE; } leveldir_new->user_defined = (leveldir_new->in_user_dir && IS_LEVELCLASS_PRIVATE(leveldir_new)); leveldir_new->color = LEVELCOLOR(leveldir_new); setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new)); leveldir_new->handicap_level = /* set handicap to default value */ (leveldir_new->user_defined || !leveldir_new->handicap ? leveldir_new->last_level : leveldir_new->first_level); #if 1 #if 1 DrawInitTextExt(leveldir_new->name, 150, FC_YELLOW, leveldir_new->level_group); #else if (leveldir_new->level_group || DelayReached(&progress_delay, progress_delay_value)) DrawInitText(leveldir_new->name, 150, FC_YELLOW); #endif #else DrawInitText(leveldir_new->name, 150, FC_YELLOW); #endif #if 0 /* !!! don't skip sets without levels (else artwork base sets are missing) */ #if 1 if (leveldir_new->levels < 1 && !leveldir_new->level_group) { /* skip level sets without levels (which are probably artwork base sets) */ freeSetupFileHash(setup_file_hash); free(directory_path); free(filename); return FALSE; } #endif #endif pushTreeInfo(node_first, leveldir_new); freeSetupFileHash(setup_file_hash); if (leveldir_new->level_group) { /* create node to link back to current level directory */ createParentTreeInfoNode(leveldir_new); /* recursively step into sub-directory and look for more level series */ LoadLevelInfoFromLevelDir(&leveldir_new->node_group, leveldir_new, directory_path); } free(directory_path); free(filename); return TRUE; } static void LoadLevelInfoFromLevelDir(TreeInfo **node_first, TreeInfo *node_parent, char *level_directory) { DIR *dir; struct dirent *dir_entry; boolean valid_entry_found = FALSE; if ((dir = opendir(level_directory)) == NULL) { Error(ERR_WARN, "cannot read level directory '%s'", level_directory); return; } while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { struct stat file_status; char *directory_name = dir_entry->d_name; char *directory_path = getPath2(level_directory, directory_name); /* skip entries for current and parent directory */ if (strEqual(directory_name, ".") || strEqual(directory_name, "..")) { free(directory_path); continue; } /* find out if directory entry is itself a directory */ if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ { free(directory_path); continue; } free(directory_path); if (strEqual(directory_name, GRAPHICS_DIRECTORY) || strEqual(directory_name, SOUNDS_DIRECTORY) || strEqual(directory_name, MUSIC_DIRECTORY)) continue; valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent, level_directory, directory_name); } closedir(dir); /* special case: top level directory may directly contain "levelinfo.conf" */ if (node_parent == NULL && !valid_entry_found) { /* check if this directory directly contains a file "levelinfo.conf" */ valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent, level_directory, "."); } if (!valid_entry_found) Error(ERR_WARN, "cannot find any valid level series in directory '%s'", level_directory); } boolean AdjustGraphicsForEMC() { boolean settings_changed = FALSE; settings_changed |= adjustTreeGraphicsForEMC(leveldir_first_all); settings_changed |= adjustTreeGraphicsForEMC(leveldir_first); return settings_changed; } void LoadLevelInfo() { InitUserLevelDirectory(getLoginName()); DrawInitText("Loading level series", 120, FC_GREEN); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL)); /* after loading all level set information, clone the level directory tree and remove all level sets without levels (these may still contain artwork to be offered in the setup menu as "custom artwork", and are therefore checked for existing artwork in the function "LoadLevelArtworkInfo()") */ leveldir_first_all = leveldir_first; cloneTree(&leveldir_first, leveldir_first_all, TRUE); AdjustGraphicsForEMC(); /* before sorting, the first entries will be from the user directory */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); if (leveldir_first == NULL) Error(ERR_EXIT, "cannot find any valid level series in any directory"); sortTreeInfo(&leveldir_first); #if 0 dumpTreeInfo(leveldir_first, 0); #endif } static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, TreeInfo *node_parent, char *base_directory, char *directory_name, int type) { char *directory_path = getPath2(base_directory, directory_name); char *filename = getPath2(directory_path, ARTWORKINFO_FILENAME(type)); SetupFileHash *setup_file_hash = NULL; TreeInfo *artwork_new = NULL; int i; if (fileExists(filename)) setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash == NULL) /* no config file -- look for artwork files */ { DIR *dir; struct dirent *dir_entry; boolean valid_file_found = FALSE; if ((dir = opendir(directory_path)) != NULL) { while ((dir_entry = readdir(dir)) != NULL) { char *entry_name = dir_entry->d_name; if (FileIsArtworkType(entry_name, type)) { valid_file_found = TRUE; break; } } closedir(dir); } if (!valid_file_found) { if (!strEqual(directory_name, ".")) Error(ERR_WARN, "ignoring artwork directory '%s'", directory_path); free(directory_path); free(filename); return FALSE; } } artwork_new = newTreeInfo(); if (node_parent) setTreeInfoToDefaultsFromParent(artwork_new, node_parent); else setTreeInfoToDefaults(artwork_new, type); artwork_new->subdir = getStringCopy(directory_name); if (setup_file_hash) /* (before defining ".color" and ".class_desc") */ { #if 0 checkSetupFileHashIdentifier(setup_file_hash, filename, getCookie("...")); #endif /* set all structure fields according to the token/value pairs */ ldi = *artwork_new; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) setSetupInfo(levelinfo_tokens, i, getHashEntry(setup_file_hash, levelinfo_tokens[i].text)); *artwork_new = ldi; if (strEqual(artwork_new->name, ANONYMOUS_NAME)) setString(&artwork_new->name, artwork_new->subdir); if (artwork_new->identifier == NULL) artwork_new->identifier = getStringCopy(artwork_new->subdir); if (artwork_new->name_sorting == NULL) artwork_new->name_sorting = getStringCopy(artwork_new->name); } if (node_parent == NULL) /* top level group */ { artwork_new->basepath = getStringCopy(base_directory); artwork_new->fullpath = getStringCopy(artwork_new->subdir); } else /* sub level group */ { artwork_new->basepath = getStringCopy(node_parent->basepath); artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name); } artwork_new->in_user_dir = (!strEqual(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type))); /* (may use ".sort_priority" from "setup_file_hash" above) */ artwork_new->color = ARTWORKCOLOR(artwork_new); setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); if (setup_file_hash == NULL) /* (after determining ".user_defined") */ { if (strEqual(artwork_new->subdir, ".")) { if (artwork_new->user_defined) { setString(&artwork_new->identifier, "private"); artwork_new->sort_priority = ARTWORKCLASS_PRIVATE; } else { setString(&artwork_new->identifier, "classic"); artwork_new->sort_priority = ARTWORKCLASS_CLASSICS; } /* set to new values after changing ".sort_priority" */ artwork_new->color = ARTWORKCOLOR(artwork_new); setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); } else { setString(&artwork_new->identifier, artwork_new->subdir); } setString(&artwork_new->name, artwork_new->identifier); setString(&artwork_new->name_sorting, artwork_new->name); } #if 0 DrawInitText(artwork_new->name, 150, FC_YELLOW); #endif pushTreeInfo(node_first, artwork_new); freeSetupFileHash(setup_file_hash); free(directory_path); free(filename); return TRUE; } static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first, TreeInfo *node_parent, char *base_directory, int type) { DIR *dir; struct dirent *dir_entry; boolean valid_entry_found = FALSE; if ((dir = opendir(base_directory)) == NULL) { /* display error if directory is main "options.graphics_directory" etc. */ if (base_directory == OPTIONS_ARTWORK_DIRECTORY(type)) Error(ERR_WARN, "cannot read directory '%s'", base_directory); return; } while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { struct stat file_status; char *directory_name = dir_entry->d_name; char *directory_path = getPath2(base_directory, directory_name); /* skip directory entries for current and parent directory */ if (strEqual(directory_name, ".") || strEqual(directory_name, "..")) { free(directory_path); continue; } /* skip directory entries which are not a directory or are not accessible */ if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ { free(directory_path); continue; } free(directory_path); /* check if this directory contains artwork with or without config file */ valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent, base_directory, directory_name, type); } closedir(dir); /* check if this directory directly contains artwork itself */ valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent, base_directory, ".", type); if (!valid_entry_found) Error(ERR_WARN, "cannot find any valid artwork in directory '%s'", base_directory); } static TreeInfo *getDummyArtworkInfo(int type) { /* this is only needed when there is completely no artwork available */ TreeInfo *artwork_new = newTreeInfo(); setTreeInfoToDefaults(artwork_new, type); setString(&artwork_new->subdir, UNDEFINED_FILENAME); setString(&artwork_new->fullpath, UNDEFINED_FILENAME); setString(&artwork_new->basepath, UNDEFINED_FILENAME); setString(&artwork_new->identifier, UNDEFINED_FILENAME); setString(&artwork_new->name, UNDEFINED_FILENAME); setString(&artwork_new->name_sorting, UNDEFINED_FILENAME); return artwork_new; } void LoadArtworkInfo() { LoadArtworkInfoCache(); DrawInitText("Looking for custom artwork", 120, FC_GREEN); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, options.graphics_directory, TREE_TYPE_GRAPHICS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, getUserGraphicsDir(), TREE_TYPE_GRAPHICS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.snd_first, NULL, options.sounds_directory, TREE_TYPE_SOUNDS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.snd_first, NULL, getUserSoundsDir(), TREE_TYPE_SOUNDS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.mus_first, NULL, options.music_directory, TREE_TYPE_MUSIC_DIR); LoadArtworkInfoFromArtworkDir(&artwork.mus_first, NULL, getUserMusicDir(), TREE_TYPE_MUSIC_DIR); if (artwork.gfx_first == NULL) artwork.gfx_first = getDummyArtworkInfo(TREE_TYPE_GRAPHICS_DIR); if (artwork.snd_first == NULL) artwork.snd_first = getDummyArtworkInfo(TREE_TYPE_SOUNDS_DIR); if (artwork.mus_first == NULL) artwork.mus_first = getDummyArtworkInfo(TREE_TYPE_MUSIC_DIR); /* before sorting, the first entries will be from the user directory */ artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); artwork.gfx_current_identifier = artwork.gfx_current->identifier; artwork.snd_current_identifier = artwork.snd_current->identifier; artwork.mus_current_identifier = artwork.mus_current->identifier; #if 0 printf("graphics set == %s\n\n", artwork.gfx_current_identifier); printf("sounds set == %s\n\n", artwork.snd_current_identifier); printf("music set == %s\n\n", artwork.mus_current_identifier); #endif sortTreeInfo(&artwork.gfx_first); sortTreeInfo(&artwork.snd_first); sortTreeInfo(&artwork.mus_first); #if 0 dumpTreeInfo(artwork.gfx_first, 0); dumpTreeInfo(artwork.snd_first, 0); dumpTreeInfo(artwork.mus_first, 0); #endif } void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, LevelDirTree *level_node) { #if 0 static unsigned long progress_delay = 0; unsigned long progress_delay_value = 100; /* (in milliseconds) */ #endif int type = (*artwork_node)->type; /* recursively check all level directories for artwork sub-directories */ while (level_node) { /* check all tree entries for artwork, but skip parent link entries */ if (!level_node->parent_link) { TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type); boolean cached = (artwork_new != NULL); if (cached) { pushTreeInfo(artwork_node, artwork_new); } else { TreeInfo *topnode_last = *artwork_node; char *path = getPath2(getLevelDirFromTreeInfo(level_node), ARTWORK_DIRECTORY(type)); LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path, type); if (topnode_last != *artwork_node) /* check for newly added node */ { artwork_new = *artwork_node; setString(&artwork_new->identifier, level_node->subdir); setString(&artwork_new->name, level_node->name); setString(&artwork_new->name_sorting, level_node->name_sorting); artwork_new->sort_priority = level_node->sort_priority; artwork_new->color = LEVELCOLOR(artwork_new); } free(path); } /* insert artwork info (from old cache or filesystem) into new cache */ if (artwork_new != NULL) setArtworkInfoCacheEntry(artwork_new, level_node, type); } #if 1 DrawInitTextExt(level_node->name, 150, FC_YELLOW, level_node->level_group); #else if (level_node->level_group || DelayReached(&progress_delay, progress_delay_value)) DrawInitText(level_node->name, 150, FC_YELLOW); #endif if (level_node->node_group != NULL) LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group); level_node = level_node->next; } } void LoadLevelArtworkInfo() { DrawInitText("Looking for custom level artwork", 120, FC_GREEN); LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all); LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all); LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all); SaveArtworkInfoCache(); /* needed for reloading level artwork not known at ealier stage */ if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set)) { artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); } if (!strEqual(artwork.snd_current_identifier, setup.sounds_set)) { artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); } if (!strEqual(artwork.mus_current_identifier, setup.music_set)) { artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); } sortTreeInfo(&artwork.gfx_first); sortTreeInfo(&artwork.snd_first); sortTreeInfo(&artwork.mus_first); #if 0 dumpTreeInfo(artwork.gfx_first, 0); dumpTreeInfo(artwork.snd_first, 0); dumpTreeInfo(artwork.mus_first, 0); #endif } static void SaveUserLevelInfo() { LevelDirTree *level_info; char *filename; FILE *file; int i; filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write level info file '%s'", filename); free(filename); return; } level_info = newTreeInfo(); /* always start with reliable default values */ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR); setString(&level_info->name, getLoginName()); setString(&level_info->author, getRealName()); level_info->levels = 100; level_info->first_level = 1; token_value_position = TOKEN_VALUE_POSITION_SHORT; fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("LEVELINFO"))); ldi = *level_info; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) { if (i == LEVELINFO_TOKEN_NAME || i == LEVELINFO_TOKEN_AUTHOR || i == LEVELINFO_TOKEN_LEVELS || i == LEVELINFO_TOKEN_FIRST_LEVEL) fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); /* just to make things nicer :) */ if (i == LEVELINFO_TOKEN_AUTHOR) fprintf(file, "\n"); } token_value_position = TOKEN_VALUE_POSITION_DEFAULT; fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); freeTreeInfo(level_info); free(filename); } char *getSetupValue(int type, void *value) { static char value_string[MAX_LINE_LEN]; if (value == NULL) return NULL; switch (type) { case TYPE_BOOLEAN: strcpy(value_string, (*(boolean *)value ? "true" : "false")); break; case TYPE_SWITCH: strcpy(value_string, (*(boolean *)value ? "on" : "off")); break; case TYPE_SWITCH3: strcpy(value_string, (*(int *)value == AUTO ? "auto" : *(int *)value == FALSE ? "off" : "on")); break; case TYPE_YES_NO: strcpy(value_string, (*(boolean *)value ? "yes" : "no")); break; case TYPE_YES_NO_AUTO: strcpy(value_string, (*(int *)value == AUTO ? "auto" : *(int *)value == FALSE ? "no" : "yes")); break; case TYPE_ECS_AGA: strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS")); break; case TYPE_KEY: strcpy(value_string, getKeyNameFromKey(*(Key *)value)); break; case TYPE_KEY_X11: strcpy(value_string, getX11KeyNameFromKey(*(Key *)value)); break; case TYPE_INTEGER: sprintf(value_string, "%d", *(int *)value); break; case TYPE_STRING: if (*(char **)value == NULL) return NULL; strcpy(value_string, *(char **)value); break; default: value_string[0] = '\0'; break; } if (type & TYPE_GHOSTED) strcpy(value_string, "n/a"); return value_string; } char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr) { int i; char *line; static char token_string[MAX_LINE_LEN]; int token_type = token_info[token_nr].type; void *setup_value = token_info[token_nr].value; char *token_text = token_info[token_nr].text; char *value_string = getSetupValue(token_type, setup_value); /* build complete token string */ sprintf(token_string, "%s%s", prefix, token_text); /* build setup entry line */ line = getFormattedSetupEntry(token_string, value_string); if (token_type == TYPE_KEY_X11) { Key key = *(Key *)setup_value; char *keyname = getKeyNameFromKey(key); /* add comment, if useful */ if (!strEqual(keyname, "(undefined)") && !strEqual(keyname, "(unknown)")) { /* add at least one whitespace */ strcat(line, " "); for (i = strlen(line); i < token_comment_position; i++) strcat(line, " "); strcat(line, "# "); strcat(line, keyname); } } return line; } void LoadLevelSetup_LastSeries() { /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ /* ----------------------------------------------------------------------- */ char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); SetupFileHash *level_setup_hash = NULL; /* always start with reliable default values */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); #if defined(CREATE_SPECIAL_EDITION_RND_JUE) leveldir_current = getTreeInfoFromIdentifier(leveldir_first, "jue_start"); if (leveldir_current == NULL) leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); #endif if ((level_setup_hash = loadSetupFileHash(filename))) { char *last_level_series = getHashEntry(level_setup_hash, TOKEN_STR_LAST_LEVEL_SERIES); leveldir_current = getTreeInfoFromIdentifier(leveldir_first, last_level_series); if (leveldir_current == NULL) leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); checkSetupFileHashIdentifier(level_setup_hash, filename, getCookie("LEVELSETUP")); freeSetupFileHash(level_setup_hash); } else Error(ERR_WARN, "using default setup values"); free(filename); } void SaveLevelSetup_LastSeries() { /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ /* ----------------------------------------------------------------------- */ char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); char *level_subdir = leveldir_current->subdir; FILE *file; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); free(filename); return; } fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("LEVELSETUP"))); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES, level_subdir)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } static void checkSeriesInfo() { static char *level_directory = NULL; DIR *dir; struct dirent *dir_entry; /* check for more levels besides the 'levels' field of 'levelinfo.conf' */ level_directory = getPath2((leveldir_current->in_user_dir ? getUserLevelDir(NULL) : options.level_directory), leveldir_current->fullpath); if ((dir = opendir(level_directory)) == NULL) { Error(ERR_WARN, "cannot read level directory '%s'", level_directory); return; } while ((dir_entry = readdir(dir)) != NULL) /* last directory entry */ { if (strlen(dir_entry->d_name) > 4 && dir_entry->d_name[3] == '.' && strEqual(&dir_entry->d_name[4], LEVELFILE_EXTENSION)) { char levelnum_str[4]; int levelnum_value; strncpy(levelnum_str, dir_entry->d_name, 3); levelnum_str[3] = '\0'; levelnum_value = atoi(levelnum_str); #if 0 if (levelnum_value < leveldir_current->first_level) { Error(ERR_WARN, "additional level %d found", levelnum_value); leveldir_current->first_level = levelnum_value; } else if (levelnum_value > leveldir_current->last_level) { Error(ERR_WARN, "additional level %d found", levelnum_value); leveldir_current->last_level = levelnum_value; } #endif } } closedir(dir); } void LoadLevelSetup_SeriesInfo() { char *filename; SetupFileHash *level_setup_hash = NULL; char *level_subdir = leveldir_current->subdir; /* always start with reliable default values */ level_nr = leveldir_current->first_level; checkSeriesInfo(leveldir_current); /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ /* ----------------------------------------------------------------------- */ level_subdir = leveldir_current->subdir; filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); if ((level_setup_hash = loadSetupFileHash(filename))) { char *token_value; token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL); if (token_value) { level_nr = atoi(token_value); if (level_nr < leveldir_current->first_level) level_nr = leveldir_current->first_level; if (level_nr > leveldir_current->last_level) level_nr = leveldir_current->last_level; } token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL); if (token_value) { int level_nr = atoi(token_value); if (level_nr < leveldir_current->first_level) level_nr = leveldir_current->first_level; if (level_nr > leveldir_current->last_level + 1) level_nr = leveldir_current->last_level; if (leveldir_current->user_defined || !leveldir_current->handicap) level_nr = leveldir_current->last_level; leveldir_current->handicap_level = level_nr; } checkSetupFileHashIdentifier(level_setup_hash, filename, getCookie("LEVELSETUP")); freeSetupFileHash(level_setup_hash); } else Error(ERR_WARN, "using default setup values"); free(filename); } void SaveLevelSetup_SeriesInfo() { char *filename; char *level_subdir = leveldir_current->subdir; char *level_nr_str = int2str(level_nr, 0); char *handicap_level_str = int2str(leveldir_current->handicap_level, 0); FILE *file; /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ /* ----------------------------------------------------------------------- */ InitLevelSetupDirectory(level_subdir); filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); free(filename); return; } fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("LEVELSETUP"))); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, level_nr_str)); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, handicap_level_str)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/sound.h0000644000175000017500000001202610471574553020332 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * sound.h * ***********************************************************/ #ifndef SOUND_H #define SOUND_H #include "system.h" #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL) #define AUDIO_UNIX_NATIVE #endif #if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) || defined(VOXWARE) #define AUDIO_LINUX_IOCTL #endif #if defined(AUDIO_LINUX_IOCTL) || defined(PLATFORM_NETBSD) #define AUDIO_STREAMING_DSP #endif /* values for platform specific sound initialization */ #define AUDIO_SAMPLE_RATE_8000 8000 #define AUDIO_SAMPLE_RATE_22050 22050 #define AUDIO_FRAGMENT_SIZE_512 512 #define AUDIO_FRAGMENT_SIZE_1024 1024 #define AUDIO_FRAGMENT_SIZE_2048 2048 #define AUDIO_FRAGMENT_SIZE_4096 4096 #define AUDIO_FRAGMENT_SIZE_32768 32768 #define AUDIO_NUM_CHANNELS_MONO 1 #define AUDIO_NUM_CHANNELS_STEREO 2 #define AUDIO_FORMAT_UNKNOWN (0) #define AUDIO_FORMAT_U8 (1 << 0) #define AUDIO_FORMAT_S16 (1 << 1) #define AUDIO_FORMAT_LE (1 << 2) #define AUDIO_FORMAT_BE (1 << 3) #if defined(AUDIO_UNIX_NATIVE) && !defined(AUDIO_STREAMING_DSP) #define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_8000 #else #define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_22050 #endif #if defined(PLATFORM_HPUX) #define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_32768 #elif defined(PLATFORM_WIN32) #define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_1024 #else #define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_512 #endif #if defined(TARGET_SDL) #define NUM_MIXER_CHANNELS MIX_CHANNELS #else #define NUM_MIXER_CHANNELS 8 #endif #define MUSIC_CHANNEL 0 #define FIRST_SOUND_CHANNEL 1 /* values for PlaySound(), StopSound() and friends */ #define SND_CTRL_NONE (0) #define SND_CTRL_MUSIC (1 << 0) #define SND_CTRL_LOOP (1 << 1) #define SND_CTRL_FADE (1 << 2) #define SND_CTRL_STOP (1 << 3) #define SND_CTRL_ALL_SOUNDS (1 << 4) #define SND_CTRL_RELOAD_SOUNDS (1 << 5) #define SND_CTRL_RELOAD_MUSIC (1 << 6) #define SND_CTRL_PLAY_SOUND (SND_CTRL_NONE) #define SND_CTRL_PLAY_LOOP (SND_CTRL_LOOP) #define SND_CTRL_PLAY_MUSIC (SND_CTRL_LOOP | SND_CTRL_MUSIC) #define SND_CTRL_FADE_SOUND (SND_CTRL_FADE) #define SND_CTRL_FADE_MUSIC (SND_CTRL_FADE | SND_CTRL_MUSIC) #define SND_CTRL_FADE_ALL (SND_CTRL_FADE | SND_CTRL_ALL_SOUNDS) #define SND_CTRL_STOP_SOUND (SND_CTRL_STOP) #define SND_CTRL_STOP_MUSIC (SND_CTRL_STOP | SND_CTRL_MUSIC) #define SND_CTRL_STOP_ALL (SND_CTRL_STOP | SND_CTRL_ALL_SOUNDS) #define IS_MUSIC(x) ((x).state & SND_CTRL_MUSIC) #define IS_LOOP(x) ((x).state & SND_CTRL_LOOP) #define IS_FADING(x) ((x).state & SND_CTRL_FADE) #define IS_STOPPING(x) ((x).state & SND_CTRL_STOP) #define IS_RELOADING(x) ((x).state & (SND_CTRL_RELOAD_SOUNDS |\ SND_CTRL_RELOAD_MUSIC)) #define ALL_SOUNDS(x) ((x).state & SND_CTRL_ALL_SOUNDS) #define MAP_NOCONF_MUSIC(x) (-((x) + 1)) #define UNMAP_NOCONF_MUSIC(x) MAP_NOCONF_MUSIC(x) #define SOUND_MIN_VOLUME 0 #if defined(TARGET_SDL) #define SOUND_MAX_VOLUME SDL_MIX_MAXVOLUME #elif defined(TARGET_ALLEGRO) #define SOUND_MAX_VOLUME 255 #else #define SOUND_MAX_VOLUME 128 #endif #define SOUND_MAX_LEFT 0 #define SOUND_MAX_RIGHT 255 #define SOUND_MAX_LEFT2RIGHT 255 #define SOUND_MIDDLE (SOUND_MAX_LEFT2RIGHT / 2) /* general sound functions */ void UnixOpenAudio(void); void UnixCloseAudio(void); /* mixer functions */ void Mixer_InitChannels(void); void StartMixer(void); /* sound client functions */ void PlayMusic(int); void PlaySound(int); void PlaySoundStereo(int, int); void PlaySoundLoop(int); void PlaySoundMusic(int); void PlaySoundExt(int, int, int, int); void FadeMusic(void); void FadeSound(int); void FadeSounds(void); void FadeSoundsAndMusic(void); void StopMusic(void); void StopSound(int); void StopSounds(void); void StopSoundExt(int, int); int getSoundListSize(); int getMusicListSize(); struct FileInfo *getSoundListEntry(int); struct FileInfo *getMusicListEntry(int); int getSoundListPropertyMappingSize(); int getMusicListPropertyMappingSize(); struct PropertyMapping *getSoundListPropertyMapping(); struct PropertyMapping *getMusicListPropertyMapping(); void InitSoundList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void InitMusicList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void InitReloadCustomSounds(char *); void InitReloadCustomMusic(char *); void FreeAllSounds(void); void FreeAllMusic(void); #endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/snapshot.c0000644000175000017500000000317411337605605021033 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * snapshot.c * ***********************************************************/ #include "snapshot.h" static ListNode *engine_snapshot_list = NULL; void SaveEngineSnapshotBuffer(void *buffer, int size) { struct EngineSnapshotNodeInfo *bi = checked_calloc(sizeof(struct EngineSnapshotNodeInfo)); bi->buffer_orig = buffer; bi->buffer_copy = checked_malloc(size); bi->size = size; memcpy(bi->buffer_copy, buffer, size); addNodeToList(&engine_snapshot_list, NULL, bi); } static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi) { memcpy(bi->buffer_orig, bi->buffer_copy, bi->size); } void LoadEngineSnapshotBuffers() { ListNode *node = engine_snapshot_list; while (node != NULL) { LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content); node = node->next; } } void FreeEngineSnapshotBuffers() { while (engine_snapshot_list != NULL) deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key, checked_free); } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/joystick.h0000644000175000017500000000543711403520377021040 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * joystick.h * ***********************************************************/ #ifndef JOYSTICK_H #define JOYSTICK_H #include "system.h" #define JOYSTICK_NOT_AVAILABLE 0 #define JOYSTICK_AVAILABLE (1 << 0) #define JOYSTICK_ACTIVE (1 << 1) #define JOYSTICK_ACTIVATED (JOYSTICK_AVAILABLE | JOYSTICK_ACTIVE) #if defined(PLATFORM_FREEBSD) #define DEV_JOYSTICK_0 "/dev/joy0" #define DEV_JOYSTICK_1 "/dev/joy1" #define DEV_JOYSTICK_2 "/dev/joy2" #define DEV_JOYSTICK_3 "/dev/joy3" #else #define DEV_JOYSTICK_0 "/dev/js0" #define DEV_JOYSTICK_1 "/dev/js1" #define DEV_JOYSTICK_2 "/dev/js2" #define DEV_JOYSTICK_3 "/dev/js3" #endif /* get these values from the program 'js' from the joystick package, */ /* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */ #ifdef TARGET_SDL #define JOYSTICK_XLEFT -32767 #define JOYSTICK_XMIDDLE 0 #define JOYSTICK_XRIGHT 32767 #define JOYSTICK_YUPPER -32767 #define JOYSTICK_YMIDDLE 0 #define JOYSTICK_YLOWER 32767 #else #define JOYSTICK_XLEFT 1 #define JOYSTICK_XMIDDLE 128 #define JOYSTICK_XRIGHT 255 #define JOYSTICK_YUPPER 1 #define JOYSTICK_YMIDDLE 128 #define JOYSTICK_YLOWER 255 #endif #define JOYSTICK_PERCENT 25 #define JOY_NO_ACTION 0 #define JOY_LEFT MV_LEFT #define JOY_RIGHT MV_RIGHT #define JOY_UP MV_UP #define JOY_DOWN MV_DOWN #define JOY_BUTTON_1 KEY_BUTTON_1 #define JOY_BUTTON_2 KEY_BUTTON_2 #define JOY_BUTTON_SNAP KEY_BUTTON_SNAP #define JOY_BUTTON_DROP KEY_BUTTON_DROP #define JOY_MOTION KEY_MOTION #define JOY_BUTTON KEY_BUTTON #define JOY_ACTION KEY_ACTION #define JOY_BUTTON_NOT_PRESSED 0 #define JOY_BUTTON_PRESSED 1 #define JOY_BUTTON_NEW_PRESSED 2 #define JOY_BUTTON_NEW_RELEASED 3 #if defined(PLATFORM_UNIX) void UnixInitJoysticks(void); boolean UnixReadJoystick(int, int *, int *, boolean *, boolean *); #endif char *getJoyNameFromJoySymbol(int); int getJoySymbolFromJoyName(char *); int getJoystickNrFromDeviceName(char *); char *getDeviceNameFromJoystickNr(int); void CheckJoystickData(void); int Joystick(int); int JoystickButton(int); int AnyJoystick(void); int AnyJoystickButton(void); void DeactivateJoystick(); void ActivateJoystick(); #endif /* JOYSTICK_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/sound.c0000644000175000017500000017154611322337033020324 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * sound.c * ***********************************************************/ #include #include #include #include #include #include #include #include #include "platform.h" #if defined(PLATFORM_LINUX) #include #include #elif defined(PLATFORM_FREEBSD) #include #elif defined(PLATFORM_NETBSD) #include #include #elif defined(PLATFORM_HPUX) #include #endif #include "system.h" #include "sound.h" #include "misc.h" #include "setup.h" #include "text.h" /* expiration time (in milliseconds) for sound loops */ #define SOUND_LOOP_EXPIRATION_TIME 200 /* one second fading interval == 1000 ticks (milliseconds) */ #define SOUND_FADING_INTERVAL 1000 #if defined(AUDIO_STREAMING_DSP) #define SOUND_FADING_VOLUME_STEP (SOUND_MAX_VOLUME / 40) #define SOUND_FADING_VOLUME_THRESHOLD (SOUND_FADING_VOLUME_STEP * 2) #endif #define SND_TYPE_NONE 0 #define SND_TYPE_WAV 1 #define MUS_TYPE_NONE 0 #define MUS_TYPE_WAV 1 #define MUS_TYPE_MOD 2 #define DEVICENAME_DSP "/dev/dsp" #define DEVICENAME_SOUND_DSP "/dev/sound/dsp" #define DEVICENAME_AUDIO "/dev/audio" #define DEVICENAME_AUDIOCTL "/dev/audioCtl" #define SOUND_VOLUME_LEFT(x) (stereo_volume[x]) #define SOUND_VOLUME_RIGHT(x) (stereo_volume[SOUND_MAX_LEFT2RIGHT-x]) #define SAME_SOUND_NR(x,y) ((x).nr == (y).nr) #define SAME_SOUND_DATA(x,y) ((x).data_ptr == (y).data_ptr) #if defined(AUDIO_UNIX_NATIVE) struct SoundHeader_WAV { unsigned short compression_code; unsigned short num_channels; unsigned long sample_rate; unsigned long bytes_per_second; unsigned short block_align; unsigned short bits_per_sample; }; #endif struct AudioFormatInfo { boolean stereo; /* availability of stereo sound */ int format; /* size and endianess of sample data */ int sample_rate; /* sample frequency */ int fragment_size; /* audio device fragment size in bytes */ }; struct SampleInfo { char *source_filename; int num_references; int type; int format; void *data_ptr; /* pointer to first sample (8 or 16 bit) */ long data_len; /* number of samples, NOT number of bytes */ int num_channels; /* mono: 1 channel, stereo: 2 channels */ }; typedef struct SampleInfo SoundInfo; typedef struct SampleInfo MusicInfo; struct SoundControl { boolean active; int nr; int volume; int stereo_position; int state; unsigned long playing_starttime; unsigned long playing_pos; int type; int format; void *data_ptr; /* pointer to first sample (8 or 16 bit) */ long data_len; /* number of samples, NOT number of bytes */ int num_channels; /* mono: 1 channel, stereo: 2 channels */ #if defined(TARGET_ALLEGRO) int voice; #endif }; typedef struct SoundControl SoundControl; static struct ArtworkListInfo *sound_info = NULL; static struct ArtworkListInfo *music_info = NULL; static MusicInfo **Music_NoConf = NULL; static int num_music_noconf = 0; static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1]; /* ========================================================================= */ /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ static struct SoundControl mixer[NUM_MIXER_CHANNELS]; static int mixer_active_channels = 0; #if defined(AUDIO_UNIX_NATIVE) static struct AudioFormatInfo afmt; static void Mixer_Main(void); #if !defined(AUDIO_STREAMING_DSP) static unsigned char linear_to_ulaw(int); static int ulaw_to_linear(unsigned char); #endif #endif static void ReloadCustomSounds(); static void ReloadCustomMusic(); static void FreeSound(void *); static void FreeMusic(void *); static void FreeAllMusic_NoConf(); static SoundInfo *getSoundInfoEntryFromSoundID(int); static MusicInfo *getMusicInfoEntryFromMusicID(int); /* ------------------------------------------------------------------------- */ /* functions for native (non-SDL) Unix audio/mixer support */ /* ------------------------------------------------------------------------- */ #if defined(AUDIO_UNIX_NATIVE) static int OpenAudioDevice(char *audio_device_name) { int audio_device_fd; /* check if desired audio device is accessible */ if (access(audio_device_name, W_OK) != 0) return -1; /* try to open audio device in non-blocking mode */ if ((audio_device_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0) return audio_device_fd; /* re-open audio device in blocking mode */ close(audio_device_fd); audio_device_fd = open(audio_device_name, O_WRONLY); return audio_device_fd; } static void CloseAudioDevice(int *audio_device_fd) { if (*audio_device_fd == 0) return; close(*audio_device_fd); *audio_device_fd = -1; } static boolean TestAudioDevices(void) { static char *audio_device_name[] = { DEVICENAME_DSP, DEVICENAME_SOUND_DSP, DEVICENAME_AUDIO }; int audio_device_fd = -1; int i; /* look for available audio devices, starting with preferred ones */ for (i = 0; i < sizeof(audio_device_name)/sizeof(char *); i++) if ((audio_device_fd = OpenAudioDevice(audio_device_name[i])) >= 0) break; if (audio_device_fd < 0) { Error(ERR_WARN, "cannot open audio device -- no sound"); return FALSE; } close(audio_device_fd); audio.device_name = audio_device_name[i]; return TRUE; } static boolean ForkAudioProcess(void) { if (pipe(audio.mixer_pipe) < 0) { Error(ERR_WARN, "cannot create pipe -- no sounds"); return FALSE; } if ((audio.mixer_pid = fork()) < 0) { Error(ERR_WARN, "cannot create sound server process -- no sounds"); return FALSE; } if (audio.mixer_pid == 0) /* we are the child process */ audio.mixer_pid = getpid(); if (IS_CHILD_PROCESS()) Mixer_Main(); /* this function never returns */ else close(audio.mixer_pipe[0]); /* no reading from pipe needed */ return TRUE; } void UnixOpenAudio(void) { if (!TestAudioDevices()) return; audio.sound_available = TRUE; audio.sound_enabled = TRUE; #if defined(AUDIO_STREAMING_DSP) audio.music_available = TRUE; audio.loops_available = TRUE; #endif audio.num_channels = NUM_MIXER_CHANNELS; audio.music_channel = MUSIC_CHANNEL; audio.first_sound_channel = FIRST_SOUND_CHANNEL; } void UnixCloseAudio(void) { if (audio.device_fd) close(audio.device_fd); if (IS_PARENT_PROCESS() && HAS_CHILD_PROCESS()) kill(audio.mixer_pid, SIGTERM); } /* ------------------------------------------------------------------------- */ /* functions for platform specific audio device initialization */ /* ------------------------------------------------------------------------- */ #if defined(AUDIO_LINUX_IOCTL) static void InitAudioDevice_Linux(struct AudioFormatInfo *afmt) { /* "ioctl()" expects pointer to 'int' value for stereo flag (boolean is defined as 'char', which will not work here) */ unsigned int fragment_spec = 0; int fragment_size_query = -1; int stereo = TRUE; struct { int format_ioctl; int format_result; } formats[] = { /* supported audio format in preferred order */ { AFMT_S16_LE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_LE }, { AFMT_S16_BE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_BE }, { AFMT_U8, AUDIO_FORMAT_U8 }, { -1, -1 } }; int i; /* determine logarithm (log2) of the fragment size */ while ((1 << fragment_spec) < afmt->fragment_size) fragment_spec++; /* use two fragments (play one fragment, prepare the other); one fragment would result in interrupted audio output, more than two fragments would raise audio output latency to much */ fragment_spec |= 0x00020000; /* Example for fragment specification: - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz) - (with stereo the effective buffer size will shrink to 256) => fragment_size = 0x00020009 */ if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0) Error(ERR_EXIT_SOUND_SERVER, "cannot set fragment size of audio device -- no sounds"); i = 0; afmt->format = 0; while (formats[i].format_result != -1) { unsigned int audio_format = formats[i].format_ioctl; if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) == 0) { afmt->format = formats[i].format_result; break; } } if (afmt->format == 0) /* no supported audio format found */ Error(ERR_EXIT_SOUND_SERVER, "cannot set audio format of audio device -- no sounds"); /* try if we can use stereo sound */ afmt->stereo = TRUE; if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0) afmt->stereo = FALSE; if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &afmt->sample_rate) < 0) Error(ERR_EXIT_SOUND_SERVER, "cannot set sample rate of audio device -- no sounds"); /* get the real fragmentation size; this should return 512 */ if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0) Error(ERR_EXIT_SOUND_SERVER, "cannot get fragment size of audio device -- no sounds"); if (fragment_size_query != afmt->fragment_size) Error(ERR_EXIT_SOUND_SERVER, "cannot set fragment size of audio device -- no sounds"); } #endif /* AUDIO_LINUX_IOCTL */ #if defined(PLATFORM_NETBSD) static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt) { audio_info_t a_info; boolean stereo = TRUE; AUDIO_INITINFO(&a_info); a_info.play.encoding = AUDIO_ENCODING_LINEAR8; a_info.play.precision = 8; a_info.play.channels = 2; a_info.play.sample_rate = afmt->sample_rate; a_info.blocksize = afmt->fragment_size; afmt->format = AUDIO_FORMAT_U8; afmt->stereo = TRUE; if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0) { /* try to disable stereo */ a_info.play.channels = 1; afmt->stereo = FALSE; if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0) Error(ERR_EXIT_SOUND_SERVER, "cannot set sample rate of audio device -- no sounds"); } } #endif /* PLATFORM_NETBSD */ #if defined(PLATFORM_HPUX) static void InitAudioDevice_HPUX(struct AudioFormatInfo *afmt) { struct audio_describe ainfo; int audio_ctl; audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY); if (audio_ctl == -1) Error(ERR_EXIT_SOUND_SERVER, "cannot open audio device -- no sounds"); if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1) Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds"); if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1) Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds"); ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1); ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000); afmt->format = AUDIO_FORMAT_U8; afmt->stereo = FALSE; afmt->sample_rate = 8000; close(audio_ctl); } #endif /* PLATFORM_HPUX */ static void InitAudioDevice(struct AudioFormatInfo *afmt) { afmt->stereo = TRUE; afmt->format = AUDIO_FORMAT_UNKNOWN; afmt->sample_rate = DEFAULT_AUDIO_SAMPLE_RATE; afmt->fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE; #if defined(AUDIO_LINUX_IOCTL) InitAudioDevice_Linux(afmt); #elif defined(PLATFORM_NETBSD) InitAudioDevice_NetBSD(afmt); #elif defined(PLATFORM_HPUX) InitAudioDevice_HPUX(afmt); #else /* generic /dev/audio stuff might be placed here */ #endif } /* ------------------------------------------------------------------------- */ /* functions for communication between main process and sound mixer process */ /* ------------------------------------------------------------------------- */ static void SendSoundControlToMixerProcess(SoundControl *snd_ctrl) { if (IS_CHILD_PROCESS()) return; if (write(audio.mixer_pipe[1], snd_ctrl, sizeof(SoundControl)) < 0) { Error(ERR_WARN, "cannot pipe to child process -- no sounds"); audio.sound_available = audio.sound_enabled = FALSE; return; } } static void ReadSoundControlFromMainProcess(SoundControl *snd_ctrl) { if (IS_PARENT_PROCESS()) return; if (read(audio.mixer_pipe[0], snd_ctrl, sizeof(SoundControl)) != sizeof(SoundControl)) Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds"); } static void WriteReloadInfoToPipe(char *set_identifier, int type) { SoundControl snd_ctrl; TreeInfo *ti = (type == SND_CTRL_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current); unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1; unsigned long str_size2 = strlen(leveldir_current->sounds_path) + 1; unsigned long str_size3 = strlen(leveldir_current->music_path) + 1; unsigned long str_size4 = strlen(ti->basepath) + 1; unsigned long str_size5 = strlen(ti->fullpath) + 1; boolean override_level_artwork = (type == SND_CTRL_RELOAD_SOUNDS ? gfx.override_level_sounds : gfx.override_level_music); if (IS_CHILD_PROCESS()) return; if (leveldir_current == NULL) /* should never happen */ Error(ERR_EXIT, "leveldir_current == NULL"); clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = FALSE; snd_ctrl.state = type; snd_ctrl.data_len = strlen(set_identifier) + 1; if (write(audio.mixer_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0 || write(audio.mixer_pipe[1], set_identifier, snd_ctrl.data_len) < 0 || write(audio.mixer_pipe[1], &override_level_artwork, sizeof(boolean)) < 0 || write(audio.mixer_pipe[1], leveldir_current, sizeof(TreeInfo)) < 0 || write(audio.mixer_pipe[1], ti, sizeof(TreeInfo)) < 0 || write(audio.mixer_pipe[1], &str_size1, sizeof(unsigned long)) < 0 || write(audio.mixer_pipe[1], &str_size2, sizeof(unsigned long)) < 0 || write(audio.mixer_pipe[1], &str_size3, sizeof(unsigned long)) < 0 || write(audio.mixer_pipe[1], &str_size4, sizeof(unsigned long)) < 0 || write(audio.mixer_pipe[1], &str_size5, sizeof(unsigned long)) < 0 || write(audio.mixer_pipe[1], leveldir_current->fullpath, str_size1) < 0 || write(audio.mixer_pipe[1], leveldir_current->sounds_path, str_size2) < 0 || write(audio.mixer_pipe[1], leveldir_current->music_path, str_size3) < 0 || write(audio.mixer_pipe[1], ti->basepath, str_size4) < 0 || write(audio.mixer_pipe[1], ti->fullpath, str_size5) < 0) { Error(ERR_WARN, "cannot pipe to child process -- no sounds"); audio.sound_available = audio.sound_enabled = FALSE; return; } } static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl) { TreeInfo **ti_ptr = ((snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS) ? &artwork.snd_current : &artwork.mus_current); TreeInfo *ti = *ti_ptr; unsigned long str_size1, str_size2, str_size3, str_size4, str_size5; static char *set_identifier = NULL; boolean *override_level_artwork = (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS ? &gfx.override_level_sounds : &gfx.override_level_music); checked_free(set_identifier); set_identifier = checked_malloc(snd_ctrl->data_len); if (leveldir_current == NULL) leveldir_current = checked_calloc(sizeof(TreeInfo)); if (ti == NULL) ti = *ti_ptr = checked_calloc(sizeof(TreeInfo)); checked_free(leveldir_current->fullpath); checked_free(leveldir_current->sounds_path); checked_free(leveldir_current->music_path); checked_free(ti->basepath); checked_free(ti->fullpath); if (read(audio.mixer_pipe[0], set_identifier, snd_ctrl->data_len) != snd_ctrl->data_len || read(audio.mixer_pipe[0], override_level_artwork, sizeof(boolean)) != sizeof(boolean) || read(audio.mixer_pipe[0], leveldir_current, sizeof(TreeInfo)) != sizeof(TreeInfo) || read(audio.mixer_pipe[0], ti, sizeof(TreeInfo)) != sizeof(TreeInfo) || read(audio.mixer_pipe[0], &str_size1, sizeof(unsigned long)) != sizeof(unsigned long) || read(audio.mixer_pipe[0], &str_size2, sizeof(unsigned long)) != sizeof(unsigned long) || read(audio.mixer_pipe[0], &str_size3, sizeof(unsigned long)) != sizeof(unsigned long) || read(audio.mixer_pipe[0], &str_size4, sizeof(unsigned long)) != sizeof(unsigned long) || read(audio.mixer_pipe[0], &str_size5, sizeof(unsigned long)) != sizeof(unsigned long)) Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds"); leveldir_current->fullpath = checked_calloc(str_size1); leveldir_current->sounds_path = checked_calloc(str_size2); leveldir_current->music_path = checked_calloc(str_size3); ti->basepath = checked_calloc(str_size4); ti->fullpath = checked_calloc(str_size5); if (read(audio.mixer_pipe[0], leveldir_current->fullpath, str_size1) != str_size1 || read(audio.mixer_pipe[0], leveldir_current->sounds_path, str_size2) != str_size2 || read(audio.mixer_pipe[0], leveldir_current->music_path, str_size3) != str_size3 || read(audio.mixer_pipe[0], ti->basepath, str_size4) != str_size4 || read(audio.mixer_pipe[0], ti->fullpath, str_size5) != str_size5) Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds"); if (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS) artwork.snd_current_identifier = set_identifier; else artwork.mus_current_identifier = set_identifier; } #endif /* AUDIO_UNIX_NATIVE */ /* ------------------------------------------------------------------------- */ /* mixer functions */ /* ------------------------------------------------------------------------- */ void Mixer_InitChannels() { int i; for (i = 0; i < audio.num_channels; i++) mixer[i].active = FALSE; mixer_active_channels = 0; } static void Mixer_ResetChannelExpiration(int channel) { mixer[channel].playing_starttime = Counter(); #if defined(TARGET_SDL) if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel])) Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME); #endif } static boolean Mixer_ChannelExpired(int channel) { if (!mixer[channel].active) return TRUE; if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) && DelayReached(&mixer[channel].playing_starttime, SOUND_LOOP_EXPIRATION_TIME)) return TRUE; #if defined(TARGET_SDL) if (!Mix_Playing(channel)) return TRUE; #elif defined(TARGET_ALLEGRO) mixer[channel].playing_pos = voice_get_position(mixer[channel].voice); mixer[channel].volume = voice_get_volume(mixer[channel].voice); /* sound sample has completed playing or was completely faded out */ if (mixer[channel].playing_pos == -1 || mixer[channel].volume == 0) return TRUE; #endif /* TARGET_ALLEGRO */ return FALSE; } static boolean Mixer_AllocateChannel(int channel) { #if defined(TARGET_ALLEGRO) mixer[channel].voice = allocate_voice((SAMPLE *)mixer[channel].data_ptr); if (mixer[channel].voice < 0) return FALSE; #endif return TRUE; } static void Mixer_SetChannelProperties(int channel) { #if defined(TARGET_SDL) Mix_Volume(channel, mixer[channel].volume); Mix_SetPanning(channel, SOUND_VOLUME_LEFT(mixer[channel].stereo_position), SOUND_VOLUME_RIGHT(mixer[channel].stereo_position)); #elif defined(TARGET_ALLEGRO) voice_set_volume(mixer[channel].voice, mixer[channel].volume); voice_set_pan(mixer[channel].voice, mixer[channel].stereo_position); #endif } static void Mixer_StartChannel(int channel) { #if defined(TARGET_SDL) Mix_PlayChannel(channel, mixer[channel].data_ptr, IS_LOOP(mixer[channel]) ? -1 : 0); #elif defined(TARGET_ALLEGRO) if (IS_LOOP(mixer[channel])) voice_set_playmode(mixer[channel].voice, PLAYMODE_LOOP); voice_start(mixer[channel].voice); #endif } static void Mixer_PlayChannel(int channel) { /* start with inactive channel in case something goes wrong */ mixer[channel].active = FALSE; if (mixer[channel].type != MUS_TYPE_WAV) return; if (!Mixer_AllocateChannel(channel)) return; Mixer_SetChannelProperties(channel); Mixer_StartChannel(channel); Mixer_ResetChannelExpiration(channel); mixer[channel].playing_pos = 0; mixer[channel].active = TRUE; mixer_active_channels++; } static void Mixer_PlayMusicChannel() { Mixer_PlayChannel(audio.music_channel); #if defined(TARGET_SDL) if (mixer[audio.music_channel].type != MUS_TYPE_WAV) { /* Mix_VolumeMusic() must be called _after_ Mix_PlayMusic() -- this looks like a bug in the SDL_mixer library */ Mix_PlayMusic(mixer[audio.music_channel].data_ptr, -1); Mix_VolumeMusic(SOUND_MAX_VOLUME); } #endif } static void Mixer_StopChannel(int channel) { if (!mixer[channel].active) return; #if defined(TARGET_SDL) Mix_HaltChannel(channel); #elif defined(TARGET_ALLEGRO) voice_set_volume(mixer[channel].voice, 0); deallocate_voice(mixer[channel].voice); #endif mixer[channel].active = FALSE; mixer_active_channels--; } static void Mixer_StopMusicChannel() { Mixer_StopChannel(audio.music_channel); #if defined(TARGET_SDL) Mix_HaltMusic(); #endif } static void Mixer_FadeChannel(int channel) { if (!mixer[channel].active) return; mixer[channel].state |= SND_CTRL_FADE; #if defined(TARGET_SDL) Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL); #elif defined(TARGET_ALLEGRO) if (voice_check(mixer[channel].voice)) voice_ramp_volume(mixer[channel].voice, SOUND_FADING_INTERVAL, 0); #endif } static void Mixer_FadeMusicChannel() { Mixer_FadeChannel(audio.music_channel); #if defined(TARGET_SDL) Mix_FadeOutMusic(SOUND_FADING_INTERVAL); #endif } static void Mixer_UnFadeChannel(int channel) { if (!mixer[channel].active || !IS_FADING(mixer[channel])) return; mixer[channel].state &= ~SND_CTRL_FADE; mixer[channel].volume = SOUND_MAX_VOLUME; #if defined(TARGET_SDL) Mix_ExpireChannel(channel, -1); Mix_Volume(channel, mixer[channel].volume); #elif defined(TARGET_ALLEGRO) voice_stop_volumeramp(mixer[channel].voice); voice_ramp_volume(mixer[channel].voice, SOUND_FADING_INTERVAL, mixer[channel].volume); #endif } static void Mixer_InsertSound(SoundControl snd_ctrl) { SoundInfo *snd_info; int i, k; int num_sounds = getSoundListSize(); int num_music = getMusicListSize(); if (IS_MUSIC(snd_ctrl)) { if (snd_ctrl.nr >= num_music) /* invalid music */ return; if (snd_ctrl.nr < 0) /* undefined music */ { if (num_music_noconf == 0) /* no fallback music available */ return; snd_ctrl.nr = UNMAP_NOCONF_MUSIC(snd_ctrl.nr) % num_music_noconf; snd_info = Music_NoConf[snd_ctrl.nr]; } else snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr); } else { if (snd_ctrl.nr < 0 || snd_ctrl.nr >= num_sounds) return; snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr); } if (snd_info == NULL) return; /* copy sound sample and format information */ snd_ctrl.type = snd_info->type; snd_ctrl.format = snd_info->format; snd_ctrl.data_ptr = snd_info->data_ptr; snd_ctrl.data_len = snd_info->data_len; snd_ctrl.num_channels = snd_info->num_channels; /* play music samples on a dedicated music channel */ if (IS_MUSIC(snd_ctrl)) { Mixer_StopMusicChannel(); mixer[audio.music_channel] = snd_ctrl; Mixer_PlayMusicChannel(); return; } /* check if (and how often) this sound sample is already playing */ for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++) if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl)) k++; /* reset expiration delay for already playing loop sounds */ if (k > 0 && IS_LOOP(snd_ctrl)) { for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl)) { if (IS_FADING(mixer[i])) Mixer_UnFadeChannel(i); /* restore settings like volume and stereo position */ mixer[i].volume = snd_ctrl.volume; mixer[i].stereo_position = snd_ctrl.stereo_position; Mixer_SetChannelProperties(i); Mixer_ResetChannelExpiration(i); } } return; } /* don't play sound more than n times simultaneously (with n == 2 for now) */ if (k >= 2) { unsigned long playing_current = Counter(); int longest = 0, longest_nr = audio.first_sound_channel; /* look for oldest equal sound */ for (i = audio.first_sound_channel; i < audio.num_channels; i++) { int playing_time = playing_current - mixer[i].playing_starttime; int actual; if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl)) continue; actual = 1000 * playing_time / mixer[i].data_len; if (actual >= longest) { longest = actual; longest_nr = i; } } Mixer_StopChannel(longest_nr); } /* If all (non-music) channels are active, stop the channel that has played its sound sample most completely (in percent of the sample length). As we cannot currently get the actual playing position of the channel's sound sample when compiling with the SDL mixer library, we use the current playing time (in milliseconds) instead. */ #if DEBUG /* channel allocation sanity check -- should not be needed */ if (mixer_active_channels == audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1)) { for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (!mixer[i].active) { Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i); Error(ERR_INFO, "Mixer_InsertSound: This should never happen!"); mixer_active_channels--; } } } #endif if (mixer_active_channels == audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1)) { unsigned long playing_current = Counter(); int longest = 0, longest_nr = audio.first_sound_channel; #if 0 #if DEBUG /* print some debugging information about audio channel usage */ for (i = audio.first_sound_channel; i < audio.num_channels; i++) { Error(ERR_INFO, "Mixer_InsertSound: %d [%d]: %ld (%ld)", i, mixer[i].active, mixer[i].data_len, (long)mixer[i].data_ptr); } #endif #endif for (i = audio.first_sound_channel; i < audio.num_channels; i++) { int playing_time = playing_current - mixer[i].playing_starttime; int actual = 1000 * playing_time / mixer[i].data_len; if (!IS_LOOP(mixer[i]) && actual > longest) { longest = actual; longest_nr = i; } } Mixer_StopChannel(longest_nr); } /* add the new sound to the mixer */ for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (!mixer[i].active) { #if defined(AUDIO_UNIX_NATIVE) if (snd_info->data_len == 0) { printf("THIS SHOULD NEVER HAPPEN! [snd_info->data_len == 0]\n"); } #endif mixer[i] = snd_ctrl; Mixer_PlayChannel(i); break; } } } static void HandleSoundRequest(SoundControl snd_ctrl) { int i; #if defined(AUDIO_UNIX_NATIVE) if (IS_PARENT_PROCESS()) { SendSoundControlToMixerProcess(&snd_ctrl); return; } #endif /* deactivate channels that have expired since the last request */ for (i = 0; i < audio.num_channels; i++) if (mixer[i].active && Mixer_ChannelExpired(i)) Mixer_StopChannel(i); if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */ { Mixer_StopMusicChannel(); for (i = audio.first_sound_channel; i < audio.num_channels; i++) Mixer_StopChannel(i); #if defined(AUDIO_UNIX_NATIVE) CloseAudioDevice(&audio.device_fd); ReadReloadInfoFromPipe(&snd_ctrl); #endif if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS) ReloadCustomSounds(); else ReloadCustomMusic(); } else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */ { if (IS_MUSIC(snd_ctrl)) { Mixer_FadeMusicChannel(); return; } for (i = audio.first_sound_channel; i < audio.num_channels; i++) if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl)) Mixer_FadeChannel(i); } else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */ { if (IS_MUSIC(snd_ctrl)) { Mixer_StopMusicChannel(); return; } for (i = audio.first_sound_channel; i < audio.num_channels; i++) if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl)) Mixer_StopChannel(i); #if defined(AUDIO_UNIX_NATIVE) if (!mixer_active_channels) CloseAudioDevice(&audio.device_fd); #endif } else if (snd_ctrl.active) /* add new sound to mixer */ { Mixer_InsertSound(snd_ctrl); } } void StartMixer(void) { int i; #if 0 SDL_version compile_version; const SDL_version *link_version; MIX_VERSION(&compile_version); printf("compiled with SDL_mixer version: %d.%d.%d\n", compile_version.major, compile_version.minor, compile_version.patch); link_version = Mix_Linked_Version(); printf("running with SDL_mixer version: %d.%d.%d\n", link_version->major, link_version->minor, link_version->patch); #endif if (!audio.sound_available) return; /* initialize stereo position conversion information */ for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++) stereo_volume[i] = (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i)); #if defined(AUDIO_UNIX_NATIVE) if (!ForkAudioProcess()) audio.sound_available = FALSE; #endif } #if defined(AUDIO_UNIX_NATIVE) static void CopySampleToMixingBuffer(SoundControl *snd_ctrl, int sample_pos, int sample_size, short *buffer_base_ptr, int buffer_pos, int num_output_channels) { short *buffer_ptr = buffer_base_ptr + num_output_channels * buffer_pos; int num_channels = snd_ctrl->num_channels; int stepsize = num_channels; int output_stepsize = num_output_channels; int i, j; if (snd_ctrl->format == AUDIO_FORMAT_U8) { byte *sample_ptr = (byte *)snd_ctrl->data_ptr + num_channels * sample_pos; for (i = 0; i < num_output_channels; i++) { int offset = (snd_ctrl->num_channels == 1 ? 0 : i); for (j = 0; j < sample_size; j++) buffer_ptr[output_stepsize * j + i] = ((short)(sample_ptr[stepsize * j + offset] ^ 0x80)) << 8; } } else /* AUDIO_FORMAT_S16 */ { short *sample_ptr= (short *)snd_ctrl->data_ptr + num_channels * sample_pos; for (i = 0; i < num_output_channels; i++) { int offset = (snd_ctrl->num_channels == 1 ? 0 : i); for (j = 0; j < sample_size; j++) buffer_ptr[output_stepsize * j + i] = sample_ptr[stepsize * j + offset]; } } } #if defined(AUDIO_STREAMING_DSP) static void Mixer_Main_DSP() { static short premix_first_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE]; static long premix_last_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE]; static byte playing_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE]; boolean stereo; int fragment_size; int sample_bytes; int max_sample_size; int num_output_channels; int i, j; if (!mixer_active_channels) return; if (audio.device_fd < 0) { if ((audio.device_fd = OpenAudioDevice(audio.device_name)) < 0) return; InitAudioDevice(&afmt); } stereo = afmt.stereo; fragment_size = afmt.fragment_size; sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2); num_output_channels = (stereo ? 2 : 1); max_sample_size = fragment_size / (num_output_channels * sample_bytes); /* first clear the last premixing buffer */ clear_mem(premix_last_buffer, max_sample_size * num_output_channels * sizeof(long)); for (i = 0; i < audio.num_channels; i++) { void *sample_ptr; int sample_len; int sample_pos; int sample_size; if (!mixer[i].active) continue; if (Mixer_ChannelExpired(i)) { Mixer_StopChannel(i); continue; } /* pointer, lenght and actual playing position of sound sample */ sample_ptr = mixer[i].data_ptr; sample_len = mixer[i].data_len; sample_pos = mixer[i].playing_pos; sample_size = MIN(max_sample_size, sample_len - sample_pos); mixer[i].playing_pos += sample_size; /* copy original sample to first mixing buffer */ CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size, premix_first_buffer, 0, num_output_channels); /* are we about to restart a looping sound? */ if (IS_LOOP(mixer[i]) && sample_size < max_sample_size) { while (sample_size < max_sample_size) { int restarted_sample_size = MIN(max_sample_size - sample_size, sample_len); CopySampleToMixingBuffer(&mixer[i], 0, restarted_sample_size, premix_first_buffer, sample_size, num_output_channels); mixer[i].playing_pos = restarted_sample_size; sample_size += restarted_sample_size; } } /* decrease volume if sound is fading out */ if (IS_FADING(mixer[i]) && mixer[i].volume >= SOUND_FADING_VOLUME_THRESHOLD) mixer[i].volume -= SOUND_FADING_VOLUME_STEP; /* adjust volume of actual sound sample */ if (mixer[i].volume != SOUND_MAX_VOLUME) for (j = 0; j < sample_size * num_output_channels; j++) premix_first_buffer[j] = mixer[i].volume * (long)premix_first_buffer[j] / SOUND_MAX_VOLUME; /* adjust left and right channel volume due to stereo sound position */ if (stereo) { int left_volume = SOUND_VOLUME_LEFT(mixer[i].stereo_position); int right_volume = SOUND_VOLUME_RIGHT(mixer[i].stereo_position); for (j = 0; j < sample_size; j++) { premix_first_buffer[2 * j + 0] = left_volume * premix_first_buffer[2 * j + 0] / SOUND_MAX_LEFT2RIGHT; premix_first_buffer[2 * j + 1] = right_volume * premix_first_buffer[2 * j + 1] / SOUND_MAX_LEFT2RIGHT; } } /* fill the last mixing buffer with stereo or mono sound */ for (j = 0; j < sample_size * num_output_channels; j++) premix_last_buffer[j] += premix_first_buffer[j]; /* delete completed sound entries from the mixer */ if (mixer[i].playing_pos >= mixer[i].data_len) { if (IS_LOOP(mixer[i])) mixer[i].playing_pos = 0; else Mixer_StopChannel(i); } else if (mixer[i].volume <= SOUND_FADING_VOLUME_THRESHOLD) Mixer_StopChannel(i); } /* prepare final playing buffer according to system audio format */ for (i = 0; i < max_sample_size * num_output_channels; i++) { /* cut off at 17 bit value */ if (premix_last_buffer[i] < -65535) premix_last_buffer[i] = -65535; else if (premix_last_buffer[i] > 65535) premix_last_buffer[i] = 65535; /* shift to 16 bit value */ premix_last_buffer[i] >>= 1; if (afmt.format & AUDIO_FORMAT_U8) { playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80; } else if (afmt.format & AUDIO_FORMAT_LE) /* 16 bit */ { playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff; playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8; } else /* big endian */ { playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8; playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff; } } /* finally play the sound fragment */ write(audio.device_fd, playing_buffer, fragment_size); if (!mixer_active_channels) CloseAudioDevice(&audio.device_fd); } #else /* !AUDIO_STREAMING_DSP */ static int Mixer_Main_SimpleAudio(SoundControl snd_ctrl) { static short premix_first_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE]; static byte playing_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE]; int max_sample_size = DEFAULT_AUDIO_FRAGMENT_SIZE; int num_output_channels = 1; void *sample_ptr; int sample_len; int sample_pos; int sample_size; int i, j; i = 1; /* pointer, lenght and actual playing position of sound sample */ sample_ptr = mixer[i].data_ptr; sample_len = mixer[i].data_len; sample_pos = mixer[i].playing_pos; sample_size = MIN(max_sample_size, sample_len - sample_pos); mixer[i].playing_pos += sample_size; /* copy original sample to first mixing buffer */ CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size, premix_first_buffer, 0, num_output_channels); /* adjust volume of actual sound sample */ if (mixer[i].volume != SOUND_MAX_VOLUME) for (j = 0; j < sample_size; j++) premix_first_buffer[j] = mixer[i].volume * (long)premix_first_buffer[j] / SOUND_MAX_VOLUME; /* might be needed for u-law /dev/audio */ for (j = 0; j < sample_size; j++) playing_buffer[j] = linear_to_ulaw(premix_first_buffer[j]); /* delete completed sound entries from the mixer */ if (mixer[i].playing_pos >= mixer[i].data_len) Mixer_StopChannel(i); for (i = 0; i < sample_size; i++) playing_buffer[i] = (premix_first_buffer[i] >> 8) ^ 0x80; /* finally play the sound fragment */ write(audio.device_fd, playing_buffer, sample_size); return sample_size; } #endif /* !AUDIO_STREAMING_DSP */ void Mixer_Main() { SoundControl snd_ctrl; fd_set mixer_fdset; close(audio.mixer_pipe[1]); /* no writing into pipe needed */ Mixer_InitChannels(); #if defined(PLATFORM_HPUX) InitAudioDevice(&afmt); #endif FD_ZERO(&mixer_fdset); FD_SET(audio.mixer_pipe[0], &mixer_fdset); while (1) /* wait for sound playing commands from client */ { struct timeval delay = { 0, 0 }; FD_SET(audio.mixer_pipe[0], &mixer_fdset); select(audio.mixer_pipe[0] + 1, &mixer_fdset, NULL, NULL, NULL); if (!FD_ISSET(audio.mixer_pipe[0], &mixer_fdset)) continue; ReadSoundControlFromMainProcess(&snd_ctrl); HandleSoundRequest(snd_ctrl); #if defined(AUDIO_STREAMING_DSP) while (mixer_active_channels && select(audio.mixer_pipe[0] + 1, &mixer_fdset, NULL, NULL, &delay) < 1) { FD_SET(audio.mixer_pipe[0], &mixer_fdset); Mixer_Main_DSP(); } #else /* !AUDIO_STREAMING_DSP */ if (!snd_ctrl.active || IS_LOOP(snd_ctrl) || (audio.device_fd = OpenAudioDevice(audio.device_name)) < 0) continue; InitAudioDevice(&afmt); delay.tv_sec = 0; delay.tv_usec = 0; while (mixer_active_channels && select(audio.mixer_pipe[0] + 1, &mixer_fdset, NULL, NULL, &delay) < 1) { int wait_percent = 90; /* wait 90% of the real playing time */ int sample_size; FD_SET(audio.mixer_pipe[0], &mixer_fdset); sample_size = Mixer_Main_SimpleAudio(snd_ctrl); delay.tv_sec = 0; delay.tv_usec = ((sample_size * 10 * wait_percent) / afmt.sample_rate) * 1000; } CloseAudioDevice(&audio.device_fd); Mixer_InitChannels(); /* remove all sounds from mixer */ #endif /* !AUDIO_STREAMING_DSP */ } } #endif /* AUDIO_UNIX_NATIVE */ #if defined(AUDIO_UNIX_NATIVE) && !defined(AUDIO_STREAMING_DSP) /* these two are stolen from "sox"... :) */ /* ** This routine converts from linear to ulaw. ** ** Craig Reese: IDA/Supercomputing Research Center ** Joe Campbell: Department of Defense ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) "A New Digital Technique for Implementation of Any ** Continuous PCM Companding Law," Villeret, Michel, ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, ** 1973, pg. 11.12-11.17 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: Signed 16 bit linear sample ** Output: 8 bit ulaw sample */ #define ZEROTRAP /* turn on the trap as per the MIL-STD */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 static unsigned char linear_to_ulaw(int sample) { static int exp_lut[256] = { 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; int sign, exponent, mantissa; unsigned char ulawbyte; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if (sign != 0) sample = -sample; /* get magnitude */ if (sample > CLIP) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = sample + BIAS; exponent = exp_lut[( sample >> 7 ) & 0xFF]; mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F; ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa ); #ifdef ZEROTRAP if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ #endif return(ulawbyte); } /* ** This routine converts from ulaw to 16 bit linear. ** ** Craig Reese: IDA/Supercomputing Research Center ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: 8 bit ulaw sample ** Output: signed 16 bit linear sample */ static int ulaw_to_linear(unsigned char ulawbyte) { static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; int sign, exponent, mantissa, sample; ulawbyte = ~ ulawbyte; sign = ( ulawbyte & 0x80 ); exponent = ( ulawbyte >> 4 ) & 0x07; mantissa = ulawbyte & 0x0F; sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) ); if (sign != 0) sample = -sample; return(sample); } #endif /* AUDIO_UNIX_NATIVE && !AUDIO_STREAMING_DSP */ /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ /* ========================================================================= */ /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */ #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define WAV_HEADER_SIZE 16 /* size of WAV file header */ static void *Load_WAV(char *filename) { SoundInfo *snd_info; #if defined(AUDIO_UNIX_NATIVE) struct SoundHeader_WAV header; #if 0 byte sound_header_buffer[WAV_HEADER_SIZE]; int i; #endif char chunk_name[CHUNK_ID_LEN + 1]; int chunk_size; int data_byte_len; FILE *file; #endif if (!audio.sound_available) return NULL; snd_info = checked_calloc(sizeof(SoundInfo)); #if defined(TARGET_SDL) if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL) { Error(ERR_WARN, "cannot read sound file '%s'", filename); free(snd_info); return NULL; } snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen; #elif defined(TARGET_ALLEGRO) if ((snd_info->data_ptr = load_sample(filename)) == NULL) { Error(ERR_WARN, "cannot read sound file '%s'", filename); free(snd_info); return NULL; } snd_info->data_len = ((SAMPLE *)snd_info->data_ptr)->len; #else /* AUDIO_UNIX_NATIVE */ clear_mem(&header, sizeof(struct SoundHeader_WAV)); /* to make gcc happy */ if ((file = fopen(filename, MODE_READ)) == NULL) { Error(ERR_WARN, "cannot open sound file '%s'", filename); free(snd_info); return NULL; } /* read chunk id "RIFF" */ getFileChunkLE(file, chunk_name, &chunk_size); if (!strEqual(chunk_name, "RIFF")) { Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename); fclose(file); free(snd_info); return NULL; } /* read "RIFF" type id "WAVE" */ getFileChunkLE(file, chunk_name, NULL); if (!strEqual(chunk_name, "WAVE")) { Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename); fclose(file); free(snd_info); return NULL; } while (getFileChunkLE(file, chunk_name, &chunk_size)) { if (strEqual(chunk_name, "fmt ")) { if (chunk_size < WAV_HEADER_SIZE) { Error(ERR_WARN, "sound file '%s': chunk 'fmt ' too short", filename); fclose(file); free(snd_info); return NULL; } header.compression_code = getFile16BitLE(file); header.num_channels = getFile16BitLE(file); header.sample_rate = getFile32BitLE(file); header.bytes_per_second = getFile32BitLE(file); header.block_align = getFile16BitLE(file); header.bits_per_sample = getFile16BitLE(file); if (chunk_size > WAV_HEADER_SIZE) ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE); if (header.compression_code != 1) { Error(ERR_WARN, "sound file '%s': compression code %d not supported", filename, header.compression_code); fclose(file); free(snd_info); return NULL; } if (header.num_channels != 1 && header.num_channels != 2) { Error(ERR_WARN, "sound file '%s': number of %d channels not supported", filename, header.num_channels); fclose(file); free(snd_info); return NULL; } if (header.bits_per_sample != 8 && header.bits_per_sample != 16) { Error(ERR_WARN, "sound file '%s': %d bits per sample not supported", filename, header.bits_per_sample); fclose(file); free(snd_info); return NULL; } /* warn, but accept wrong sample rate (may be only slightly different) */ if (header.sample_rate != DEFAULT_AUDIO_SAMPLE_RATE) Error(ERR_WARN, "sound file '%s': wrong sample rate %d instead of %d", filename, header.sample_rate, DEFAULT_AUDIO_SAMPLE_RATE); #if 0 printf("WAV file: '%s'\n", filename); printf(" Compression code: %d'\n", header.compression_code); printf(" Number of channels: %d'\n", header.num_channels); printf(" Sample rate: %ld'\n", header.sample_rate); printf(" Average bytes per second: %ld'\n", header.bytes_per_second); printf(" Block align: %d'\n", header.block_align); printf(" Significant bits per sample: %d'\n", header.bits_per_sample); #endif } else if (strEqual(chunk_name, "data")) { data_byte_len = chunk_size; snd_info->data_len = data_byte_len; snd_info->data_ptr = checked_malloc(snd_info->data_len); /* read sound data */ if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) != snd_info->data_len) { Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename); fclose(file); free(snd_info->data_ptr); free(snd_info); return NULL; } /* check for odd number of data bytes (data chunk is word aligned) */ if ((data_byte_len % 2) == 1) ReadUnusedBytesFromFile(file, 1); } else /* unknown chunk -- ignore */ ReadUnusedBytesFromFile(file, chunk_size); } fclose(file); if (snd_info->data_ptr == NULL) { Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename); free(snd_info); return NULL; } if (header.bits_per_sample == 8) snd_info->format = AUDIO_FORMAT_U8; else /* header.bits_per_sample == 16 */ { snd_info->format = AUDIO_FORMAT_S16; snd_info->data_len /= 2; /* correct number of samples */ } snd_info->num_channels = header.num_channels; if (header.num_channels == 2) snd_info->data_len /= 2; /* correct number of samples */ #if 0 if (header.num_channels == 1) /* convert mono sound to stereo */ { void *buffer_ptr = checked_malloc(data_byte_len * 2); void *sample_ptr = snd_info->data_ptr; int sample_size = snd_info->data_len; int i; if (snd_ctrl->format == AUDIO_FORMAT_U8) for (i = 0; i < sample_size; i++) *buffer_ptr++ = ((short)(((byte *)sample_ptr)[i] ^ 0x80)) << 8; else /* AUDIO_FORMAT_S16 */ for (i = 0; i < sample_size; i++) *buffer_ptr++ = ((short *)sample_ptr)[i]; } #endif #endif /* AUDIO_UNIX_NATIVE */ snd_info->type = SND_TYPE_WAV; snd_info->source_filename = getStringCopy(filename); return snd_info; } static void *Load_MOD(char *filename) { #if defined(TARGET_SDL) MusicInfo *mod_info; if (!audio.sound_available) return NULL; mod_info = checked_calloc(sizeof(MusicInfo)); if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL) { Error(ERR_WARN, "cannot read music file '%s'", filename); free(mod_info); return NULL; } mod_info->type = MUS_TYPE_MOD; mod_info->source_filename = getStringCopy(filename); return mod_info; #else return NULL; #endif } static void *Load_WAV_or_MOD(char *filename) { if (FileIsSound(filename)) return Load_WAV(filename); else if (FileIsMusic(filename)) return Load_MOD(filename); else return NULL; } void LoadCustomMusic_NoConf(void) { static boolean draw_init_text = TRUE; /* only draw at startup */ static char *last_music_directory = NULL; char *music_directory = getCustomMusicDirectory(); DIR *dir; struct dirent *dir_entry; int num_music = getMusicListSize(); if (!audio.sound_available) return; if (last_music_directory != NULL && strEqual(last_music_directory, music_directory)) return; /* old and new music directory are the same */ if (last_music_directory != NULL) free(last_music_directory); last_music_directory = getStringCopy(music_directory); FreeAllMusic_NoConf(); if ((dir = opendir(music_directory)) == NULL) { Error(ERR_WARN, "cannot read music directory '%s'", music_directory); audio.music_available = FALSE; return; } if (draw_init_text) DrawInitText("Loading music", 120, FC_GREEN); while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { char *basename = dir_entry->d_name; char *filename = NULL; MusicInfo *mus_info = NULL; boolean music_already_used = FALSE; int i; /* skip all music files that are configured in music config file */ for (i = 0; i < num_music; i++) { struct FileInfo *music = getMusicListEntry(i); if (strEqual(basename, music->filename)) { music_already_used = TRUE; break; } } if (music_already_used) continue; if (draw_init_text) DrawInitText(basename, 150, FC_YELLOW); filename = getPath2(music_directory, basename); if (FileIsMusic(basename)) mus_info = Load_WAV_or_MOD(filename); free(filename); if (mus_info) { num_music_noconf++; Music_NoConf = checked_realloc(Music_NoConf, num_music_noconf * sizeof(MusicInfo *)); Music_NoConf[num_music_noconf - 1] = mus_info; } } closedir(dir); draw_init_text = FALSE; } int getSoundListSize() { return (sound_info->num_file_list_entries + sound_info->num_dynamic_file_list_entries); } int getMusicListSize() { return (music_info->num_file_list_entries + music_info->num_dynamic_file_list_entries); } struct FileInfo *getSoundListEntry(int pos) { int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); return (pos < num_list_entries ? &sound_info->file_list[list_pos] : &sound_info->dynamic_file_list[list_pos]); } struct FileInfo *getMusicListEntry(int pos) { int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); return (pos < num_list_entries ? &music_info->file_list[list_pos] : &music_info->dynamic_file_list[list_pos]); } static SoundInfo *getSoundInfoEntryFromSoundID(int pos) { int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); SoundInfo **snd_info = (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list : sound_info->dynamic_artwork_list); return snd_info[list_pos]; } static MusicInfo *getMusicInfoEntryFromMusicID(int pos) { int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); MusicInfo **mus_info = (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list : music_info->dynamic_artwork_list); return mus_info[list_pos]; } int getSoundListPropertyMappingSize() { return sound_info->num_property_mapping_entries; } int getMusicListPropertyMappingSize() { return music_info->num_property_mapping_entries; } struct PropertyMapping *getSoundListPropertyMapping() { return sound_info->property_mapping; } struct PropertyMapping *getMusicListPropertyMapping() { return music_info->property_mapping; } void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; sound_info = checked_calloc(sizeof(struct ArtworkListInfo)); sound_info->type = ARTWORK_TYPE_SOUNDS; /* ---------- initialize file list and suffix lists ---------- */ sound_info->num_file_list_entries = num_file_list_entries; sound_info->num_dynamic_file_list_entries = 0; sound_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); sound_info->dynamic_file_list = NULL; sound_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) sound_info->num_suffix_list_entries++; sound_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ sound_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) sound_info->num_base_prefixes++; sound_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) sound_info->num_ext1_suffixes++; sound_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) sound_info->num_ext2_suffixes++; sound_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) sound_info->num_ext3_suffixes++; sound_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) sound_info->num_ignore_tokens++; sound_info->base_prefixes = base_prefixes; sound_info->ext1_suffixes = ext1_suffixes; sound_info->ext2_suffixes = ext2_suffixes; sound_info->ext3_suffixes = ext3_suffixes; sound_info->ignore_tokens = ignore_tokens; sound_info->num_property_mapping_entries = 0; sound_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *); sound_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(SoundInfo *)); sound_info->dynamic_artwork_list = NULL; sound_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ sound_info->load_artwork = Load_WAV; sound_info->free_artwork = FreeSound; } void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; music_info = checked_calloc(sizeof(struct ArtworkListInfo)); music_info->type = ARTWORK_TYPE_MUSIC; /* ---------- initialize file list and suffix lists ---------- */ music_info->num_file_list_entries = num_file_list_entries; music_info->num_dynamic_file_list_entries = 0; music_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); music_info->dynamic_file_list = NULL; music_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) music_info->num_suffix_list_entries++; music_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ music_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) music_info->num_base_prefixes++; music_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) music_info->num_ext1_suffixes++; music_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) music_info->num_ext2_suffixes++; music_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) music_info->num_ext3_suffixes++; music_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) music_info->num_ignore_tokens++; music_info->base_prefixes = base_prefixes; music_info->ext1_suffixes = ext1_suffixes; music_info->ext2_suffixes = ext2_suffixes; music_info->ext3_suffixes = ext3_suffixes; music_info->ignore_tokens = ignore_tokens; music_info->num_property_mapping_entries = 0; music_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *); music_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(MusicInfo *)); music_info->dynamic_artwork_list = NULL; music_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ music_info->load_artwork = Load_WAV_or_MOD; music_info->free_artwork = FreeMusic; } void PlayMusic(int nr) { if (!audio.music_available) return; PlaySoundMusic(nr); } void PlaySound(int nr) { PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND); } void PlaySoundStereo(int nr, int stereo_position) { PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND); } void PlaySoundLoop(int nr) { PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP); } void PlaySoundMusic(int nr) { PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC); } void PlaySoundExt(int nr, int volume, int stereo_position, int state) { SoundControl snd_ctrl; if (!audio.sound_available || !audio.sound_enabled || audio.sound_deactivated) return; if (volume < SOUND_MIN_VOLUME) volume = SOUND_MIN_VOLUME; else if (volume > SOUND_MAX_VOLUME) volume = SOUND_MAX_VOLUME; if (stereo_position < SOUND_MAX_LEFT) stereo_position = SOUND_MAX_LEFT; else if (stereo_position > SOUND_MAX_RIGHT) stereo_position = SOUND_MAX_RIGHT; clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = TRUE; snd_ctrl.nr = nr; snd_ctrl.volume = volume; snd_ctrl.stereo_position = stereo_position; snd_ctrl.state = state; HandleSoundRequest(snd_ctrl); } void FadeMusic(void) { if (!audio.music_available) return; StopSoundExt(-1, SND_CTRL_FADE_MUSIC); } void FadeSound(int nr) { StopSoundExt(nr, SND_CTRL_FADE_SOUND); } void FadeSounds() { StopSoundExt(-1, SND_CTRL_FADE_ALL); } void FadeSoundsAndMusic() { FadeSounds(); FadeMusic(); } void StopMusic(void) { if (!audio.music_available) return; StopSoundExt(-1, SND_CTRL_STOP_MUSIC); } void StopSound(int nr) { StopSoundExt(nr, SND_CTRL_STOP_SOUND); } void StopSounds() { StopMusic(); StopSoundExt(-1, SND_CTRL_STOP_ALL); } void StopSoundExt(int nr, int state) { SoundControl snd_ctrl; if (!audio.sound_available) return; clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = FALSE; snd_ctrl.nr = nr; snd_ctrl.state = state; HandleSoundRequest(snd_ctrl); } static void ReloadCustomSounds() { #if 0 printf("::: reloading sounds '%s' ...\n", artwork.snd_current_identifier); #endif LoadArtworkConfig(sound_info); ReloadCustomArtworkList(sound_info); } static void ReloadCustomMusic() { #if 0 printf("::: reloading music '%s' ...\n", artwork.mus_current_identifier); #endif LoadArtworkConfig(music_info); ReloadCustomArtworkList(music_info); /* load all music files from directory not defined in "musicinfo.conf" */ LoadCustomMusic_NoConf(); } void InitReloadCustomSounds(char *set_identifier) { if (!audio.sound_available) return; #if defined(AUDIO_UNIX_NATIVE) LoadArtworkConfig(sound_info); /* also load config on sound client */ WriteReloadInfoToPipe(set_identifier, SND_CTRL_RELOAD_SOUNDS); #else ReloadCustomSounds(); #endif } void InitReloadCustomMusic(char *set_identifier) { if (!audio.music_available) return; #if defined(AUDIO_UNIX_NATIVE) LoadArtworkConfig(music_info); /* also load config on sound client */ WriteReloadInfoToPipe(set_identifier, SND_CTRL_RELOAD_MUSIC); #else ReloadCustomMusic(); #endif } void FreeSound(void *ptr) { SoundInfo *sound = (SoundInfo *)ptr; if (sound == NULL) return; if (sound->data_ptr) { #if defined(TARGET_SDL) Mix_FreeChunk(sound->data_ptr); #elif defined(TARGET_ALLEGRO) destroy_sample(sound->data_ptr); #else /* AUDIO_UNIX_NATIVE */ free(sound->data_ptr); #endif } checked_free(sound->source_filename); free(sound); } void FreeMusic(void *ptr) { MusicInfo *music = (MusicInfo *)ptr; if (music == NULL) return; if (music->data_ptr) { #if defined(TARGET_SDL) if (music->type == MUS_TYPE_MOD) Mix_FreeMusic(music->data_ptr); else Mix_FreeChunk(music->data_ptr); #elif defined(TARGET_ALLEGRO) destroy_sample(music->data_ptr); #else /* AUDIO_UNIX_NATIVE */ free(music->data_ptr); #endif } free(music); } static void FreeAllMusic_NoConf() { int i; if (Music_NoConf == NULL) return; for (i = 0; i < num_music_noconf; i++) FreeMusic(Music_NoConf[i]); free(Music_NoConf); Music_NoConf = NULL; num_music_noconf = 0; } void FreeAllSounds() { FreeCustomArtworkLists(sound_info); } void FreeAllMusic() { FreeCustomArtworkLists(music_info); FreeAllMusic_NoConf(); } /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */ /* ========================================================================= */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/hash.c0000644000175000017500000002431710613746521020120 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * hash.c * ***********************************************************/ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software and its documentation and acknowledgment shall be * given in the documentation and software packages that this Software was * used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "hash.h" /*****************************************************************************/ struct hashtable * create_hashtable(unsigned int minsize, float maxloadfactor, unsigned int (*hashf) (void*), int (*eqf) (void*,void*)) { struct hashtable *h; unsigned int i, size = 1u; /* Check requested hashtable isn't too large */ if (minsize > (1u << 31)) return NULL; /* Enforce size as power of 2 */ while (size < minsize) size <<= 1; h = (struct hashtable *)malloc(sizeof(struct hashtable)); if (h == NULL) return NULL; h->table = (struct entry **)malloc(sizeof(struct entry*) * size); if (h->table == NULL) { free(h); return NULL; } for (i=0; i < size; i++) h->table[i] = NULL; h->tablelength = size; h->entrycount = 0; h->hashfn = hashf; h->eqfn = eqf; h->loadlimit = (unsigned int) ((float)size * maxloadfactor); return h; } /*****************************************************************************/ static unsigned int hash(struct hashtable *h, void *k) { /* Aim to protect against poor hash functions by adding logic here * - logic taken from java 1.4 hashtable source */ unsigned int i = h->hashfn(k); i += ~(i << 9); i ^= ((i >> 14) | (i << 18)); /* >>> */ i += (i << 4); i ^= ((i >> 10) | (i << 22)); /* >>> */ return i; } /*****************************************************************************/ static unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { /* Only works if tablelength == 2^N */ return (hashvalue & (tablelength - 1u)); } /*****************************************************************************/ static int hashtable_expand(struct hashtable *h) { /* Double the size of the table to accomodate more entries */ struct entry **newtable; struct entry *e; struct entry **pE; unsigned int newsize, i, index; /* Check we're not hitting max capacity */ if (0 == (newsize = (h->tablelength << 1))) return 0; newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); if (newtable != NULL) { memset(newtable, 0, newsize * sizeof(struct entry *)); /* This algorithm is not 'stable'. ie. it reverses the list * when it transfers entries between the tables */ for (i = 0; i < h->tablelength; i++) { while ((e = h->table[i]) != NULL) { h->table[i] = e->next; index = indexFor(newsize,e->h); e->next = newtable[index]; newtable[index] = e; } } free(h->table); h->table = newtable; } else /* Plan B: realloc instead */ { newtable = (struct entry **) realloc(h->table, newsize * sizeof(struct entry *)); if (newtable == NULL) return 0; h->table = newtable; for (i = h->tablelength; i < newsize; i++) newtable[i] = NULL; for (i = 0; i < h->tablelength; i++) { for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { index = indexFor(newsize,e->h); if (index == i) { pE = &(e->next); } else { *pE = e->next; e->next = newtable[index]; newtable[index] = e; } } } } h->tablelength = newsize; h->loadlimit <<= 1; return -1; } /*****************************************************************************/ unsigned int hashtable_count(struct hashtable *h) { return h->entrycount; } /*****************************************************************************/ int hashtable_insert(struct hashtable *h, void *k, void *v) { /* This method allows duplicate keys - but they shouldn't be used */ unsigned int index; struct entry *e; if (++(h->entrycount) > h->loadlimit) { /* Ignore the return value. If expand fails, we should * still try cramming just this value into the existing table * -- we may not have memory for a larger table, but one more * element may be ok. Next time we insert, we'll try expanding again.*/ hashtable_expand(h); } e = (struct entry *)malloc(sizeof(struct entry)); if (e == NULL) { --(h->entrycount); return 0; } e->h = hash(h,k); index = indexFor(h->tablelength,e->h); e->k = k; e->v = v; e->next = h->table[index]; h->table[index] = e; return -1; } /*****************************************************************************/ int hashtable_change(struct hashtable *h, void *k, void *v) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (e != NULL) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { free(e->v); e->v = v; return -1; } e = e->next; } return 0; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_search(struct hashtable *h, void *k) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (e != NULL) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; e = e->next; } return NULL; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_remove(struct hashtable *h, void *k) { /* TODO: consider compacting the table when the load factor drops enough, * or provide a 'compact' method. */ struct entry *e; struct entry **pE; void *v; unsigned int index = indexFor(h->tablelength,hash(h,k)); pE = &(h->table[index]); e = *pE; while (e != NULL) { if (h->eqfn(k, e->k)) { *pE = e->next; h->entrycount--; v = e->v; free(e->k); free(e); return v; } pE = &(e->next); e = e->next; } return NULL; } /*****************************************************************************/ /* destroy */ void hashtable_destroy(struct hashtable *h, int free_values) { unsigned int i; struct entry *e, *f; struct entry **table = h->table; for (i = 0; i < h->tablelength; i++) { e = table[i]; while (e != NULL) { f = e; e = e->next; free(f->k); if (free_values) free(f->v); free(f); } } free(h->table); free(h); } /*****************************************************************************/ /* hashtable_iterator - iterator constructor */ struct hashtable_itr * hashtable_iterator(struct hashtable *h) { unsigned int i, tablelength; struct hashtable_itr *itr = (struct hashtable_itr *) malloc(sizeof(struct hashtable_itr)); if (itr == NULL) return NULL; itr->h = h; itr->e = NULL; tablelength = h->tablelength; itr->index = tablelength; if (0 == h->entrycount) return itr; for (i = 0; i < tablelength; i++) { if (h->table[i] != NULL) { itr->e = h->table[i]; itr->index = i; break; } } return itr; } /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i) { return i->e->k; } /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_value(struct hashtable_itr *i) { return i->e->v; } /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr) { unsigned int j,tablelength; struct entry **table; struct entry *next; if (itr->e == NULL) return 0; /* stupidity check */ next = itr->e->next; if (next != NULL) { itr->e = next; return -1; } tablelength = itr->h->tablelength; if (tablelength <= (j = ++(itr->index))) { itr->e = NULL; return 0; } table = itr->h->table; while ((next = table[j]) == NULL) { if (++j >= tablelength) { itr->index = tablelength; return 0; } } itr->index = j; itr->e = next; return -1; } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/system.c0000644000175000017500000012672011363425522020520 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * system.c * ***********************************************************/ #include #include #include "platform.h" #if defined(PLATFORM_MSDOS) #include #endif #include "system.h" #include "image.h" #include "sound.h" #include "setup.h" #include "joystick.h" #include "misc.h" /* ========================================================================= */ /* exported variables */ /* ========================================================================= */ struct ProgramInfo program; struct OptionInfo options; struct VideoSystemInfo video; struct AudioSystemInfo audio; struct GfxInfo gfx; struct ArtworkInfo artwork; struct JoystickInfo joystick; struct SetupInfo setup; LevelDirTree *leveldir_first_all = NULL; LevelDirTree *leveldir_first = NULL; LevelDirTree *leveldir_current = NULL; int level_nr; Display *display = NULL; Visual *visual = NULL; int screen = 0; Colormap cmap = None; DrawWindow *window = NULL; DrawBuffer *backbuffer = NULL; DrawBuffer *drawto = NULL; int button_status = MB_NOT_PRESSED; boolean motion_status = FALSE; int redraw_mask = REDRAW_NONE; int redraw_tiles = 0; int FrameCounter = 0; /* ========================================================================= */ /* init/close functions */ /* ========================================================================= */ void InitProgramInfo(char *argv0, char *userdata_subdir, char *userdata_subdir_unix, char *program_title, char *window_title, char *icon_title, char *x11_icon_filename, char *x11_iconmask_filename, char *sdl_icon_filename, char *msdos_cursor_filename, char *cookie_prefix, char *filename_prefix, int program_version) { program.command_basepath = getBasePath(argv0); program.command_basename = getBaseName(argv0); program.userdata_subdir = userdata_subdir; program.userdata_subdir_unix = userdata_subdir_unix; program.userdata_path = getUserGameDataDir(); program.program_title = program_title; program.window_title = window_title; program.icon_title = icon_title; program.x11_icon_filename = x11_icon_filename; program.x11_iconmask_filename = x11_iconmask_filename; program.sdl_icon_filename = sdl_icon_filename; program.msdos_cursor_filename = msdos_cursor_filename; program.cookie_prefix = cookie_prefix; program.filename_prefix = filename_prefix; program.version_major = VERSION_MAJOR(program_version); program.version_minor = VERSION_MINOR(program_version); program.version_patch = VERSION_PATCH(program_version); program.error_filename = getErrorFilename(ERROR_BASENAME); program.error_file = stderr; } void InitExitFunction(void (*exit_function)(int)) { program.exit_function = exit_function; /* set signal handlers to custom exit function */ signal(SIGINT, exit_function); signal(SIGTERM, exit_function); #if defined(TARGET_SDL) /* set exit function to automatically cleanup SDL stuff after exit() */ atexit(SDL_Quit); #endif } void InitPlatformDependentStuff(void) { #if defined(PLATFORM_MSDOS) _fmode = O_BINARY; #endif #if defined(PLATFORM_MACOSX) updateUserGameDataDir(); #endif #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX) openErrorFile(); #endif #if defined(TARGET_SDL) if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0) Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError()); SDLNet_Init(); #endif } void ClosePlatformDependentStuff(void) { #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS) closeErrorFile(); #endif #if defined(PLATFORM_MSDOS) dumpErrorFile(); #endif } void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize, int real_sx, int real_sy, int full_sxsize, int full_sysize, Bitmap *field_save_buffer) { gfx.sx = sx; gfx.sy = sy; gfx.sxsize = sxsize; gfx.sysize = sysize; gfx.real_sx = real_sx; gfx.real_sy = real_sy; gfx.full_sxsize = full_sxsize; gfx.full_sysize = full_sysize; gfx.field_save_buffer = field_save_buffer; #if 0 gfx.background_bitmap = NULL; gfx.background_bitmap_mask = REDRAW_NONE; #endif SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */ SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */ } void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize) { gfx.dx = dx; gfx.dy = dy; gfx.dxsize = dxsize; gfx.dysize = dysize; } void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize) { gfx.vx = vx; gfx.vy = vy; gfx.vxsize = vxsize; gfx.vysize = vysize; } void InitGfxWindowInfo(int win_xsize, int win_ysize) { gfx.win_xsize = win_xsize; gfx.win_ysize = win_ysize; #if 1 gfx.background_bitmap_mask = REDRAW_NONE; ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH); #endif } void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height) { /* currently only used by MSDOS code to alloc VRAM buffer, if available */ /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */ gfx.scrollbuffer_width = scrollbuffer_width; gfx.scrollbuffer_height = scrollbuffer_height; } void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height) { gfx.clipping_enabled = enabled; gfx.clip_x = x; gfx.clip_y = y; gfx.clip_width = width; gfx.clip_height = height; } void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)) { gfx.draw_busy_anim_function = draw_busy_anim_function; } void InitGfxCustomArtworkInfo() { gfx.override_level_graphics = FALSE; gfx.override_level_sounds = FALSE; gfx.override_level_music = FALSE; gfx.draw_init_text = TRUE; } void SetDrawDeactivationMask(int draw_deactivation_mask) { gfx.draw_deactivation_mask = draw_deactivation_mask; } void SetDrawBackgroundMask(int draw_background_mask) { gfx.draw_background_mask = draw_background_mask; } static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile, int dest_x, int dest_y, int width, int height) { int bitmap_xsize = width; int bitmap_ysize = height; int tile_xsize = tile->width; int tile_ysize = tile->height; int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize; int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize; int x, y; for (y = 0; y < tile_ysteps; y++) { for (x = 0; x < tile_xsteps; x++) { int draw_x = dest_x + x * tile_xsize; int draw_y = dest_y + y * tile_ysize; int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize); int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize); BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y); } } } void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask) { if (background_bitmap_tile != NULL) gfx.background_bitmap_mask |= mask; else gfx.background_bitmap_mask &= ~mask; #if 0 if (gfx.background_bitmap == NULL) gfx.background_bitmap = CreateBitmap(video.width, video.height, DEFAULT_DEPTH); #endif if (background_bitmap_tile == NULL) /* empty background requested */ return; if (mask == REDRAW_ALL) DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, 0, 0, video.width, video.height); else if (mask == REDRAW_FIELD) DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize); else if (mask == REDRAW_DOOR_1) { DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize); } } void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove every mask before setting mask for window */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL); } void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for main area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD); } void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for door area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1); } /* ========================================================================= */ /* video functions */ /* ========================================================================= */ inline static int GetRealDepth(int depth) { return (depth == DEFAULT_DEPTH ? video.default_depth : depth); } inline static void sysFillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { #if defined(TARGET_SDL) SDLFillRectangle(bitmap, x, y, width, height, color); #else X11FillRectangle(bitmap, x, y, width, height, color); #endif } inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { #if defined(TARGET_SDL) SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, mask_mode); #else X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, mask_mode); #endif } void InitVideoDisplay(void) { #if defined(TARGET_SDL) SDLInitVideoDisplay(); #else X11InitVideoDisplay(); #endif } void CloseVideoDisplay(void) { KeyboardAutoRepeatOn(); #if defined(TARGET_SDL) SDL_QuitSubSystem(SDL_INIT_VIDEO); #else if (display) XCloseDisplay(display); #endif } void InitVideoBuffer(int width, int height, int depth, boolean fullscreen) { video.width = width; video.height = height; video.depth = GetRealDepth(depth); video.fullscreen_available = FULLSCREEN_STATUS; video.fullscreen_enabled = FALSE; #if 0 video.fullscreen_mode_current = NULL; video.fullscreen_modes = NULL; #endif #if defined(TARGET_SDL) SDLInitVideoBuffer(&backbuffer, &window, fullscreen); #else X11InitVideoBuffer(&backbuffer, &window); #endif drawto = backbuffer; } inline static void FreeBitmapPointers(Bitmap *bitmap) { if (bitmap == NULL) return; #if defined(TARGET_SDL) SDLFreeBitmapPointers(bitmap); #else X11FreeBitmapPointers(bitmap); #endif checked_free(bitmap->source_filename); bitmap->source_filename = NULL; } inline static void TransferBitmapPointers(Bitmap *src_bitmap, Bitmap *dst_bitmap) { if (src_bitmap == NULL || dst_bitmap == NULL) return; FreeBitmapPointers(dst_bitmap); *dst_bitmap = *src_bitmap; } void FreeBitmap(Bitmap *bitmap) { if (bitmap == NULL) return; FreeBitmapPointers(bitmap); free(bitmap); } Bitmap *CreateBitmapStruct(void) { #if defined(TARGET_SDL) return checked_calloc(sizeof(struct SDLSurfaceInfo)); #else return checked_calloc(sizeof(struct X11DrawableInfo)); #endif } Bitmap *CreateBitmap(int width, int height, int depth) { Bitmap *new_bitmap = CreateBitmapStruct(); int real_width = MAX(1, width); /* prevent zero bitmap width */ int real_height = MAX(1, height); /* prevent zero bitmap height */ int real_depth = GetRealDepth(depth); #if defined(TARGET_SDL) SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth); #else X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth); #endif new_bitmap->width = real_width; new_bitmap->height = real_height; return new_bitmap; } void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth) { Bitmap *new_bitmap = CreateBitmap(width, height, depth); if (*bitmap == NULL) { *bitmap = new_bitmap; } else { TransferBitmapPointers(new_bitmap, *bitmap); free(new_bitmap); } } void CloseWindow(DrawWindow *window) { #if defined(TARGET_X11) X11CloseWindow(window); #endif } inline static boolean CheckDrawingArea(int x, int y, int width, int height, int draw_mask) { if (draw_mask == REDRAW_NONE) return FALSE; if (draw_mask & REDRAW_ALL) return TRUE; if ((draw_mask & REDRAW_FIELD) && x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize) return TRUE; if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize) return TRUE; if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy) return TRUE; return FALSE; } boolean DrawingDeactivated(int x, int y, int width, int height) { return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask); } boolean DrawingOnBackground(int x, int y) { return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) && CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask)); } static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y, int *width, int *height, boolean is_dest) { #if 1 int clip_x, clip_y, clip_width, clip_height; if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */ { clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width); clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height); clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x); clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y); } else { clip_x = 0; clip_y = 0; clip_width = bitmap->width; clip_height = bitmap->height; } /* skip if rectangle completely outside bitmap */ if (*x + *width <= clip_x || *y + *height <= clip_y || *x >= clip_x + clip_width || *y >= clip_y + clip_height) return FALSE; /* clip if rectangle overlaps bitmap */ if (*x < clip_x) { *width -= clip_x - *x; *x = clip_x; } else if (*x + *width > clip_x + clip_width) { *width = clip_x + clip_width - *x; } if (*y < clip_y) { *height -= clip_y - *y; *y = clip_y; } else if (*y + *height > clip_y + clip_height) { *height = clip_y + clip_height - *y; } return TRUE; #else /* skip if rectangle completely outside bitmap */ if (*x + *width <= 0 || *y + *height <= 0 || *x >= bitmap->width || *y >= bitmap->height) return FALSE; /* clip if rectangle overlaps bitmap */ if (*x < 0) { *width += *x; *x = 0; } else if (*x + *width > bitmap->width) { *width = bitmap->width - *x; } if (*y < 0) { *height += *y; *y = 0; } else if (*y + *height > bitmap->height) { *height = bitmap->height - *y; } return TRUE; #endif } void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { int dst_x_unclipped = dst_x; int dst_y_unclipped = dst_y; if (DrawingDeactivated(dst_x, dst_y, width, height)) return; #if 1 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) || !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE)) return; /* source x/y might need adjustment if destination x/y was clipped top/left */ src_x += dst_x - dst_x_unclipped; src_y += dst_y - dst_y_unclipped; #else /* skip if rectangle starts outside bitmap */ if (src_x >= src_bitmap->width || src_y >= src_bitmap->height || dst_x >= dst_bitmap->width || dst_y >= dst_bitmap->height) return; /* clip if rectangle overlaps bitmap */ if (src_x + width > src_bitmap->width) width = src_bitmap->width - src_x; if (src_y + height > src_bitmap->height) height = src_bitmap->height - src_y; if (dst_x + width > dst_bitmap->width) width = dst_bitmap->width - dst_x; if (dst_y + height > dst_bitmap->height) height = dst_bitmap->height - dst_y; #endif #if 0 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */ /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13, but is already fixed in SVN and should therefore finally be fixed with the next official SDL release, which is probably version 1.2.14.) */ #if 1 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */ #if defined(TARGET_SDL) && defined(PLATFORM_WIN32) if (src_bitmap == dst_bitmap) { /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */ /* needed when blitting directly to same bitmap -- should not be needed with recent SDL libraries, but apparently does not work in 1.2.11 directly */ static Bitmap *tmp_bitmap = NULL; static int tmp_bitmap_xsize = 0; static int tmp_bitmap_ysize = 0; /* start with largest static bitmaps for initial bitmap size ... */ if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0) { tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width); tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height); } /* ... and allow for later re-adjustments due to custom artwork bitmaps */ if (src_bitmap->width > tmp_bitmap_xsize || src_bitmap->height > tmp_bitmap_ysize) { tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width); tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height); FreeBitmap(tmp_bitmap); tmp_bitmap = NULL; } if (tmp_bitmap == NULL) tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize, DEFAULT_DEPTH); sysCopyArea(src_bitmap, tmp_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); sysCopyArea(tmp_bitmap, dst_bitmap, dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE); return; } #endif #endif #endif sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); } void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { #if 1 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */ if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE)) return; #endif #if defined(TARGET_SDL) SDLFadeRectangle(bitmap_cross, x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); #else X11FadeRectangle(bitmap_cross, x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); #endif } void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { if (DrawingDeactivated(x, y, width, height)) return; #if 1 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE)) return; #else /* skip if rectangle starts outside bitmap */ if (x >= bitmap->width || y >= bitmap->height) return; /* clip if rectangle overlaps bitmap */ if (x + width > bitmap->width) width = bitmap->width - x; if (y + height > bitmap->height) height = bitmap->height - y; #endif sysFillRectangle(bitmap, x, y, width, height, color); } void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height) { FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL); } void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y, int width, int height) { if (DrawingOnBackground(x, y)) BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y); else ClearRectangle(bitmap, x, y, width, height); } void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap) { #if defined(TARGET_X11) if (clip_gc) { bitmap->clip_gc = clip_gc; XSetClipMask(display, bitmap->clip_gc, clip_pixmap); } #endif } void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y) { #if defined(TARGET_X11) if (clip_gc) { bitmap->clip_gc = clip_gc; XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y); } #endif } void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingDeactivated(dst_x, dst_y, width, height)) return; sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_MASKED); } void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingOnBackground(dst_x, dst_y)) { /* draw background */ BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height, dst_x, dst_y); /* draw foreground */ SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { #if defined(TARGET_SDL) SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL); #else X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL); #endif } void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { #if defined(TARGET_SDL) SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL); #else X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL); #endif } #if !defined(TARGET_X11_NATIVE) void DrawLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y, Pixel pixel, int line_width) { int x, y; for (x = 0; x < line_width; x++) { for (y = 0; y < line_width; y++) { int dx = x - line_width / 2; int dy = y - line_width / 2; if ((x == 0 && y == 0) || (x == 0 && y == line_width - 1) || (x == line_width - 1 && y == 0) || (x == line_width - 1 && y == line_width - 1)) continue; #if defined(TARGET_SDL) SDLDrawLine(bitmap, from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel); #elif defined(TARGET_ALLEGRO) AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel); #endif } } } #endif void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel) { #if !defined(TARGET_X11_NATIVE) int line_width = 4; int i; for (i = 0; i < num_points - 1; i++) DrawLine(bitmap, points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, pixel, line_width); /* SDLDrawLines(bitmap->surface, points, num_points, pixel); */ #else XSetForeground(display, bitmap->line_gc[1], pixel); XDrawLines(display, bitmap->drawable, bitmap->line_gc[1], (XPoint *)points, num_points, CoordModeOrigin); #endif } Pixel GetPixel(Bitmap *bitmap, int x, int y) { if (x < 0 || x >= bitmap->width || y < 0 || y >= bitmap->height) return BLACK_PIXEL; #if defined(TARGET_SDL) return SDLGetPixel(bitmap, x, y); #elif defined(TARGET_ALLEGRO) return AllegroGetPixel(bitmap->drawable, x, y); #else return X11GetPixel(bitmap, x, y); #endif } Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r, unsigned int color_g, unsigned int color_b) { #if defined(TARGET_SDL) return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b); #elif defined(TARGET_ALLEGRO) return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8); #else return X11GetPixelFromRGB(color_r, color_g, color_b); #endif } Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color) { unsigned int color_r = (color >> 16) & 0xff; unsigned int color_g = (color >> 8) & 0xff; unsigned int color_b = (color >> 0) & 0xff; return GetPixelFromRGB(bitmap, color_r, color_g, color_b); } /* execute all pending screen drawing operations */ void FlushDisplay(void) { #ifndef TARGET_SDL XFlush(display); #endif } /* execute and wait for all pending screen drawing operations */ void SyncDisplay(void) { #ifndef TARGET_SDL XSync(display, FALSE); #endif } void KeyboardAutoRepeatOn(void) { #if defined(TARGET_SDL) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2, SDL_DEFAULT_REPEAT_INTERVAL / 2); SDL_EnableUNICODE(1); #else if (display) XAutoRepeatOn(display); #endif } void KeyboardAutoRepeatOff(void) { #if defined(TARGET_SDL) SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); SDL_EnableUNICODE(0); #else if (display) XAutoRepeatOff(display); #endif } boolean PointerInWindow(DrawWindow *window) { #if defined(TARGET_SDL) return TRUE; #else Window root, child; int root_x, root_y; unsigned int mask; int win_x, win_y; /* if XQueryPointer() returns False, the pointer is not on the same screen as the specified window */ return XQueryPointer(display, window->drawable, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask); #endif } boolean SetVideoMode(boolean fullscreen) { #if defined(TARGET_SDL) return SDLSetVideoMode(&backbuffer, fullscreen); #else boolean success = TRUE; if (fullscreen && video.fullscreen_available) { Error(ERR_WARN, "fullscreen not available in X11 version"); /* display error message only once */ video.fullscreen_available = FALSE; success = FALSE; } return success; #endif } boolean ChangeVideoModeIfNeeded(boolean fullscreen) { #if defined(TARGET_SDL) if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)|| (!fullscreen && video.fullscreen_enabled)) fullscreen = SetVideoMode(fullscreen); #endif return fullscreen; } Bitmap *LoadImage(char *filename) { Bitmap *new_bitmap; #if defined(TARGET_SDL) new_bitmap = SDLLoadImage(filename); #else new_bitmap = X11LoadImage(filename); #endif if (new_bitmap) new_bitmap->source_filename = getStringCopy(filename); return new_bitmap; } Bitmap *LoadCustomImage(char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename); if ((new_bitmap = LoadImage(filename)) == NULL) Error(ERR_EXIT, "LoadImage() failed: %s", GetError()); return new_bitmap; } void ReloadCustomImage(Bitmap *bitmap, char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) /* (should never happen) */ { Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename); return; } if (strEqual(filename, bitmap->source_filename)) { /* The old and new image are the same (have the same filename and path). This usually means that this image does not exist in this graphic set and a fallback to the existing image is done. */ return; } if ((new_bitmap = LoadImage(filename)) == NULL) { Error(ERR_WARN, "LoadImage() failed: %s", GetError()); return; } if (bitmap->width != new_bitmap->width || bitmap->height != new_bitmap->height) { Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions", filename); FreeBitmap(new_bitmap); return; } TransferBitmapPointers(new_bitmap, bitmap); free(new_bitmap); } Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height) { Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH); #if defined(TARGET_SDL) SDLZoomBitmap(src_bitmap, dst_bitmap); #else X11ZoomBitmap(src_bitmap, dst_bitmap); #endif return dst_bitmap; } static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor, boolean create_small_bitmaps) { Bitmap swap_bitmap; Bitmap *new_bitmap; Bitmap *tmp_bitmap_1; Bitmap *tmp_bitmap_2; Bitmap *tmp_bitmap_4; Bitmap *tmp_bitmap_8; Bitmap *tmp_bitmap_16; Bitmap *tmp_bitmap_32; int width_1, height_1; int width_2, height_2; int width_4, height_4; int width_8, height_8; int width_16, height_16; int width_32, height_32; int new_width, new_height; /* calculate new image dimensions for normal sized image */ width_1 = old_bitmap->width * zoom_factor; height_1 = old_bitmap->height * zoom_factor; /* get image with normal size (this might require scaling up) */ if (zoom_factor != 1) tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1); else tmp_bitmap_1 = old_bitmap; /* this is only needed to make compilers happy */ tmp_bitmap_2 = NULL; tmp_bitmap_4 = NULL; tmp_bitmap_8 = NULL; tmp_bitmap_16 = NULL; tmp_bitmap_32 = NULL; if (create_small_bitmaps) { /* calculate new image dimensions for small images */ width_2 = width_1 / 2; height_2 = height_1 / 2; width_4 = width_1 / 4; height_4 = height_1 / 4; width_8 = width_1 / 8; height_8 = height_1 / 8; width_16 = width_1 / 16; height_16 = height_1 / 16; width_32 = width_1 / 32; height_32 = height_1 / 32; UPDATE_BUSY_STATE(); /* get image with 1/2 of normal size (for use in the level editor) */ if (zoom_factor != 2) tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2); else tmp_bitmap_2 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/4 of normal size (for use in the level editor) */ if (zoom_factor != 4) tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2); else tmp_bitmap_4 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/8 of normal size (for use on the preview screen) */ if (zoom_factor != 8) tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2); else tmp_bitmap_8 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/16 of normal size (for use on the preview screen) */ if (zoom_factor != 16) tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2); else tmp_bitmap_16 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/32 of normal size (for use on the preview screen) */ if (zoom_factor != 32) tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2); else tmp_bitmap_32 = old_bitmap; UPDATE_BUSY_STATE(); } #if 0 /* if image was scaled up, create new clipmask for normal size image */ if (zoom_factor != 1) { #if defined(TARGET_X11) if (old_bitmap->clip_mask) XFreePixmap(display, old_bitmap->clip_mask); old_bitmap->clip_mask = Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1); XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask); #else SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface; if (old_bitmap->surface_masked) SDL_FreeSurface(old_bitmap->surface_masked); SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY, SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00)); if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL) Error(ERR_EXIT, "SDL_DisplayFormat() failed"); SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */ #endif } #endif if (create_small_bitmaps) { new_width = width_1; new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */ new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH); BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0); BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2, 0, height_1); BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4, width_1 / 2, height_1); BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8, 3 * width_1 / 4, height_1); BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16, 7 * width_1 / 8, height_1); BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32, 15 * width_1 / 16, height_1); UPDATE_BUSY_STATE(); } else { new_width = width_1; new_height = height_1; new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */ } if (create_small_bitmaps) { /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */ if (zoom_factor != 1) FreeBitmap(tmp_bitmap_1); if (zoom_factor != 2) FreeBitmap(tmp_bitmap_2); if (zoom_factor != 4) FreeBitmap(tmp_bitmap_4); if (zoom_factor != 8) FreeBitmap(tmp_bitmap_8); if (zoom_factor != 16) FreeBitmap(tmp_bitmap_16); if (zoom_factor != 32) FreeBitmap(tmp_bitmap_32); } /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */ #if defined(TARGET_SDL) swap_bitmap.surface = old_bitmap->surface; old_bitmap->surface = new_bitmap->surface; new_bitmap->surface = swap_bitmap.surface; #else swap_bitmap.drawable = old_bitmap->drawable; old_bitmap->drawable = new_bitmap->drawable; new_bitmap->drawable = swap_bitmap.drawable; #endif old_bitmap->width = new_bitmap->width; old_bitmap->height = new_bitmap->height; #if 1 /* this replaces all blit masks created when loading -- maybe optimize this */ { #if defined(TARGET_X11) if (old_bitmap->clip_mask) XFreePixmap(display, old_bitmap->clip_mask); old_bitmap->clip_mask = Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height); XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask); #else SDL_Surface *old_surface = old_bitmap->surface; if (old_bitmap->surface_masked) SDL_FreeSurface(old_bitmap->surface_masked); SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY, SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00)); if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL) Error(ERR_EXIT, "SDL_DisplayFormat() failed"); SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */ #endif } #endif UPDATE_BUSY_STATE(); FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */ } void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor) { CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE); } void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor) { CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE); } /* ------------------------------------------------------------------------- */ /* mouse pointer functions */ /* ------------------------------------------------------------------------- */ #if !defined(PLATFORM_MSDOS) #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0 /* XPM image definitions */ static const char *cursor_image_none[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "0,0" }; #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER static const char *cursor_image_dot[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " X ", "X.X ", " X ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "1,1" }; static const char **cursor_image_playfield = cursor_image_dot; #else /* some people complained about a "white dot" on the screen and thought it was a graphical error... OK, let's just remove the whole pointer :-) */ static const char **cursor_image_playfield = cursor_image_none; #endif #if defined(TARGET_SDL) static const int cursor_bit_order = BIT_ORDER_MSB; #elif defined(TARGET_X11_NATIVE) static const int cursor_bit_order = BIT_ORDER_LSB; #endif static struct MouseCursorInfo *get_cursor_from_image(const char **image) { struct MouseCursorInfo *cursor; boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB); int header_lines = 4; int x, y, i; cursor = checked_calloc(sizeof(struct MouseCursorInfo)); sscanf(image[0], " %d %d ", &cursor->width, &cursor->height); i = -1; for (y = 0; y < cursor->width; y++) { for (x = 0; x < cursor->height; x++) { int bit_nr = x % 8; int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr ); if (bit_nr == 0) { i++; cursor->data[i] = cursor->mask[i] = 0; } switch (image[header_lines + y][x]) { case 'X': cursor->data[i] |= bit_mask; cursor->mask[i] |= bit_mask; break; case '.': cursor->mask[i] |= bit_mask; break; case ' ': break; } } } sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y); return cursor; } #endif /* !PLATFORM_MSDOS */ void SetMouseCursor(int mode) { #if !defined(PLATFORM_MSDOS) static struct MouseCursorInfo *cursor_none = NULL; static struct MouseCursorInfo *cursor_playfield = NULL; struct MouseCursorInfo *cursor_new; if (cursor_none == NULL) cursor_none = get_cursor_from_image(cursor_image_none); if (cursor_playfield == NULL) cursor_playfield = get_cursor_from_image(cursor_image_playfield); cursor_new = (mode == CURSOR_DEFAULT ? NULL : mode == CURSOR_NONE ? cursor_none : mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL); #if defined(TARGET_SDL) SDLSetMouseCursor(cursor_new); #elif defined(TARGET_X11_NATIVE) X11SetMouseCursor(cursor_new); #endif #endif } /* ========================================================================= */ /* audio functions */ /* ========================================================================= */ void OpenAudio(void) { /* always start with reliable default values */ audio.sound_available = FALSE; audio.music_available = FALSE; audio.loops_available = FALSE; audio.sound_enabled = FALSE; audio.sound_deactivated = FALSE; audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0; audio.mixer_pid = 0; audio.device_name = NULL; audio.device_fd = -1; audio.num_channels = 0; audio.music_channel = 0; audio.first_sound_channel = 0; #if defined(TARGET_SDL) SDLOpenAudio(); #elif defined(PLATFORM_UNIX) UnixOpenAudio(); #elif defined(PLATFORM_MSDOS) MSDOSOpenAudio(); #endif } void CloseAudio(void) { #if defined(TARGET_SDL) SDLCloseAudio(); #elif defined(PLATFORM_UNIX) UnixCloseAudio(); #elif defined(PLATFORM_MSDOS) MSDOSCloseAudio(); #endif audio.sound_enabled = FALSE; } void SetAudioMode(boolean enabled) { if (!audio.sound_available) return; audio.sound_enabled = enabled; } /* ========================================================================= */ /* event functions */ /* ========================================================================= */ void InitEventFilter(EventFilter filter_function) { #if defined(TARGET_SDL) /* set event filter to filter out certain events */ SDL_SetEventFilter(filter_function); #endif } boolean PendingEvent(void) { #if defined(TARGET_SDL) return (SDL_PollEvent(NULL) ? TRUE : FALSE); #else return (XPending(display) ? TRUE : FALSE); #endif } void NextEvent(Event *event) { #if defined(TARGET_SDL) SDLNextEvent(event); #else XNextEvent(display, event); #endif } void PeekEvent(Event *event) { #if defined(TARGET_SDL) SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS); #else XPeekEvent(display, event); #endif } Key GetEventKey(KeyEvent *event, boolean with_modifiers) { #if defined(TARGET_SDL) #if 0 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n", (int)event->keysym.unicode, (int)event->keysym.sym, (int)SDL_GetModState()); #endif if (with_modifiers && event->keysym.unicode > 0x0000 && event->keysym.unicode < 0x2000) return event->keysym.unicode; else return event->keysym.sym; #else #if 0 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n", (int)XLookupKeysym(event, event->state), (int)XLookupKeysym(event, 0)); #endif if (with_modifiers) return XLookupKeysym(event, event->state); else return XLookupKeysym(event, 0); #endif } KeyMod HandleKeyModState(Key key, int key_status) { static KeyMod current_modifiers = KMOD_None; if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */ { KeyMod new_modifier = KMOD_None; switch(key) { case KSYM_Shift_L: new_modifier = KMOD_Shift_L; break; case KSYM_Shift_R: new_modifier = KMOD_Shift_R; break; case KSYM_Control_L: new_modifier = KMOD_Control_L; break; case KSYM_Control_R: new_modifier = KMOD_Control_R; break; case KSYM_Meta_L: new_modifier = KMOD_Meta_L; break; case KSYM_Meta_R: new_modifier = KMOD_Meta_R; break; case KSYM_Alt_L: new_modifier = KMOD_Alt_L; break; case KSYM_Alt_R: new_modifier = KMOD_Alt_R; break; default: break; } if (key_status == KEY_PRESSED) current_modifiers |= new_modifier; else current_modifiers &= ~new_modifier; } return current_modifiers; } KeyMod GetKeyModState() { #if defined(TARGET_SDL) return (KeyMod)SDL_GetModState(); #else return HandleKeyModState(KSYM_UNDEFINED, 0); #endif } KeyMod GetKeyModStateFromEvents() { /* always use key modifier state as tracked from key events (this is needed if the modifier key event was injected into the event queue, but the key was not really pressed on keyboard -- SDL_GetModState() seems to directly query the keys as held pressed on the keyboard) -- this case is currently only used to filter out clipboard insert events from "True X-Mouse" tool */ return HandleKeyModState(KSYM_UNDEFINED, 0); } boolean CheckCloseWindowEvent(ClientMessageEvent *event) { if (event->type != EVENT_CLIENTMESSAGE) return FALSE; #if defined(TARGET_SDL) return TRUE; /* the only possible message here is SDL_QUIT */ #elif defined(PLATFORM_UNIX) if ((event->window == window->drawable) && (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE))) return TRUE; #endif return FALSE; } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ void InitJoysticks() { int i; #if defined(NO_JOYSTICK) return; /* joysticks generally deactivated by compile-time directive */ #endif /* always start with reliable default values */ joystick.status = JOYSTICK_NOT_AVAILABLE; for (i = 0; i < MAX_PLAYERS; i++) joystick.fd[i] = -1; /* joystick device closed */ #if defined(TARGET_SDL) SDLInitJoysticks(); #elif defined(PLATFORM_UNIX) UnixInitJoysticks(); #elif defined(PLATFORM_MSDOS) MSDOSInitJoysticks(); #endif #if 0 for (i = 0; i < MAX_PLAYERS; i++) printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]); #endif } boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { #if defined(TARGET_SDL) return SDLReadJoystick(nr, x, y, b1, b2); #elif defined(PLATFORM_UNIX) return UnixReadJoystick(nr, x, y, b1, b2); #elif defined(PLATFORM_MSDOS) return MSDOSReadJoystick(nr, x, y, b1, b2); #endif } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/hash.h0000644000175000017500000002255611272652010020117 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * hash.h * ***********************************************************/ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software and its documentation and acknowledgment shall be * given in the documentation and software packages that this Software was * used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #ifndef HASH_H #define HASH_H /* Example of use: * * struct hashtable *h; * struct some_key *k; * struct some_value *v; * * static unsigned int hash_from_key_fn( void *k ); * static int keys_equal_fn ( void *key1, void *key2 ); * * h = create_hashtable(16, 0.75, hash_from_key_fn, keys_equal_fn); * k = (struct some_key *) malloc(sizeof(struct some_key)); * v = (struct some_value *) malloc(sizeof(struct some_value)); * * (initialise k and v to suitable values) * * if (! hashtable_insert(h,k,v) ) * { exit(-1); } * * if (NULL == (found = hashtable_search(h,k) )) * { printf("not found!"); } * * if (NULL == (found = hashtable_remove(h,k) )) * { printf("Not found\n"); } * */ /* Macros may be used to define type-safe(r) hashtable access functions, with * methods specialized to take known key and value types as parameters. * * Example: * * Insert this at the start of your file: * * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); * * This defines the functions 'insert_some', 'search_some' and 'remove_some'. * These operate just like hashtable_insert etc., with the same parameters, * but their function signatures have 'struct some_key *' rather than * 'void *', and hence can generate compile time errors if your program is * supplying incorrect data as a key (and similarly for value). * * Note that the hash and key equality functions passed to create_hashtable * still take 'void *' parameters instead of 'some key *'. This shouldn't be * a difficult issue as they're only defined and passed once, and the other * functions will ensure that only valid keys are supplied to them. * * The cost for this checking is increased code size and runtime overhead * - if performance is important, it may be worth switching back to the * unsafe methods once your program has been debugged with the safe methods. * This just requires switching to some simple alternative defines - eg: * #define insert_some hashtable_insert * */ /*****************************************************************************/ struct entry { void *k, *v; unsigned int h; struct entry *next; }; struct hashtable { unsigned int tablelength; struct entry **table; unsigned int entrycount; unsigned int loadlimit; unsigned int (*hashfn) (void *k); int (*eqfn) (void *k1, void *k2); }; /*****************************************************************************/ struct hashtable_itr { struct hashtable *h; struct entry *e; unsigned int index; }; /***************************************************************************** * create_hashtable * @name create_hashtable * @param minsize minimum initial size of hashtable * @param maxloadfactor maximum ratio entries / tablesize * @param hashfunction function for hashing keys * @param key_eq_fn function for determining key equality * @return newly created hashtable or NULL on failure */ struct hashtable * create_hashtable(unsigned int minsize, float maxloadfactor, unsigned int (*hashfunction) (void*), int (*key_eq_fn) (void*,void*)); /***************************************************************************** * hashtable_insert * @name hashtable_insert * @param h the hashtable to insert into * @param k the key - hashtable claims ownership and will free on removal * @param v the value - does not claim ownership * @return non-zero for successful insertion * * This function will cause the table to expand if the insertion would take * the ratio of entries to table size over the maximum load factor. * * This function does not check for repeated insertions with a duplicate key. * The value returned when using a duplicate key is undefined -- when * the hashtable changes size, the order of retrieval of duplicate key * entries is reversed. * If in doubt, remove before insert. */ int hashtable_insert(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_insert(h,k,v); \ } /***************************************************************************** * hashtable_change * @name hashtable_change * @param h the hashtable to search * @param k the key of the entry to change * @param v the new value * @return non-zero for successful change */ int hashtable_change(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_CHANGE(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_change(h,k,v); \ } /***************************************************************************** * hashtable_search * @name hashtable_search * @param h the hashtable to search * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * hashtable_search(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_search(h,k)); \ } /***************************************************************************** * hashtable_remove * @name hashtable_remove * @param h the hashtable to remove the item from * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * /* returns value */ hashtable_remove(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_remove(h,k)); \ } /***************************************************************************** * hashtable_count * @name hashtable_count * @return the number of items stored in the hashtable */ unsigned int hashtable_count(struct hashtable *h); /***************************************************************************** * hashtable_destroy * @name hashtable_destroy * @param free_values whether to call 'free' on the remaining values */ void hashtable_destroy(struct hashtable *h, int free_values); /*****************************************************************************/ /* hashtable_iterator */ struct hashtable_itr * hashtable_iterator(struct hashtable *h); /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i); /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_value(struct hashtable_itr *i); /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr); #endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/windows.h0000644000175000017500000000234710471574636020703 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * windows.h * ***********************************************************/ #ifndef WINDOWS_H #define WINDOWS_H #include /* some symbols are already defined on Windows */ #define CreateBitmap CreateBitmap_internal #define GetPixel GetPixel_internal #define CloseWindow CloseWindow_internal #define FloodFill FloodFill_internal #ifdef LoadImage #undef LoadImage #define LoadImage LoadImage_internal #endif #ifdef PlaySound #undef PlaySound #define PlaySound PlaySound_internal #endif #ifdef DrawText #undef DrawText #define DrawText DrawText_internal #endif #endif /* WINDOWS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/pcx.h0000644000175000017500000000217310471574477020003 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * pcx.h * ***********************************************************/ #ifndef PCX_H #define PCX_H #include "system.h" #include "image.h" #if !defined(TARGET_SDL) #define PCX_Success 0 #define PCX_OpenFailed -1 #define PCX_ReadFailed -2 #define PCX_FileInvalid -3 #define PCX_NoMemory -4 #define PCX_ColorFailed -5 #define PCX_OtherError -6 /* global PCX error value */ extern int errno_pcx; Image *Read_PCX_to_Image(char *); #endif /* !TARGET_SDL */ #endif /* PCX_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/setup.h0000644000175000017500000002554611352503604020341 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * setup.h * ***********************************************************/ #ifndef SETUP_H #define SETUP_H #include "system.h" #include "hash.h" /* values for setup file handling */ #define TYPE_BOOLEAN (1 << 0) #define TYPE_SWITCH (1 << 1) #define TYPE_SWITCH3 (1 << 2) #define TYPE_YES_NO (1 << 3) #define TYPE_YES_NO_AUTO (1 << 4) #define TYPE_ECS_AGA (1 << 5) #define TYPE_KEY (1 << 6) #define TYPE_KEY_X11 (1 << 7) #define TYPE_INTEGER (1 << 8) #define TYPE_STRING (1 << 9) #define TYPE_ELEMENT (1 << 10) #define TYPE_GRAPHIC (1 << 11) /* additional values for setup screen */ #define TYPE_ENTER_SCREEN (1 << 12) #define TYPE_LEAVE_SCREEN (1 << 13) #define TYPE_ENTER_MENU (1 << 14) #define TYPE_LEAVE_MENU (1 << 15) #define TYPE_ENTER_LIST (1 << 16) #define TYPE_LEAVE_LIST (1 << 17) #define TYPE_EMPTY (1 << 18) #define TYPE_KEYTEXT (1 << 19) #define TYPE_GHOSTED (1 << 20) #define TYPE_QUERY (1 << 21) /* additional values for internal purposes */ #define TYPE_BITFIELD (1 << 22) #define TYPE_CONTENT (1 << 23) #define TYPE_ELEMENT_LIST (1 << 24) #define TYPE_CONTENT_LIST (1 << 25) /* derived values for setup file handling */ #define TYPE_BOOLEAN_STYLE (TYPE_BOOLEAN | \ TYPE_SWITCH | \ TYPE_YES_NO | \ TYPE_ECS_AGA ) /* derived values for setup screen */ #define TYPE_VALUE (TYPE_BOOLEAN_STYLE | \ TYPE_SWITCH3 | \ TYPE_YES_NO_AUTO | \ TYPE_KEY | \ TYPE_KEY_X11 | \ TYPE_INTEGER | \ TYPE_STRING | \ TYPE_ELEMENT | \ TYPE_GRAPHIC) #define TYPE_SKIP_ENTRY (TYPE_EMPTY | \ TYPE_KEY | \ TYPE_STRING | \ TYPE_GHOSTED) #define TYPE_ENTER (TYPE_ENTER_SCREEN | \ TYPE_ENTER_MENU | \ TYPE_ENTER_LIST) #define TYPE_LEAVE (TYPE_LEAVE_SCREEN | \ TYPE_LEAVE_MENU | \ TYPE_LEAVE_LIST) #define TYPE_ENTER_OR_LEAVE (TYPE_ENTER | TYPE_LEAVE) /* cookie token for file identifier and version number */ #define TOKEN_STR_FILE_IDENTIFIER "file_identifier" struct TokenInfo { int type; void *value; char *text; }; /* some definitions for list and hash handling */ typedef struct SetupFileList SetupFileList; typedef struct hashtable SetupFileHash; #define BEGIN_HASH_ITERATION(hash, itr) \ if (hash != NULL && hashtable_count(hash) > 0) \ { \ struct hashtable_itr *itr = hashtable_iterator(hash); \ do { \ #define HASH_ITERATION_TOKEN(itr) ((char *)hashtable_iterator_key(itr)) #define HASH_ITERATION_VALUE(itr) ((char *)hashtable_iterator_value(itr)) #define END_HASH_ITERATION(hash, itr) \ } while (hashtable_iterator_advance(itr)); \ free(itr); \ } \ /* sort priorities of level series (also used as level series classes) */ #define LEVELCLASS_TUTORIAL_START 10 #define LEVELCLASS_TUTORIAL_END 99 #define LEVELCLASS_CLASSICS_START 100 #define LEVELCLASS_CLASSICS_END 199 #define LEVELCLASS_CONTRIB_START 200 #define LEVELCLASS_CONTRIB_END 299 #define LEVELCLASS_PRIVATE_START 300 #define LEVELCLASS_PRIVATE_END 399 #define LEVELCLASS_BD_START 400 #define LEVELCLASS_BD_END 499 #define LEVELCLASS_EM_START 500 #define LEVELCLASS_EM_END 599 #define LEVELCLASS_SP_START 600 #define LEVELCLASS_SP_END 699 #define LEVELCLASS_DX_START 700 #define LEVELCLASS_DX_END 799 #define LEVELCLASS_SB_START 800 #define LEVELCLASS_SB_END 899 #define LEVELCLASS_PREDEFINED_START LEVELCLASS_TUTORIAL_START #define LEVELCLASS_PREDEFINED_END LEVELCLASS_SB_END #define LEVELCLASS_TUTORIAL LEVELCLASS_TUTORIAL_START #define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START #define LEVELCLASS_CONTRIB LEVELCLASS_CONTRIB_START #define LEVELCLASS_PRIVATE LEVELCLASS_PRIVATE_START #define LEVELCLASS_BD LEVELCLASS_BD_START #define LEVELCLASS_EM LEVELCLASS_EM_START #define LEVELCLASS_SP LEVELCLASS_SP_START #define LEVELCLASS_DX LEVELCLASS_DX_START #define LEVELCLASS_SB LEVELCLASS_SB_START #define LEVELCLASS_UNDEFINED 999 #define IS_LEVELCLASS_TUTORIAL(p) \ ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \ (p)->sort_priority <= LEVELCLASS_TUTORIAL_END) #define IS_LEVELCLASS_CLASSICS(p) \ ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \ (p)->sort_priority <= LEVELCLASS_CLASSICS_END) #define IS_LEVELCLASS_CONTRIB(p) \ ((p)->sort_priority >= LEVELCLASS_CONTRIB_START && \ (p)->sort_priority <= LEVELCLASS_CONTRIB_END) #define IS_LEVELCLASS_PRIVATE(p) \ ((p)->sort_priority >= LEVELCLASS_PRIVATE_START && \ (p)->sort_priority <= LEVELCLASS_PRIVATE_END) #define IS_LEVELCLASS_BD(p) \ ((p)->sort_priority >= LEVELCLASS_BD_START && \ (p)->sort_priority <= LEVELCLASS_BD_END) #define IS_LEVELCLASS_EM(p) \ ((p)->sort_priority >= LEVELCLASS_EM_START && \ (p)->sort_priority <= LEVELCLASS_EM_END) #define IS_LEVELCLASS_SP(p) \ ((p)->sort_priority >= LEVELCLASS_SP_START && \ (p)->sort_priority <= LEVELCLASS_SP_END) #define IS_LEVELCLASS_DX(p) \ ((p)->sort_priority >= LEVELCLASS_DX_START && \ (p)->sort_priority <= LEVELCLASS_DX_END) #define IS_LEVELCLASS_SB(p) \ ((p)->sort_priority >= LEVELCLASS_SB_START && \ (p)->sort_priority <= LEVELCLASS_SB_END) #define IS_LEVELCLASS_UNDEFINED(p) \ ((p)->sort_priority < LEVELCLASS_PREDEFINED_START || \ (p)->sort_priority > LEVELCLASS_PREDEFINED_END) #define LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \ IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \ IS_LEVELCLASS_CONTRIB(n) ? LEVELCLASS_CONTRIB : \ IS_LEVELCLASS_PRIVATE(n) ? LEVELCLASS_PRIVATE : \ IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \ IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \ IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \ IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \ IS_LEVELCLASS_SB(n) ? LEVELCLASS_SB : \ LEVELCLASS_UNDEFINED) /* sort priorities of artwork */ #define ARTWORKCLASS_CLASSICS_START 100 #define ARTWORKCLASS_CLASSICS_END 199 #define ARTWORKCLASS_CONTRIB_START 200 #define ARTWORKCLASS_CONTRIB_END 299 #define ARTWORKCLASS_PRIVATE_START 300 #define ARTWORKCLASS_PRIVATE_END 399 #define ARTWORKCLASS_LEVEL_START 400 #define ARTWORKCLASS_LEVEL_END 499 #define ARTWORKCLASS_CLASSICS ARTWORKCLASS_CLASSICS_START #define ARTWORKCLASS_CONTRIB ARTWORKCLASS_CONTRIB_START #define ARTWORKCLASS_PRIVATE ARTWORKCLASS_PRIVATE_START #define ARTWORKCLASS_LEVEL ARTWORKCLASS_LEVEL_START #define ARTWORKCLASS_UNDEFINED 999 #define IS_ARTWORKCLASS_CLASSICS(p) \ ((p)->sort_priority >= ARTWORKCLASS_CLASSICS_START && \ (p)->sort_priority <= ARTWORKCLASS_CLASSICS_END) #define IS_ARTWORKCLASS_CONTRIB(p) \ ((p)->sort_priority >= ARTWORKCLASS_CONTRIB_START && \ (p)->sort_priority <= ARTWORKCLASS_CONTRIB_END) #define IS_ARTWORKCLASS_PRIVATE(p) \ ((p)->sort_priority >= ARTWORKCLASS_PRIVATE_START && \ (p)->sort_priority <= ARTWORKCLASS_PRIVATE_END) #define IS_ARTWORKCLASS_LEVEL(p) \ ((p)->sort_priority >= ARTWORKCLASS_LEVEL_START && \ (p)->sort_priority <= ARTWORKCLASS_LEVEL_END) #define ARTWORKCLASS(n) (IS_ARTWORKCLASS_CLASSICS(n) ? ARTWORKCLASS_CLASSICS :\ IS_ARTWORKCLASS_CONTRIB(n) ? ARTWORKCLASS_CONTRIB : \ IS_ARTWORKCLASS_PRIVATE(n) ? ARTWORKCLASS_PRIVATE : \ IS_ARTWORKCLASS_LEVEL(n) ? ARTWORKCLASS_LEVEL : \ ARTWORKCLASS_UNDEFINED) char *setLevelArtworkDir(TreeInfo *); char *getTapeFilename(int); char *getSolutionTapeFilename(int); char *getScoreFilename(int); char *getSetupFilename(void); char *getEditorSetupFilename(void); char *getHelpAnimFilename(void); char *getHelpTextFilename(void); char *getLevelSetInfoFilename(void); char *getLevelSetTitleMessageFilename(int, boolean); char *getImageFilename(char *); char *getCustomImageFilename(char *); char *getCustomSoundFilename(char *); char *getCustomMusicFilename(char *); char *getCustomArtworkFilename(char *, int); char *getCustomArtworkConfigFilename(int); char *getCustomArtworkLevelConfigFilename(int); char *getCustomMusicDirectory(void); void InitTapeDirectory(char *); void InitScoreDirectory(char *); void InitUserLevelDirectory(char *); void InitLevelSetupDirectory(char *); TreeInfo *newTreeInfo(); TreeInfo *newTreeInfo_setDefaults(int); void pushTreeInfo(TreeInfo **, TreeInfo *); int numTreeInfo(TreeInfo *); boolean validLevelSeries(TreeInfo *); TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *); TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *); int numTreeInfoInGroup(TreeInfo *); int posTreeInfo(TreeInfo *); TreeInfo *getTreeInfoFromPos(TreeInfo *, int); TreeInfo *getTreeInfoFromIdentifier(TreeInfo *, char *); void dumpTreeInfo(TreeInfo *, int); void sortTreeInfoBySortFunction(TreeInfo **, int (*compare_function)(const void *, const void *)); void sortTreeInfo(TreeInfo **); char *getHomeDir(void); char *getCommonDataDir(void); char *getPersonalDataDir(void); char *getUserGameDataDir(void); char *getSetupDir(void); char *getCurrentLevelDir(void); void updateUserGameDataDir(void); void createDirectory(char *, char *, int); void InitUserDataDirectory(void); void SetFilePermissions(char *, int); char *getCookie(char *); int getFileVersionFromCookieString(const char *); boolean checkCookieString(const char *, const char *); char *getFormattedSetupEntry(char *, char *); boolean getTokenValueFromSetupLine(char *, char **, char **); SetupFileList *newSetupFileList(char *, char *); void freeSetupFileList(SetupFileList *); char *getListEntry(SetupFileList *, char *); SetupFileList *setListEntry(SetupFileList *, char *, char *); SetupFileList *addListEntry(SetupFileList *, char *, char *); SetupFileList *loadSetupFileList(char *); SetupFileHash *newSetupFileHash(); void freeSetupFileHash(SetupFileHash *); char *getHashEntry(SetupFileHash *, char *); void setHashEntry(SetupFileHash *, char *, char *); char *removeHashEntry(SetupFileHash *, char *); SetupFileHash *loadSetupFileHash(char *); void checkSetupFileHashIdentifier(SetupFileHash *, char *, char *); void setSetupInfo(struct TokenInfo *, int, char *); char *getSetupValue(int, void *); char *getSetupLine(struct TokenInfo *, char *, int); unsigned int get_hash_from_key(void *); boolean AdjustGraphicsForEMC(); void LoadLevelInfo(void); void LoadArtworkInfo(void); void LoadLevelArtworkInfo(void); void LoadLevelSetup_LastSeries(void); void SaveLevelSetup_LastSeries(void); void LoadLevelSetup_SeriesInfo(void); void SaveLevelSetup_SeriesInfo(void); #endif /* MISC_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/x11.c0000644000175000017500000003660311355446457017620 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * x11.c * ***********************************************************/ #include "system.h" #include "pcx.h" #include "misc.h" #include "setup.h" #if defined(TARGET_X11) static void X11InitDisplay(); static DrawWindow *X11InitWindow(); static int X11DebugErrorHandler(Display *display, XErrorEvent *event) { int x = 0; return 1 / x; /* !!! crash program to give backtrace in gdb !!! */ } void X11InitVideoDisplay(void) { /* initialize X11 video */ X11InitDisplay(); /* set default X11 depth */ video.default_depth = XDefaultDepth(display, screen); } void X11InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window) { if (*window != NULL) X11CloseWindow(*window); *window = X11InitWindow(); XMapWindow(display, (*window)->drawable); FlushDisplay(); /* create additional (off-screen) buffer for double-buffering */ #if 1 ReCreateBitmap(backbuffer, video.width, video.height, video.depth); #else *backbuffer = CreateBitmap(video.width, video.height, video.depth); #endif } static void X11InitDisplay() { #if !defined(PLATFORM_MSDOS) XVisualInfo vinfo_template, *vinfo; int num_visuals; #endif unsigned int depth; /* connect to X server */ if (!(display = XOpenDisplay(options.display_name))) Error(ERR_EXIT, "cannot connect to X server %s", XDisplayName(options.display_name)); if (options.debug_x11_sync) { Error(ERR_WARN, "running in X11 synchronous mode (debug only)"); XSynchronize(display, True); XSetErrorHandler(X11DebugErrorHandler); } screen = DefaultScreen(display); visual = DefaultVisual(display, screen); depth = DefaultDepth(display, screen); cmap = DefaultColormap(display, screen); #if !defined(PLATFORM_MSDOS) /* look for good enough visual */ vinfo_template.screen = screen; vinfo_template.class = (depth == 8 ? PseudoColor : TrueColor); vinfo_template.depth = depth; if ((vinfo = XGetVisualInfo(display, VisualScreenMask | VisualClassMask | VisualDepthMask, &vinfo_template, &num_visuals))) { visual = vinfo->visual; XFree((void *)vinfo); } /* got appropriate visual? */ if (depth < 8) Error(ERR_EXIT, "X11 display not supported (less than 8 bits per pixel)"); else if ((depth ==8 && visual->class != PseudoColor) || (depth > 8 && visual->class != TrueColor && visual->class != DirectColor)) Error(ERR_EXIT, "X11 display not supported (inappropriate visual)"); #endif /* !PLATFORM_MSDOS */ } static DrawWindow *X11InitWindow() { DrawWindow *new_window = CreateBitmapStruct(); unsigned int border_width = 4; XGCValues gc_values; unsigned long gc_valuemask; #if !defined(PLATFORM_MSDOS) XTextProperty windowName, iconName; Pixmap icon_pixmap, iconmask_pixmap; unsigned int icon_width, icon_height; int icon_hot_x, icon_hot_y; XSizeHints size_hints; XWMHints wm_hints; XClassHint class_hints; char *window_name = program.window_title; char *icon_name = program.window_title; long window_event_mask; Atom proto_atom = None, delete_atom = None; #endif int screen_width, screen_height; int win_xpos, win_ypos; unsigned long pen_fg = WhitePixel(display, screen); unsigned long pen_bg = BlackPixel(display, screen); const int width = video.width, height = video.height; int i; screen_width = XDisplayWidth(display, screen); screen_height = XDisplayHeight(display, screen); win_xpos = (screen_width - width) / 2; win_ypos = (screen_height - height) / 2; new_window->width = width; new_window->height = height; new_window->drawable = XCreateSimpleWindow(display, RootWindow(display, screen), win_xpos, win_ypos, width, height, border_width, pen_fg, pen_bg); #if !defined(PLATFORM_MSDOS) proto_atom = XInternAtom(display, "WM_PROTOCOLS", FALSE); delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", FALSE); if ((proto_atom != None) && (delete_atom != None)) XChangeProperty(display, new_window->drawable, proto_atom, XA_ATOM, 32, PropModePrepend, (unsigned char *) &delete_atom, 1); if (XReadBitmapFile(display, new_window->drawable, getCustomImageFilename(program.x11_icon_filename), &icon_width, &icon_height, &icon_pixmap, &icon_hot_x, &icon_hot_y) != BitmapSuccess) Error(ERR_EXIT, "cannot read icon bitmap file '%s'", program.x11_icon_filename); if (XReadBitmapFile(display, new_window->drawable, getCustomImageFilename(program.x11_iconmask_filename), &icon_width, &icon_height, &iconmask_pixmap, &icon_hot_x, &icon_hot_y) != BitmapSuccess) Error(ERR_EXIT, "cannot read icon bitmap file '%s'", program.x11_iconmask_filename); size_hints.width = size_hints.min_width = size_hints.max_width = width; size_hints.height = size_hints.min_height = size_hints.max_height = height; size_hints.flags = PSize | PMinSize | PMaxSize; if (win_xpos || win_ypos) { size_hints.x = win_xpos; size_hints.y = win_ypos; size_hints.flags |= PPosition; } if (!XStringListToTextProperty(&window_name, 1, &windowName)) Error(ERR_EXIT, "structure allocation for windowName failed"); if (!XStringListToTextProperty(&icon_name, 1, &iconName)) Error(ERR_EXIT, "structure allocation for iconName failed"); wm_hints.initial_state = NormalState; wm_hints.input = True; wm_hints.icon_pixmap = icon_pixmap; wm_hints.icon_mask = iconmask_pixmap; wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint; class_hints.res_name = program.command_basename; class_hints.res_class = program.program_title; XSetWMProperties(display, new_window->drawable, &windowName, &iconName, NULL, 0, &size_hints, &wm_hints, &class_hints); XFree(windowName.value); XFree(iconName.value); /* Select event types wanted */ window_event_mask = ExposureMask | StructureNotifyMask | FocusChangeMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask | KeyPressMask | KeyReleaseMask; XSelectInput(display, new_window->drawable, window_event_mask); #endif /* create GC for drawing with window depth and background color (black) */ gc_values.graphics_exposures = False; gc_values.foreground = pen_bg; gc_values.background = pen_bg; gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground; new_window->gc = XCreateGC(display, new_window->drawable, gc_valuemask, &gc_values); /* create GCs for line drawing (black and white) */ for (i = 0; i < 2; i++) { gc_values.graphics_exposures = False; gc_values.foreground = (i ? pen_fg : pen_bg); gc_values.background = pen_bg; gc_values.line_width = 4; gc_values.line_style = LineSolid; gc_values.cap_style = CapRound; gc_values.join_style = JoinRound; gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle; new_window->line_gc[i] = XCreateGC(display, new_window->drawable, gc_valuemask, &gc_values); } return new_window; } void X11CloseWindow(DrawWindow *window) { if (window->drawable) { XUnmapWindow(display, window->drawable); XDestroyWindow(display, window->drawable); } if (window->gc) XFreeGC(display, window->gc); free(window); } void X11ZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap) { #if defined(TARGET_ALLEGRO) AllegroZoomBitmap(src_bitmap->drawable, dst_bitmap->drawable, src_bitmap->width, src_bitmap->height, dst_bitmap->width, dst_bitmap->height); #else ZoomPixmap(display, src_bitmap->gc, src_bitmap->drawable, dst_bitmap->drawable, src_bitmap->width, src_bitmap->height, dst_bitmap->width, dst_bitmap->height); #endif } static void SetImageDimensions(Bitmap *bitmap) { #if defined(TARGET_ALLEGRO) BITMAP *allegro_bitmap = (BITMAP *)(bitmap->drawable); bitmap->width = allegro_bitmap->w; bitmap->height = allegro_bitmap->h; #else Window root; int x, y; unsigned int border_width, depth; XGetGeometry(display, bitmap->drawable, &root, &x, &y, &bitmap->width, &bitmap->height, &border_width, &depth); #endif } Bitmap *X11LoadImage(char *filename) { Bitmap *new_bitmap = CreateBitmapStruct(); char *error = "Read_PCX_to_Pixmap(): %s '%s'"; int pcx_err; XGCValues clip_gc_values; unsigned long clip_gc_valuemask; pcx_err = Read_PCX_to_Pixmap(display, window->drawable, window->gc, filename, &new_bitmap->drawable, &new_bitmap->clip_mask); switch(pcx_err) { case PCX_Success: break; case PCX_OpenFailed: SetError(error, "cannot open PCX file", filename); return NULL; case PCX_ReadFailed: SetError(error, "cannot read PCX file", filename); return NULL; case PCX_FileInvalid: SetError(error, "invalid PCX file", filename); return NULL; case PCX_NoMemory: SetError(error, "not enough memory for PCX file", filename); return NULL; case PCX_ColorFailed: SetError(error, "cannot get colors for PCX file", filename); return NULL; case PCX_OtherError: /* this should already have called SetError() */ return NULL; default: SetError(error, "unknown error reading PCX file", filename); return NULL; } if (!new_bitmap->drawable) { SetError("X11LoadImage(): cannot get graphics for '%s'", filename); return NULL; } if (!new_bitmap->clip_mask) { SetError("X11LoadImage(): cannot get clipmask for '%s'", filename); return NULL; } clip_gc_values.graphics_exposures = False; clip_gc_values.clip_mask = new_bitmap->clip_mask; clip_gc_valuemask = GCGraphicsExposures | GCClipMask; new_bitmap->stored_clip_gc = XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values); /* set GraphicContext inheritated from Window */ new_bitmap->gc = window->gc; /* set image width and height */ SetImageDimensions(new_bitmap); return new_bitmap; } void X11CreateBitmapContent(Bitmap *new_bitmap, int width, int height, int depth) { Pixmap pixmap; if ((pixmap = XCreatePixmap(display, window->drawable, width, height, depth)) == None) Error(ERR_EXIT, "cannot create pixmap"); new_bitmap->drawable = pixmap; if (window == NULL) Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first"); new_bitmap->gc = window->gc; new_bitmap->line_gc[0] = window->line_gc[0]; new_bitmap->line_gc[1] = window->line_gc[1]; } void X11FreeBitmapPointers(Bitmap *bitmap) { /* The X11 version seems to have a memory leak here -- although "XFreePixmap()" is called, the corresponding memory seems not to be freed (according to "ps"). The SDL version apparently does not have this problem. */ if (bitmap->drawable) XFreePixmap(display, bitmap->drawable); if (bitmap->clip_mask) XFreePixmap(display, bitmap->clip_mask); if (bitmap->stored_clip_gc) XFreeGC(display, bitmap->stored_clip_gc); /* the other GCs are only pointers to GCs used elsewhere */ bitmap->drawable = None; bitmap->clip_mask = None; bitmap->stored_clip_gc = None; } void X11CopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable, (mask_mode == BLIT_MASKED ? src_bitmap->clip_gc : dst_bitmap->gc), src_x, src_y, width, height, dst_x, dst_y); } void X11FillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { XSetForeground(display, bitmap->gc, color); XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height); } void X11FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { /* fading currently not supported -- simply copy backbuffer to screen */ if (fade_mode == FADE_MODE_FADE_OUT) X11FillRectangle(backbuffer, x, y, width, height, BLACK_PIXEL); if (draw_border_function != NULL) draw_border_function(); X11CopyArea(backbuffer, window, x, y, width, height, x, y, BLIT_OPAQUE); /* as we currently cannot use the fade delay, also do not use post delay */ } void X11DrawSimpleLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y, Pixel color) { XSetForeground(display, bitmap->gc, color); XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y); } Pixel X11GetPixel(Bitmap *bitmap, int x, int y) { XImage *pixel_image; Pixel pixel_value; pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1, AllPlanes, ZPixmap); pixel_value = XGetPixel(pixel_image, 0, 0); X11DestroyImage(pixel_image); return pixel_value; } #if defined(TARGET_X11_NATIVE) Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g, unsigned int color_b) { XColor xcolor; Pixel pixel; xcolor.flags = DoRed | DoGreen | DoBlue; xcolor.red = (color_r << 8); xcolor.green = (color_g << 8); xcolor.blue = (color_b << 8); XAllocColor(display, cmap, &xcolor); pixel = xcolor.pixel; return pixel; } #endif /* TARGET_X11_NATIVE */ void X11DestroyImage(XImage *ximage) { #if defined(TARGET_X11_NATIVE) /* this seems to be needed for OS/2, but does not hurt on other platforms */ if (ximage->data != NULL) { free(ximage->data); ximage->data = NULL; } #endif /* TARGET_X11_NATIVE */ XDestroyImage(ximage); } /* ------------------------------------------------------------------------- */ /* mouse pointer functions */ /* ------------------------------------------------------------------------- */ #if defined(TARGET_X11_NATIVE) static Cursor create_cursor(struct MouseCursorInfo *cursor_info) { Pixmap pixmap_data, pixmap_mask; XColor color_fg, color_bg; Cursor cursor; /* shape and mask are single plane pixmaps */ pixmap_data = XCreatePixmapFromBitmapData(display, window->drawable, cursor_info->data, cursor_info->width, cursor_info->height, 1, 0, 1); pixmap_mask = XCreatePixmapFromBitmapData(display, window->drawable, cursor_info->mask, cursor_info->width, cursor_info->height, 1, 0, 1); XParseColor(display, cmap, "black", &color_fg); XParseColor(display, cmap, "white", &color_bg); cursor = XCreatePixmapCursor(display, pixmap_data, pixmap_mask, &color_fg, &color_bg, cursor_info->hot_x, cursor_info->hot_y); return cursor; } void X11SetMouseCursor(struct MouseCursorInfo *cursor_info) { static struct MouseCursorInfo *last_cursor_info = NULL; static Cursor cursor_default = None; static Cursor cursor_current = None; if (cursor_info != NULL && cursor_info != last_cursor_info) { cursor_current = create_cursor(cursor_info); last_cursor_info = cursor_info; } XDefineCursor(display, window->drawable, cursor_info ? cursor_current : cursor_default); } #endif /* TARGET_X11_NATIVE */ #endif /* TARGET_X11 */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/text.c0000644000175000017500000006277511364305412020165 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * text.c * ***********************************************************/ #include #include #include "text.h" #include "misc.h" /* ========================================================================= */ /* font functions */ /* ========================================================================= */ #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) static GC font_clip_gc = None; static void InitFontClipmasks() { XGCValues clip_gc_values; unsigned long clip_gc_valuemask; GC copy_clipmask_gc; int i, j; /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is often very slow when preparing a masked XCopyArea() for big Pixmaps. To prevent this, create small (tile-sized) mask Pixmaps which will then be set much faster with XSetClipOrigin() and speed things up a lot. */ clip_gc_values.graphics_exposures = False; clip_gc_valuemask = GCGraphicsExposures; font_clip_gc = XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values); /* create graphic context structures needed for clipping */ clip_gc_values.graphics_exposures = False; clip_gc_valuemask = GCGraphicsExposures; copy_clipmask_gc = XCreateGC(display, gfx.font_bitmap_info[0].bitmap->clip_mask, clip_gc_valuemask, &clip_gc_values); /* create only those clipping Pixmaps we really need */ for (i = 0; i < gfx.num_fonts; i++) { if (gfx.font_bitmap_info[i].bitmap == NULL) continue; gfx.font_bitmap_info[i].clip_mask = checked_calloc(gfx.font_bitmap_info[i].num_chars * sizeof(Pixmap)); for (j = 0; j < gfx.font_bitmap_info[i].num_chars; j++) { Bitmap *src_bitmap = gfx.font_bitmap_info[i].bitmap; Pixmap src_pixmap = src_bitmap->clip_mask; int xpos = j % gfx.font_bitmap_info[i].num_chars_per_line; int ypos = j / gfx.font_bitmap_info[i].num_chars_per_line; int width = gfx.font_bitmap_info[i].width; int height = gfx.font_bitmap_info[i].height; int src_x = gfx.font_bitmap_info[i].src_x + xpos * width; int src_y = gfx.font_bitmap_info[i].src_y + ypos * height; gfx.font_bitmap_info[i].clip_mask[j] = XCreatePixmap(display, window->drawable, width, height, 1); XCopyArea(display, src_pixmap, gfx.font_bitmap_info[i].clip_mask[j], copy_clipmask_gc, src_x, src_y, width, height, 0, 0); } } XFreeGC(display, copy_clipmask_gc); } static void FreeFontClipmasks() { int i, j; if (gfx.num_fonts == 0 || gfx.font_bitmap_info[0].bitmap == NULL) return; for (i = 0; i < gfx.num_fonts; i++) { if (gfx.font_bitmap_info[i].clip_mask) { for (j = 0; j < gfx.font_bitmap_info[i].num_chars; j++) XFreePixmap(display, gfx.font_bitmap_info[i].clip_mask[j]); free(gfx.font_bitmap_info[i].clip_mask); } gfx.font_bitmap_info[i].clip_mask = NULL; gfx.font_bitmap_info[i].num_chars = 0; } if (font_clip_gc) XFreeGC(display, font_clip_gc); font_clip_gc = None; } #endif /* TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND */ void InitFontInfo(struct FontBitmapInfo *font_bitmap_info, int num_fonts, int (*select_font_function)(int), int (*get_font_from_token_function)(char *)) { gfx.num_fonts = num_fonts; gfx.font_bitmap_info = font_bitmap_info; gfx.select_font_function = select_font_function; gfx.get_font_from_token_function = get_font_from_token_function; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) InitFontClipmasks(); #endif } void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info) { if (font_bitmap_info == NULL) return; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) FreeFontClipmasks(); #endif free(font_bitmap_info); } struct FontBitmapInfo *getFontBitmapInfo(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return &gfx.font_bitmap_info[font_bitmap_id]; } int getFontWidth(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].width; } int getFontHeight(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].height; } int getTextWidth(char *text, int font_nr) { return (text != NULL ? strlen(text) * getFontWidth(font_nr) : 0); } static int getFontCharPosition(int font_nr, char c) { int font_bitmap_id = gfx.select_font_function(font_nr); struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id]; boolean default_font = (font->num_chars == DEFAULT_NUM_CHARS_PER_FONT); int font_pos = (unsigned char)c - 32; /* map some special characters to their ascii values in default font */ if (default_font) font_pos = MAP_FONT_ASCII(c) - 32; /* this allows dynamic special characters together with special font */ if (font_pos < 0 || font_pos >= font->num_chars) font_pos = 0; return font_pos; } void getFontCharSource(int font_nr, char c, Bitmap **bitmap, int *x, int *y) { int font_bitmap_id = gfx.select_font_function(font_nr); struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id]; int font_pos = getFontCharPosition(font_nr, c); *bitmap = font->bitmap; *x = font->src_x + (font_pos % font->num_chars_per_line) * font->width; *y = font->src_y + (font_pos / font->num_chars_per_line) * font->height; } /* ========================================================================= */ /* text string helper functions */ /* ========================================================================= */ int maxWordLengthInString(char *text) { char *text_ptr; int max_word_len = 0; for (text_ptr = text; *text_ptr; text_ptr++) max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0); return max_word_len; } /* ========================================================================= */ /* simple text drawing functions */ /* ========================================================================= */ void DrawInitTextExt(char *text, int ypos, int font_nr, boolean force) { static unsigned long progress_delay = 0; unsigned long progress_delay_value = 100; /* (in milliseconds) */ UPDATE_BUSY_STATE(); if (!force && !DelayReached(&progress_delay, progress_delay_value)) return; if (window != NULL && gfx.draw_init_text && gfx.num_fonts > 0 && gfx.font_bitmap_info[font_nr].bitmap != NULL) { int x = (video.width - getTextWidth(text, font_nr)) / 2; int y = ypos; int width = video.width; int height = getFontHeight(font_nr); ClearRectangle(drawto, 0, y, width, height); DrawTextExt(drawto, x, y, text, font_nr, BLIT_OPAQUE); /* this makes things significantly faster than directly drawing to window */ BlitBitmap(drawto, window, 0, y, width, height, 0, y); } } void DrawInitText(char *text, int ypos, int font_nr) { DrawInitTextExt(text, ypos, font_nr, TRUE); } void DrawInitTextIfNeeded(char *text, int ypos, int font_nr) { DrawInitTextExt(text, ypos, font_nr, FALSE); } void DrawTextF(int x, int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; va_start(ap, format); vsprintf(buffer, format, ap); va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) Error(ERR_EXIT, "string too long in DrawTextF() -- aborting"); DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr); } void DrawTextFCentered(int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; va_start(ap, format); vsprintf(buffer, format, ap); va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting"); DrawText(gfx.sx + (gfx.sxsize - getTextWidth(buffer, font_nr)) / 2, gfx.sy + y, buffer, font_nr); } void DrawTextS(int x, int y, int font_nr, char *text) { DrawText(gfx.sx + x, gfx.sy + y, text, font_nr); } void DrawTextSCentered(int y, int font_nr, char *text) { DrawText(gfx.sx + (gfx.sxsize - getTextWidth(text, font_nr)) / 2, gfx.sy + y, text, font_nr); } void DrawTextCentered(int y, int font_nr, char *text) { DrawText((gfx.sxsize - getTextWidth(text, font_nr)) / 2, y, text, font_nr); } void DrawTextSAligned(int x, int y, char *text, int font_nr, int align) { DrawText(gfx.sx + ALIGNED_XPOS(x, getTextWidth(text, font_nr), align), gfx.sx + y, text, font_nr); } void DrawTextAligned(int x, int y, char *text, int font_nr, int align) { DrawText(ALIGNED_XPOS(x, getTextWidth(text, font_nr), align), y, text, font_nr); } void DrawText(int x, int y, char *text, int font_nr) { int mask_mode = BLIT_OPAQUE; if (DrawingOnBackground(x, y)) mask_mode = BLIT_ON_BACKGROUND; DrawTextExt(drawto, x, y, text, font_nr, mask_mode); if (x < gfx.dx) redraw_mask |= REDRAW_FIELD; else if (y < gfx.vy || gfx.vy == 0) redraw_mask |= REDRAW_DOOR_1; } void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text, int font_nr, int mask_mode) { #if 1 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); #else int font_bitmap_id = gfx.select_font_function(font_nr); struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id]; #endif int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); #if 0 int border_1 = gfx.sx + gfx.sxsize; int border_2 = gfx.dx + gfx.dxsize; int dst_x_start = dst_x; #endif Bitmap *src_bitmap; int src_x, src_y; char *text_ptr = text; if (font->bitmap == NULL) return; /* skip text to be printed outside the window (left/right will be clipped) */ if (dst_y < 0 || dst_y + font_height > video.height) return; /* add offset for drawing font characters */ dst_x += font->draw_xoffset; dst_y += font->draw_yoffset; while (*text_ptr) { char c = *text_ptr++; if (c == '\n') c = ' '; /* print space instead of newline */ getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y); /* clip text at the left side of the window */ if (dst_x < 0) { dst_x += font_width; continue; } /* clip text at the right side of the window */ #if 1 if (dst_x + font_width > video.width) break; #else /* (this does not work well when trying to print text to whole screen) */ if ((dst_x_start < border_1 && dst_x + font_width > border_1) || (dst_x_start < border_2 && dst_x + font_width > border_2)) break; #endif if (mask_mode == BLIT_INVERSE) /* special mode for text gadgets */ { /* first step: draw solid colored rectangle (use "cursor" character) */ if (strlen(text) == 1) /* only one char inverted => draw cursor */ { Bitmap *cursor_bitmap; int cursor_x, cursor_y; getFontCharSource(font_nr, FONT_ASCII_CURSOR, &cursor_bitmap, &cursor_x, &cursor_y); BlitBitmap(cursor_bitmap, dst_bitmap, cursor_x, cursor_y, font_width, font_height, dst_x, dst_y); } #if defined(TARGET_SDL) /* second step: draw masked inverted character */ SDLCopyInverseMasked(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); #else /* second step: draw masked black rectangle (use "space" character) */ SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, dst_bitmap, 0, 0, font_width, font_height, dst_x, dst_y); #endif } else if (mask_mode == BLIT_MASKED || mask_mode == BLIT_ON_BACKGROUND) { if (mask_mode == BLIT_ON_BACKGROUND) { /* clear font character background */ ClearRectangleOnBackground(dst_bitmap, dst_x, dst_y, font_width, font_height); } #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) /* use special font tile clipmasks */ { int font_pos = getFontCharPosition(font_nr, c); SetClipMask(src_bitmap, font_clip_gc, font->clip_mask[font_pos]); SetClipOrigin(src_bitmap, font_clip_gc, dst_x, dst_y); } #else SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); #endif BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); } else /* normal, non-masked font blitting */ { BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); } dst_x += font_width; } } /* ========================================================================= */ /* text buffer drawing functions */ /* ========================================================================= */ #define MAX_LINES_FROM_FILE 1024 char *GetTextBufferFromFile(char *filename, int max_lines) { FILE *file; char *buffer; int num_lines = 0; if (filename == NULL) return NULL; if (!(file = fopen(filename, MODE_READ))) return NULL; buffer = checked_calloc(1); /* start with valid, but empty text buffer */ while (!feof(file) && num_lines < max_lines) { char line[MAX_LINE_LEN]; /* read next line of input file */ if (!fgets(line, MAX_LINE_LEN, file)) break; buffer = checked_realloc(buffer, strlen(buffer) + strlen(line) + 1); strcat(buffer, line); num_lines++; } fclose(file); return buffer; } void DrawTextToTextArea_OLD(int x, int y, char *text, int font_nr, int line_length, int area_xsize, int area_ysize, int mask_mode) { int area_line = 0; int font_height = getFontHeight(font_nr); if (text == NULL) return; while (*text && area_line < area_ysize) { char buffer[MAX_OUTPUT_LINESIZE + 1]; int i; for (i = 0; i < line_length && *text; i++) if ((buffer[i] = *text++) == '\n') break; buffer[MIN(i, area_xsize)] = '\0'; DrawTextExt(drawto, x, y + area_line * font_height, buffer, font_nr, mask_mode); area_line++; } redraw_mask |= REDRAW_FIELD; } static boolean RenderLineToBuffer(char **src_buffer_ptr, char *dst_buffer, int *dst_buffer_len, int line_length, boolean last_line_was_empty) { char *text_ptr = *src_buffer_ptr; char *buffer = dst_buffer; int buffer_len = *dst_buffer_len; boolean buffer_filled = FALSE; while (*text_ptr) { char *word_ptr; int word_len; /* skip leading whitespaces */ while (*text_ptr == ' ' || *text_ptr == '\t') text_ptr++; word_ptr = text_ptr; word_len = 0; /* look for end of next word */ while (*word_ptr != ' ' && *word_ptr != '\t' && *word_ptr != '\0') { word_ptr++; word_len++; } if (word_len == 0) { continue; } else if (*text_ptr == '\n') /* special case: force empty line */ { if (buffer_len == 0) text_ptr++; /* prevent printing of multiple empty lines */ if (buffer_len > 0 || !last_line_was_empty) buffer_filled = TRUE; } else if (word_len < line_length - buffer_len) { /* word fits into text buffer -- add word */ if (buffer_len > 0) buffer[buffer_len++] = ' '; strncpy(&buffer[buffer_len], text_ptr, word_len); buffer_len += word_len; buffer[buffer_len] = '\0'; text_ptr += word_len; } else if (buffer_len > 0) { /* not enough space left for word in text buffer -- print buffer */ buffer_filled = TRUE; } else { /* word does not fit at all into empty text buffer -- cut word */ strncpy(buffer, text_ptr, line_length); buffer[line_length] = '\0'; text_ptr += line_length; buffer_filled = TRUE; } if (buffer_filled) break; } *src_buffer_ptr = text_ptr; *dst_buffer_len = buffer_len; return buffer_filled; } #if 0 void DrawTextWrapped_OLD(int x, int y, char *text, int font_nr, int line_length, int max_lines) { char *text_ptr = text; int current_line = 0; int font_height = getFontHeight(font_nr); while (*text_ptr && current_line < max_lines) { char buffer[line_length + 1]; int buffer_len = 0; buffer[0] = '\0'; RenderLineToBuffer(&text_ptr, buffer, &buffer_len, line_length, TRUE); DrawText(x, y + current_line * font_height, buffer, font_nr); current_line++; } } #endif #if 0 int DrawTextFromFile_OLD(int x, int y, char *filename, int font_nr, int line_length, int max_lines, boolean wrap_text) { int font_height = getFontHeight(font_nr); char line[MAX_LINE_LEN]; char buffer[line_length + 1]; int buffer_len; int current_line = 0; FILE *file; if (current_line >= max_lines) return 0; if (filename == NULL) return 0; if (!(file = fopen(filename, MODE_READ))) return 0; buffer[0] = '\0'; buffer_len = 0; while (!feof(file) && current_line < max_lines) { char *line_ptr; boolean last_line_was_empty = TRUE; /* read next line of input file */ if (!fgets(line, MAX_LINE_LEN, file)) break; /* skip comments (lines directly beginning with '#') */ if (line[0] == '#') continue; /* cut trailing newline from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '\n' || *line_ptr == '\r') { *line_ptr = '\0'; break; } } if (strlen(line) == 0) /* special case: force empty line */ strcpy(line, "\n"); line_ptr = line; while (*line_ptr && current_line < max_lines) { #if 1 boolean buffer_filled; if (wrap_text) { buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len, line_length, last_line_was_empty); } else { if (strlen(line_ptr) <= line_length) { buffer_len = strlen(line_ptr); strcpy(buffer, line_ptr); } else { buffer_len = line_length; strncpy(buffer, line_ptr, line_length); } buffer[buffer_len] = '\0'; line_ptr += buffer_len; buffer_filled = TRUE; } #else boolean buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len, line_length, last_line_was_empty); #endif if (buffer_filled) { DrawText(x, y + current_line * font_height, buffer, font_nr); current_line++; last_line_was_empty = (buffer_len == 0); buffer[0] = '\0'; buffer_len = 0; } } } fclose(file); if (buffer_len > 0 && current_line < max_lines) { DrawText(x, y + current_line * font_height, buffer, font_nr); current_line++; } return current_line; } #endif static boolean getCheckedTokenValueFromString(char *string, char **token, char **value) { char *ptr; if (!getTokenValueFromString(string, token, value)) return FALSE; if (**token != '.') /* token should begin with dot */ return FALSE; for (ptr = *token; *ptr; ptr++) /* token should contain no whitespace */ if (*ptr == ' ' || *ptr == '\t') return FALSE; for (ptr = *value; *ptr; ptr++) /* value should contain no whitespace */ if (*ptr == ' ' || *ptr == '\t') return FALSE; return TRUE; } static void DrawTextBuffer_Flush(int x, int y, char *buffer, int font_nr, int line_length, int cut_length, int line_spacing, int mask_mode, boolean centered, int current_line) { int buffer_len = strlen(buffer); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0); int offset_xsize = (centered ? font_width * (line_length - buffer_len) / 2 : 0); int final_cut_length = MAX(0, cut_length - offset_chars); int xx = x + offset_xsize; int yy = y + current_line * (font_height + line_spacing); buffer[final_cut_length] = '\0'; if (mask_mode != -1) DrawTextExt(drawto, xx, yy, buffer, font_nr, mask_mode); else DrawText(xx, yy, buffer, font_nr); } int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr, int line_length, int cut_length, int max_lines, int line_spacing, int mask_mode, boolean autowrap, boolean centered, boolean parse_comments) { #if 0 int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); #endif char buffer[line_length + 1]; int buffer_len; int current_line = 0; if (text_buffer == NULL || *text_buffer == '\0') return 0; if (current_line >= max_lines) return 0; if (cut_length == -1) cut_length = line_length; buffer[0] = '\0'; buffer_len = 0; while (*text_buffer && current_line < max_lines) { char line[MAX_LINE_LEN + 1]; char *line_ptr; boolean last_line_was_empty = TRUE; #if 1 int num_line_chars = MAX_LINE_LEN; #else int num_line_chars = (autowrap ? MAX_LINE_LEN : line_length); #endif int i; /* copy next line from text buffer to line buffer (nearly fgets() style) */ for (i = 0; i < num_line_chars && *text_buffer; i++) if ((line[i] = *text_buffer++) == '\n') break; line[i] = '\0'; /* prevent 'num_line_chars' sized lines to cause additional empty line */ if (i == num_line_chars && *text_buffer == '\n') text_buffer++; /* skip comments (lines directly beginning with '#') */ if (line[0] == '#' && parse_comments) { char *token, *value; /* try to read generic token/value pair definition after comment sign */ if (getCheckedTokenValueFromString(line + 1, &token, &value)) { /* if found, flush the current buffer, if non-empty */ if (buffer_len > 0 && current_line < max_lines) { DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, line_spacing, mask_mode, centered, current_line); current_line++; buffer[0] = '\0'; buffer_len = 0; } if (strEqual(token, ".font")) font_nr = gfx.get_font_from_token_function(value); else if (strEqual(token, ".autowrap")) autowrap = get_boolean_from_string(value); else if (strEqual(token, ".centered")) centered = get_boolean_from_string(value); else if (strEqual(token, ".parse_comments")) parse_comments = get_boolean_from_string(value); } continue; } /* cut trailing newline and carriage return from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '\n' || *line_ptr == '\r') { *line_ptr = '\0'; break; } } if (strlen(line) == 0) /* special case: force empty line */ strcpy(line, "\n"); line_ptr = line; while (*line_ptr && current_line < max_lines) { boolean buffer_filled; if (autowrap) { buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len, line_length, last_line_was_empty); } else { if (strlen(line_ptr) <= line_length) { buffer_len = strlen(line_ptr); strcpy(buffer, line_ptr); } else { buffer_len = line_length; strncpy(buffer, line_ptr, line_length); } buffer[buffer_len] = '\0'; line_ptr += buffer_len; buffer_filled = TRUE; } if (buffer_filled) { #if 1 DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, line_spacing, mask_mode, centered, current_line); #else int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0); int offset_xsize = (centered ? font_width * (line_length - buffer_len) / 2 : 0); int final_cut_length = MAX(0, cut_length - offset_chars); int xx = x + offset_xsize; buffer[final_cut_length] = '\0'; if (mask_mode != -1) DrawTextExt(drawto, xx, y + current_line * font_height, buffer, font_nr, mask_mode); else DrawText(xx, y + current_line * font_height, buffer, font_nr); #endif current_line++; last_line_was_empty = (buffer_len == 0); buffer[0] = '\0'; buffer_len = 0; } } } if (buffer_len > 0 && current_line < max_lines) { #if 1 DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, line_spacing, mask_mode, centered, current_line); #else int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0); int offset_xsize = (centered ? font_width * (line_length - buffer_len) / 2 : 0); int final_cut_length = MAX(0, cut_length - offset_chars); int xx = x + offset_xsize; buffer[final_cut_length] = '\0'; if (mask_mode != -1) DrawTextExt(drawto, xx, y + current_line * font_height, buffer, font_nr, mask_mode); else DrawText(xx, y + current_line * font_height, buffer, font_nr); #endif current_line++; } return current_line; } int DrawTextFile(int x, int y, char *filename, int font_nr, int line_length, int cut_length, int max_lines, int line_spacing, int mask_mode, boolean autowrap, boolean centered, boolean parse_comments) { char *text_buffer = GetTextBufferFromFile(filename, MAX_LINES_FROM_FILE); int num_lines_printed = DrawTextBuffer(x, y, text_buffer, font_nr, line_length, cut_length, max_lines, line_spacing, mask_mode, autowrap, centered, parse_comments); checked_free(text_buffer); return num_lines_printed; } #if 0 void DrawTextWrapped(int x, int y, char *text, int font_nr, int line_length, int max_lines) { DrawTextBuffer(x, y, text, font_nr, line_length, -1, max_lines, -1, TRUE, FALSE, FALSE); } void DrawTextToTextArea(int x, int y, char *text, int font_nr, int line_length, int cut_length, int max_lines, int mask_mode) { DrawTextBuffer(x, y, text, font_nr, line_length, cut_length, max_lines, mask_mode, FALSE, FALSE, FALSE); } #endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/image.h0000644000175000017500000000726410676275243020275 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * image.h * ***********************************************************/ #ifndef IMAGE_H #define IMAGE_H #include "system.h" #if defined(TARGET_X11) #define MAX_COLORS 256 /* maximal number of colors for each image */ typedef unsigned short Intensity; /* RGB intensity for X11 */ typedef struct { Display *display; /* destination display */ int depth; /* depth of destination drawable */ Pixel index[MAX_COLORS]; /* array of pixel values */ int no; /* number of pixels in the array */ Colormap cmap; /* colormap used for image */ Pixmap pixmap; /* final pixmap */ Pixmap pixmap_mask; /* final pixmap of mask */ } XImageInfo; struct RGBMap { unsigned int used; /* number of colors used in RGB map */ Intensity red[MAX_COLORS]; /* color values in X style */ Intensity green[MAX_COLORS]; Intensity blue[MAX_COLORS]; boolean color_used[MAX_COLORS]; /* flag if color cell is used */ }; typedef struct { unsigned int type; /* type of image (True-Color etc.) */ struct RGBMap rgb; /* RGB map of image if IRGB type */ unsigned int width; /* width of image in pixels */ unsigned int height; /* height of image in pixels */ unsigned int depth; /* depth of image in bits if IRGB type */ unsigned int bytes_per_pixel;/* (depth + 7) / 8 */ unsigned int bytes_per_row; /* width * bytes_per_pixel */ byte *data; /* image data */ } Image; #define IMAGETYPE_BITMAP 0 /* monochrome bitmap */ #define IMAGETYPE_RGB 1 /* RGB image with colormap */ #define IMAGETYPE_TRUECOLOR 2 /* true-color image */ #define TRUECOLOR_RED(pixel) (((unsigned long)((pixel) & 0xff0000)) >> 16) #define TRUECOLOR_GREEN(pixel) (((unsigned long)((pixel) & 0xff00)) >> 8) #define TRUECOLOR_BLUE(pixel) ( (unsigned long)((pixel) & 0xff)) #define RGB_TO_TRUECOLOR(r,g,b) ((((unsigned long)((r) & 0xff00)) << 8) | ((g) & 0xff00) | (((unsigned short)(b)) >> 8)) Image *newImage(unsigned int, unsigned int, unsigned int); void freeImage(Image *); void freeXImage(Image *, XImageInfo *); Pixmap Pixmap_to_Mask(Pixmap, int, int); void ZoomPixmap(Display *, GC, Pixmap, Pixmap, int, int, int, int); int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *); #endif /* TARGET_X11 */ int getImageListSize(); struct FileInfo *getImageListEntryFromImageID(int); Bitmap *getBitmapFromImageID(int); int getOriginalImageWidthFromImageID(int); int getOriginalImageHeightFromImageID(int); char *getTokenFromImageID(int); int getImageIDFromToken(char *); char *getImageConfigFilename(); int getImageListPropertyMappingSize(); struct PropertyMapping *getImageListPropertyMapping(); void InitImageList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void ReloadCustomImages(); void CreateImageWithSmallImages(int, int); void ScaleImage(int, int); void FreeAllImages(); #endif /* IMAGE_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/Makefile0000644000175000017500000000304611403523057020460 0ustar dimkadimka# ============================================================================= # Rocks'n'Diamonds Makefile (libgame) # ----------------------------------------------------------------------------- # (c) 1995-2006 Holger Schemel # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = system.c \ gadgets.c \ text.c \ sound.c \ joystick.c \ snapshot.c \ toons.c \ pcx.c \ image.c \ random.c \ hash.c \ setup.c \ misc.c \ msdos.c \ x11.c \ sdl.c OBJS = system.o \ gadgets.o \ text.o \ sound.o \ snapshot.o \ joystick.o \ toons.o \ pcx.o \ image.o \ random.o \ hash.o \ setup.o \ misc.o \ msdos.o \ x11.o \ sdl.o LIBGAME = libgame.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(LIBGAME) $(LIBGAME): $(OBJS) $(AR) cru $(LIBGAME) $(OBJS) $(RANLIB) $(LIBGAME) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(LIBGAME) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/macosx.h0000644000175000017500000000172110471574422020467 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * macosx.h * ***********************************************************/ #ifndef MACOSX_H #define MACOSX_H /* some symbols are already defined on Mac OS X */ #define Delay Delay_internal #define DrawLine DrawLine_internal #define DrawText DrawText_internal #define GetPixel GetPixel_internal #endif /* MACOSX_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/gadgets.c0000644000175000017500000017511011364306011020577 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * gadgets.c * ***********************************************************/ #include #include #include "gadgets.h" #include "text.h" #include "misc.h" /* values for DrawGadget() */ #define DG_UNPRESSED 0 #define DG_PRESSED 1 #define DG_BUFFERED 0 #define DG_DIRECT 1 static struct GadgetInfo *gadget_list_first_entry = NULL; static struct GadgetInfo *gadget_list_last_entry = NULL; static struct GadgetInfo *last_info_gi = NULL; static int next_free_gadget_id = 1; static boolean gadget_id_wrapped = FALSE; static void (*PlayGadgetSoundActivating)(void) = NULL; static void (*PlayGadgetSoundSelecting)(void) = NULL; void InitGadgetsSoundCallback(void (*activating_function)(void), void (*selecting_function)(void)) { PlayGadgetSoundActivating = activating_function; PlayGadgetSoundSelecting = selecting_function; } static struct GadgetInfo *getGadgetInfoFromGadgetID(int id) { struct GadgetInfo *gi = gadget_list_first_entry; while (gi && gi->id != id) gi = gi->next; return gi; } static int getNewGadgetID() { int id = next_free_gadget_id++; if (next_free_gadget_id <= 0) /* counter overrun */ { gadget_id_wrapped = TRUE; /* now we must check each ID */ next_free_gadget_id = 0; } if (gadget_id_wrapped) { next_free_gadget_id++; while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL) next_free_gadget_id++; } if (next_free_gadget_id <= 0) /* cannot get new gadget id */ Error(ERR_EXIT, "too much gadgets -- this should not happen"); return id; } static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my, int button) { struct GadgetInfo *gi; /* first check for scrollbars in case of mouse scroll wheel button events */ if (IS_WHEEL_BUTTON(button)) { /* real horizontal wheel or vertical wheel with modifier key pressed */ boolean check_horizontal = (IS_WHEEL_BUTTON_HORIZONTAL(button) || GetKeyModState() & KMOD_Shift); /* check for the first active scrollbar with matching mouse wheel area */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && ((gi->type & GD_TYPE_SCROLLBAR_HORIZONTAL && check_horizontal) || (gi->type & GD_TYPE_SCROLLBAR_VERTICAL && !check_horizontal)) && mx >= gi->wheelarea.x && mx < gi->wheelarea.x + gi->wheelarea.width && my >= gi->wheelarea.y && my < gi->wheelarea.y + gi->wheelarea.height) return gi; } /* no active scrollbar found -- ignore this scroll wheel button event */ return NULL; } /* open selectboxes may overlap other active gadgets, so check them first */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open && mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) return gi; } /* check all other gadgets */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height) return gi; } return NULL; } static void setTextAreaCursorExt(struct GadgetInfo *gi, boolean set_cursor_pos) { char *text = gi->textarea.value; int area_xsize = gi->textarea.xsize; int area_ysize = gi->textarea.ysize; int cursor_position = gi->textarea.cursor_position; int cursor_x = gi->textarea.cursor_x; int cursor_y = gi->textarea.cursor_y; int pos = 0; int x = 0; int y = 0; while (*text) { if (set_cursor_pos) /* x/y => position */ { if (y == cursor_y && (x == cursor_x || (x < cursor_x && *text == '\n'))) break; } else /* position => x/y */ { if (pos == cursor_position) break; } if (x + 1 >= area_xsize || *text == '\n') { if (y + 1 >= area_ysize) break; x = 0; y++; } else x++; text++; pos++; } gi->textarea.cursor_x = x; gi->textarea.cursor_y = y; gi->textarea.cursor_x_preferred = x; gi->textarea.cursor_position = pos; } static void setTextAreaCursorXY(struct GadgetInfo *gi, int x, int y) { gi->textarea.cursor_x = x; gi->textarea.cursor_y = y; setTextAreaCursorExt(gi, TRUE); } static void setTextAreaCursorPosition(struct GadgetInfo *gi, int pos) { gi->textarea.cursor_position = pos; setTextAreaCursorExt(gi, FALSE); } static void default_callback_info(void *ptr) { return; } static void default_callback_action(void *ptr) { return; } static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) { struct GadgetDesign *gd; int state = (pressed ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED); boolean redraw_selectbox = FALSE; if (gi == NULL) return; gd = (!gi->active ? &gi->alt_design[state] : gi->checked ? &gi->alt_design[state] : &gi->design[state]); switch (gi->type) { case GD_TYPE_NORMAL_BUTTON: case GD_TYPE_CHECK_BUTTON: case GD_TYPE_RADIO_BUTTON: BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->width, gi->height, gi->x, gi->y); if (gi->deco.design.bitmap) BlitBitmap(gi->deco.design.bitmap, drawto, gi->deco.design.x, gi->deco.design.y, gi->deco.width, gi->deco.height, gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0), gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0)); break; case GD_TYPE_TEXT_BUTTON: { int i; int font_nr = (gi->active ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int text_size = strlen(gi->textbutton.value); int text_start = (gi->width - text_size * font_width) / 2; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->textbutton.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* gadget text value */ DrawTextExt(drawto, gi->x + text_start + (pressed ? gi->deco.xshift : 0), gi->y + border_y + (pressed ? gi->deco.yshift : 0), gi->textbutton.value, font_nr, BLIT_MASKED); } break; case GD_TYPE_TEXT_INPUT_ALPHANUMERIC: case GD_TYPE_TEXT_INPUT_NUMERIC: { int i; char cursor_letter; char cursor_string[2]; char text[MAX_GADGET_TEXTSIZE + 1]; int font_nr = (pressed ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->textinput.size + 1; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* set text value */ strcpy(text, gi->textinput.value); strcat(text, " "); /* gadget text value */ DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); cursor_letter = gi->textinput.value[gi->textinput.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); cursor_string[1] = '\0'; /* draw cursor, if active */ if (pressed) DrawTextExt(drawto, gi->x + border_x + gi->textinput.cursor_position * font_width, gi->y + border_y, cursor_string, font_nr, BLIT_INVERSE); } break; case GD_TYPE_TEXT_AREA: { int i; char cursor_letter; char cursor_string[2]; int font_nr = (pressed ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int gd_height = 2 * border_y + font_height; /* top left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, border_y, gi->x, gi->y); /* top middle part of gadget border */ for (i=0; i < gi->textarea.xsize; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, border_y, gi->x + border_x + i * font_width, gi->y); /* top right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, border_y, gi->x + gi->width - border_x, gi->y); /* left and right part of gadget border for each row */ for (i=0; i < gi->textarea.ysize; i++) { BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y, border_x, font_height, gi->x, gi->y + border_y + i * font_height); BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + border_y, border_x, font_height, gi->x + gi->width - border_x, gi->y + border_y + i * font_height); } /* bottom left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gd_height - border_y, border_x, border_y, gi->x, gi->y + gi->height - border_y); /* bottom middle part of gadget border */ for (i=0; i < gi->textarea.xsize; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y + gd_height - border_y, font_width, border_y, gi->x + border_x + i * font_width, gi->y + gi->height - border_y); /* bottom right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + gd_height - border_y, border_x, border_y, gi->x + gi->width - border_x, gi->y + gi->height - border_y); ClearRectangleOnBackground(drawto, gi->x + border_x, gi->y + border_y, gi->width - 2 * border_x, gi->height - 2 * border_y); /* gadget text value */ #if 1 DrawTextBuffer(gi->x + border_x, gi->y + border_y, gi->textarea.value, font_nr, gi->textarea.xsize, 0, -1, gi->textarea.ysize, BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE); #else DrawTextToTextArea(gi->x + border_x, gi->y + border_y, gi->textarea.value, font_nr, gi->textarea.xsize, gi->textarea.xsize, gi->textarea.ysize, BLIT_ON_BACKGROUND); #endif cursor_letter = gi->textarea.value[gi->textarea.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); cursor_string[1] = '\0'; /* draw cursor, if active */ if (pressed) DrawTextExt(drawto, gi->x + border_x + gi->textarea.cursor_x * font_width, gi->y + border_y + gi->textarea.cursor_y * font_height, cursor_string, font_nr, BLIT_INVERSE); } break; case GD_TYPE_SELECTBOX: { int i; char text[MAX_GADGET_TEXTSIZE + 1]; int font_nr = (pressed ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int button = gi->border.xsize_selectbutton; int width_inner = gi->border.width - button - 2 * border_x; int box_width = gi->selectbox.width; int box_height = gi->selectbox.height; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* button part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y, button, gi->height, gi->x + gi->width - border_x - button, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* set text value */ strncpy(text, gi->selectbox.options[gi->selectbox.index].text, gi->selectbox.size); text[gi->selectbox.size] = '\0'; /* gadget text value */ DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); if (pressed) { if (!gi->selectbox.open) { gi->selectbox.open = TRUE; gi->selectbox.stay_open = FALSE; gi->selectbox.current_index = gi->selectbox.index; /* save background under selectbox */ BlitBitmap(drawto, gfx.field_save_buffer, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); } /* draw open selectbox */ /* top left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, border_y, gi->selectbox.x, gi->selectbox.y); /* top middle part of gadget border */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, border_y, gi->selectbox.x + border_x + i * font_width, gi->selectbox.y); /* top button part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y, button, border_y, gi->selectbox.x + box_width -border_x -button, gi->selectbox.y); /* top right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, border_y, gi->selectbox.x + box_width - border_x, gi->selectbox.y); /* left and right part of gadget border for each row */ for (i=0; i < gi->selectbox.num_values; i++) { BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y, border_x, font_height, gi->selectbox.x, gi->selectbox.y + border_y + i*font_height); BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + border_y, border_x, font_height, gi->selectbox.x + box_width - border_x, gi->selectbox.y + border_y + i*font_height); } /* bottom left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->height - border_y, border_x, border_y, gi->selectbox.x, gi->selectbox.y + box_height - border_y); /* bottom middle part of gadget border */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y + gi->height - border_y, font_width, border_y, gi->selectbox.x + border_x + i * font_width, gi->selectbox.y + box_height - border_y); /* bottom button part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y + gi->height - border_y, button, border_y, gi->selectbox.x + box_width -border_x -button, gi->selectbox.y + box_height - border_y); /* bottom right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + gi->height - border_y, border_x, border_y, gi->selectbox.x + box_width - border_x, gi->selectbox.y + box_height - border_y); ClearRectangleOnBackground(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y, gi->selectbox.width - 2 * border_x, gi->selectbox.height - 2 * border_y); /* selectbox text values */ for (i=0; i < gi->selectbox.num_values; i++) { int mask_mode = BLIT_MASKED; strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); text[gi->selectbox.size] = '\0'; if (i == gi->selectbox.current_index) { FillRectangle(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y + i * font_height, gi->selectbox.width - 2 * border_x, font_height, gi->selectbox.inverse_color); /* prevent use of cursor graphic by drawing at least two chars */ strcat(text, " "); text[gi->selectbox.size] = '\0'; mask_mode = BLIT_INVERSE; } DrawTextExt(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y + i * font_height, text, font_nr, mask_mode); } redraw_selectbox = TRUE; } else if (gi->selectbox.open) { gi->selectbox.open = FALSE; /* restore background under selectbox */ BlitBitmap(gfx.field_save_buffer, drawto, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); /* redraw closed selectbox */ DrawGadget(gi, FALSE, FALSE); redraw_selectbox = TRUE; } } break; case GD_TYPE_SCROLLBAR_VERTICAL: { int i; int xpos = gi->x; int ypos = gi->y + gi->scrollbar.position; int design_full = gi->width; int design_body = design_full - 2 * gi->border.ysize; int size_full = gi->scrollbar.size; int size_body = size_full - 2 * gi->border.ysize; int num_steps = size_body / design_body; int step_size_remain = size_body - num_steps * design_body; /* clear scrollbar area */ ClearRectangleOnBackground(backbuffer, gi->x, gi->y, gi->width, gi->height); /* upper part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->width, gi->border.ysize, xpos, ypos); /* middle part of gadget */ for (i=0; i < num_steps; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, design_body, xpos, ypos + gi->border.ysize + i * design_body); /* remaining middle part of gadget */ if (step_size_remain > 0) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, step_size_remain, xpos, ypos + gi->border.ysize + num_steps * design_body); /* lower part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + design_full - gi->border.ysize, gi->width, gi->border.ysize, xpos, ypos + size_full - gi->border.ysize); } break; case GD_TYPE_SCROLLBAR_HORIZONTAL: { int i; int xpos = gi->x + gi->scrollbar.position; int ypos = gi->y; int design_full = gi->height; int design_body = design_full - 2 * gi->border.xsize; int size_full = gi->scrollbar.size; int size_body = size_full - 2 * gi->border.xsize; int num_steps = size_body / design_body; int step_size_remain = size_body - num_steps * design_body; /* clear scrollbar area */ ClearRectangleOnBackground(backbuffer, gi->x, gi->y, gi->width, gi->height); /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->border.xsize, gi->height, xpos, ypos); /* middle part of gadget */ for (i=0; i < num_steps; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.xsize, gd->y, design_body, gi->height, xpos + gi->border.xsize + i * design_body, ypos); /* remaining middle part of gadget */ if (step_size_remain > 0) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.xsize, gd->y, step_size_remain, gi->height, xpos + gi->border.xsize + num_steps * design_body, ypos); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + design_full - gi->border.xsize, gd->y, gi->border.xsize, gi->height, xpos + size_full - gi->border.xsize, ypos); } break; default: return; } if (direct) { BlitBitmap(drawto, window, gi->x, gi->y, gi->width, gi->height, gi->x, gi->y); if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox) BlitBitmap(drawto, window, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); } else redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD : gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 : gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3); } static int get_minimal_size_for_numeric_input(int minmax_value) { int min_size = 1; /* value needs at least one digit */ int i; /* add number of digits needed for absolute value */ for (i = 10; i <= ABS(minmax_value); i *= 10) min_size++; /* if min/max value is negative, add one digit for minus sign */ if (minmax_value < 0) min_size++; return min_size; } static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { int tag = first_tag; if (gi == NULL) return; while (tag != GDI_END) { switch(tag) { case GDI_CUSTOM_ID: gi->custom_id = va_arg(ap, int); break; case GDI_CUSTOM_TYPE_ID: gi->custom_type_id = va_arg(ap, int); break; case GDI_INFO_TEXT: { int max_textsize = MAX_INFO_TEXTSIZE; char *text = va_arg(ap, char *); if (text != NULL) strncpy(gi->info_text, text, max_textsize); else max_textsize = 0; gi->info_text[max_textsize] = '\0'; } break; case GDI_X: gi->x = va_arg(ap, int); break; case GDI_Y: gi->y = va_arg(ap, int); break; case GDI_WIDTH: gi->width = va_arg(ap, int); break; case GDI_HEIGHT: gi->height = va_arg(ap, int); break; case GDI_TYPE: gi->type = va_arg(ap, unsigned int); break; case GDI_STATE: gi->state = va_arg(ap, unsigned int); break; case GDI_ACTIVE: gi->active = (boolean)va_arg(ap, int); break; case GDI_DIRECT_DRAW: gi->direct_draw = (boolean)va_arg(ap, int); break; case GDI_CHECKED: gi->checked = (boolean)va_arg(ap, int); break; case GDI_RADIO_NR: gi->radio_nr = va_arg(ap, unsigned int); break; case GDI_NUMBER_VALUE: gi->textinput.number_value = va_arg(ap, int); sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); gi->textinput.cursor_position = strlen(gi->textinput.value); break; case GDI_NUMBER_MIN: gi->textinput.number_min = va_arg(ap, int); if (gi->textinput.number_value < gi->textinput.number_min) { gi->textinput.number_value = gi->textinput.number_min; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); } break; case GDI_NUMBER_MAX: gi->textinput.number_max = va_arg(ap, int); if (gi->textinput.number_value > gi->textinput.number_max) { gi->textinput.number_value = gi->textinput.number_max; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); } break; case GDI_TEXT_VALUE: { int max_textsize = MAX_GADGET_TEXTSIZE; if (gi->textinput.size) max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE); strncpy(gi->textinput.value, va_arg(ap, char *), max_textsize); strcpy(gi->textinput.last_value, gi->textinput.value); gi->textinput.value[max_textsize] = '\0'; gi->textinput.cursor_position = strlen(gi->textinput.value); /* same tag also used for other gadget definitions */ strcpy(gi->textbutton.value, gi->textinput.value); strcpy(gi->textarea.value, gi->textinput.value); strcpy(gi->textarea.last_value, gi->textinput.value); } break; case GDI_TEXT_SIZE: { int tag_value = va_arg(ap, int); int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE); gi->textinput.size = max_textsize; gi->textinput.value[max_textsize] = '\0'; strcpy(gi->textinput.last_value, gi->textinput.value); /* same tag also used for other gadget definitions */ gi->textarea.size = max_textsize; gi->textarea.value[max_textsize] = '\0'; strcpy(gi->textarea.last_value, gi->textinput.value); gi->textbutton.size = max_textsize; gi->textbutton.value[max_textsize] = '\0'; gi->selectbox.size = gi->textinput.size; } break; case GDI_TEXT_FONT: gi->font = va_arg(ap, int); if (gi->font_active == 0) gi->font_active = gi->font; break; case GDI_TEXT_FONT_ACTIVE: gi->font_active = va_arg(ap, int); break; case GDI_SELECTBOX_OPTIONS: gi->selectbox.options = va_arg(ap, struct ValueTextInfo *); break; case GDI_SELECTBOX_INDEX: gi->selectbox.index = va_arg(ap, int); break; case GDI_DESIGN_UNPRESSED: gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *); gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int); gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int); break; case GDI_DESIGN_PRESSED: gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *); gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int); gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int); break; case GDI_ALT_DESIGN_UNPRESSED: gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *); gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int); gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int); break; case GDI_ALT_DESIGN_PRESSED: gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *); gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int); gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int); break; case GDI_BORDER_SIZE: gi->border.xsize = va_arg(ap, int); gi->border.ysize = va_arg(ap, int); break; case GDI_BORDER_SIZE_SELECTBUTTON: gi->border.xsize_selectbutton = va_arg(ap, int); break; case GDI_DESIGN_WIDTH: gi->border.width = va_arg(ap, int); break; case GDI_DECORATION_DESIGN: gi->deco.design.bitmap = va_arg(ap, Bitmap *); gi->deco.design.x = va_arg(ap, int); gi->deco.design.y = va_arg(ap, int); break; case GDI_DECORATION_POSITION: gi->deco.x = va_arg(ap, int); gi->deco.y = va_arg(ap, int); break; case GDI_DECORATION_SIZE: gi->deco.width = va_arg(ap, int); gi->deco.height = va_arg(ap, int); break; case GDI_DECORATION_SHIFTING: gi->deco.xshift = va_arg(ap, int); gi->deco.yshift = va_arg(ap, int); break; case GDI_EVENT_MASK: gi->event_mask = va_arg(ap, unsigned int); break; case GDI_AREA_SIZE: gi->drawing.area_xsize = va_arg(ap, int); gi->drawing.area_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ if (gi->width == 0 && gi->height == 0 && gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 && gi->width != 0 && gi->height != 0) { gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize; gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize; } /* same tag also used for other gadget definitions */ gi->textarea.xsize = gi->drawing.area_xsize; gi->textarea.ysize = gi->drawing.area_ysize; if (gi->type & GD_TYPE_TEXT_AREA) /* force recalculation */ { gi->width = 0; gi->height = 0; } break; case GDI_ITEM_SIZE: gi->drawing.item_xsize = va_arg(ap, int); gi->drawing.item_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ if (gi->width == 0 && gi->height == 0 && gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 && gi->width != 0 && gi->height != 0) { gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize; gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize; } break; case GDI_SCROLLBAR_ITEMS_MAX: gi->scrollbar.items_max = va_arg(ap, int); break; case GDI_SCROLLBAR_ITEMS_VISIBLE: gi->scrollbar.items_visible = va_arg(ap, int); break; case GDI_SCROLLBAR_ITEM_POSITION: gi->scrollbar.item_position = va_arg(ap, int); break; case GDI_WHEEL_AREA_X: gi->wheelarea.x = va_arg(ap, int); break; case GDI_WHEEL_AREA_Y: gi->wheelarea.y = va_arg(ap, int); break; case GDI_WHEEL_AREA_WIDTH: gi->wheelarea.width = va_arg(ap, int); break; case GDI_WHEEL_AREA_HEIGHT: gi->wheelarea.height = va_arg(ap, int); break; case GDI_CALLBACK_INFO: gi->callback_info = va_arg(ap, gadget_function); break; case GDI_CALLBACK_ACTION: gi->callback_action = va_arg(ap, gadget_function); break; default: Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag); } tag = va_arg(ap, int); /* read next tag */ } /* check if gadget is complete */ if (gi->type != GD_TYPE_DRAWING_AREA && (!gi->design[GD_BUTTON_UNPRESSED].bitmap || !gi->design[GD_BUTTON_PRESSED].bitmap)) Error(ERR_EXIT, "gadget incomplete (missing Bitmap)"); /* adjust gadget values in relation to other gadget values */ if (gi->type & GD_TYPE_TEXT_INPUT) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; if (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC) { int number_min = gi->textinput.number_min; int number_max = gi->textinput.number_max; int min_size_min = get_minimal_size_for_numeric_input(number_min); int min_size_max = get_minimal_size_for_numeric_input(number_max); int min_size = MAX(min_size_min, min_size_max); /* expand gadget text input size, if maximal value is too large */ if (gi->textinput.size < min_size) gi->textinput.size = min_size; } gi->width = 2 * border_xsize + (gi->textinput.size + 1) * font_width; gi->height = 2 * border_ysize + font_height; } if (gi->type & GD_TYPE_SELECTBOX) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; int button_size = gi->border.xsize_selectbutton; int bottom_screen_border = gfx.sy + gfx.sysize - font_height; Bitmap *src_bitmap; int src_x, src_y; gi->width = 2 * border_xsize + gi->textinput.size*font_width +button_size; gi->height = 2 * border_ysize + font_height; if (gi->selectbox.options == NULL) Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)"); gi->selectbox.num_values = 0; while (gi->selectbox.options[gi->selectbox.num_values].text != NULL) gi->selectbox.num_values++; /* calculate values for open selectbox */ gi->selectbox.width = gi->width; gi->selectbox.height = 2 * border_ysize + gi->selectbox.num_values * font_height; gi->selectbox.x = gi->x; gi->selectbox.y = gi->y + gi->height; if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border) gi->selectbox.y = gi->y - gi->selectbox.height; if (gi->selectbox.y < 0) gi->selectbox.y = bottom_screen_border - gi->selectbox.height; getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y); src_x += font_width / 2; src_y += font_height / 2; /* there may be esoteric cases with missing or too small font bitmap */ if (src_bitmap != NULL && src_x < src_bitmap->width && src_y < src_bitmap->height) gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y); /* always start with closed selectbox */ gi->selectbox.open = FALSE; } if (gi->type & GD_TYPE_TEXT_INPUT_NUMERIC) { struct GadgetTextInput *text = &gi->textinput; int value = text->number_value; text->number_value = (value < text->number_min ? text->number_min : value > text->number_max ? text->number_max : value); sprintf(text->value, "%d", text->number_value); } if (gi->type & GD_TYPE_TEXT_BUTTON) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; gi->width = 2 * border_xsize + gi->textbutton.size * font_width; gi->height = 2 * border_ysize + font_height; } if (gi->type & GD_TYPE_SCROLLBAR) { struct GadgetScrollbar *gs = &gi->scrollbar; int scrollbar_size_cmp; if (gi->width == 0 || gi->height == 0 || gs->items_max == 0 || gs->items_visible == 0) Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)"); /* calculate internal scrollbar values */ gs->size_min = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? gi->width : gi->height); gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? gi->height : gi->width); scrollbar_size_cmp = gs->size_max * gs->items_visible / gs->items_max; gs->size = MAX(scrollbar_size_cmp, gs->size_min); gs->size_max_cmp = (gs->size_max - (gs->size - scrollbar_size_cmp)); gs->position = gs->size_max_cmp * gs->item_position / gs->items_max; gs->position_max = gs->size_max - gs->size; gs->correction = gs->size_max / gs->items_max / 2; /* finetuning for maximal right/bottom position */ if (gs->item_position == gs->items_max - gs->items_visible) gs->position = gs->position_max; } if (gi->type & GD_TYPE_TEXT_AREA) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; if (gi->width == 0 || gi->height == 0) { gi->width = 2 * border_xsize + gi->textarea.xsize * font_width; gi->height = 2 * border_ysize + gi->textarea.ysize * font_height; } else { gi->textarea.xsize = (gi->width - 2 * border_xsize) / font_width; gi->textarea.ysize = (gi->height - 2 * border_ysize) / font_height; } } } void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...) { va_list ap; va_start(ap, first_tag); HandleGadgetTags(gi, first_tag, ap); va_end(ap); RedrawGadget(gi); } void RedrawGadget(struct GadgetInfo *gi) { if (gi == NULL) return; if (gi->mapped) DrawGadget(gi, gi->state, gi->direct_draw); } struct GadgetInfo *CreateGadget(int first_tag, ...) { struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo)); va_list ap; /* always start with reliable default values */ new_gadget->id = getNewGadgetID(); new_gadget->callback_info = default_callback_info; new_gadget->callback_action = default_callback_action; new_gadget->active = TRUE; new_gadget->direct_draw = TRUE; new_gadget->next = NULL; va_start(ap, first_tag); HandleGadgetTags(new_gadget, first_tag, ap); va_end(ap); /* insert new gadget into global gadget list */ if (gadget_list_last_entry) { gadget_list_last_entry->next = new_gadget; gadget_list_last_entry = gadget_list_last_entry->next; } else gadget_list_first_entry = gadget_list_last_entry = new_gadget; return new_gadget; } void FreeGadget(struct GadgetInfo *gi) { struct GadgetInfo *gi_previous = gadget_list_first_entry; /* prevent "last_info_gi" from pointing to memory that will be freed */ if (last_info_gi == gi) last_info_gi = NULL; while (gi_previous != NULL && gi_previous->next != gi) gi_previous = gi_previous->next; if (gi == gadget_list_first_entry) gadget_list_first_entry = gi->next; if (gi == gadget_list_last_entry) gadget_list_last_entry = gi_previous; if (gi_previous != NULL) gi_previous->next = gi->next; free(gi); } static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi) { if (gi->type != GD_TYPE_TEXT_INPUT_NUMERIC) return; gi->textinput.number_value = atoi(gi->textinput.value); if (gi->textinput.number_value < gi->textinput.number_min) gi->textinput.number_value = gi->textinput.number_min; if (gi->textinput.number_value > gi->textinput.number_max) gi->textinput.number_value = gi->textinput.number_max; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); if (gi->textinput.cursor_position < 0) gi->textinput.cursor_position = 0; else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) gi->textinput.cursor_position = strlen(gi->textinput.value); } /* global pointer to gadget actually in use (when mouse button pressed) */ static struct GadgetInfo *last_gi = NULL; static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw) { if (gi == NULL || gi->mapped) return; gi->mapped = TRUE; if (redraw) DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED); } void MapGadget(struct GadgetInfo *gi) { MapGadgetExt(gi, TRUE); } void UnmapGadget(struct GadgetInfo *gi) { if (gi == NULL || !gi->mapped) return; gi->mapped = FALSE; if (gi == last_gi) last_gi = NULL; } #define MAX_NUM_GADGETS 1024 #define MULTIMAP_UNMAP (1 << 0) #define MULTIMAP_REMAP (1 << 1) #define MULTIMAP_REDRAW (1 << 2) #define MULTIMAP_PLAYFIELD (1 << 3) #define MULTIMAP_DOOR_1 (1 << 4) #define MULTIMAP_DOOR_2 (1 << 5) #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \ MULTIMAP_DOOR_1 | \ MULTIMAP_DOOR_2) static void MultiMapGadgets(int mode) { struct GadgetInfo *gi = gadget_list_first_entry; static boolean map_state[MAX_NUM_GADGETS]; int map_count = 0; while (gi != NULL) { if ((mode & MULTIMAP_PLAYFIELD && gi->x < gfx.sx + gfx.sxsize) || (mode & MULTIMAP_DOOR_1 && gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) || (mode & MULTIMAP_DOOR_2 && gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) || (mode & MULTIMAP_ALL) == MULTIMAP_ALL) { if (mode & MULTIMAP_UNMAP) { map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped; UnmapGadget(gi); } else { if (map_state[map_count++ % MAX_NUM_GADGETS]) MapGadgetExt(gi, (mode & MULTIMAP_REDRAW)); } } gi = gi->next; } } void UnmapAllGadgets() { MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP); } void RemapAllGadgets() { MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP); } boolean anyTextInputGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_TEXT_INPUT) && last_gi->mapped); } boolean anyTextAreaGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_TEXT_AREA) && last_gi->mapped); } boolean anySelectboxGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped); } boolean anyScrollbarGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_SCROLLBAR) && last_gi->mapped); } boolean anyTextGadgetActive() { return (anyTextInputGadgetActive() || anyTextAreaGadgetActive() || anySelectboxGadgetActive()); } static boolean insideSelectboxLine(struct GadgetInfo *gi, int mx, int my) { return(gi != NULL && gi->type & GD_TYPE_SELECTBOX && mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height); } static boolean insideSelectboxArea(struct GadgetInfo *gi, int mx, int my) { return(gi != NULL && gi->type & GD_TYPE_SELECTBOX && mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height); } void ClickOnGadget(struct GadgetInfo *gi, int button) { if (!gi->mapped) return; /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); /* simulate pressing mouse button over specified gadget */ HandleGadgets(gi->x, gi->y, button); /* simulate releasing mouse button over specified gadget */ HandleGadgets(gi->x, gi->y, 0); } boolean HandleGadgets(int mx, int my, int button) { static unsigned long pressed_delay = 0; static unsigned long pressed_delay_value = GADGET_FRAME_DELAY; static int last_button = 0; static int last_mx = 0, last_my = 0; static int pressed_mx = 0, pressed_my = 0; static boolean keep_selectbox_open = FALSE; static boolean gadget_stopped = FALSE; int scrollbar_mouse_pos = 0; struct GadgetInfo *new_gi, *gi; boolean press_event; boolean release_event; boolean mouse_moving; boolean mouse_inside_select_line; boolean mouse_inside_select_area; boolean mouse_released_where_pressed; boolean gadget_pressed; boolean gadget_pressed_repeated; boolean gadget_pressed_off_borders; boolean gadget_pressed_inside_select_line; boolean gadget_pressed_delay_reached; boolean gadget_moving; boolean gadget_moving_inside; boolean gadget_moving_off_borders; boolean gadget_draggable; boolean gadget_dragging; boolean gadget_released; boolean gadget_released_inside; boolean gadget_released_inside_select_line; boolean gadget_released_inside_select_area; boolean gadget_released_off_borders; boolean changed_position = FALSE; /* check if there are any gadgets defined */ if (gadget_list_first_entry == NULL) return FALSE; /* simulated release of mouse button over last gadget */ if (mx == -1 && my == -1 && button == 0) { mx = last_mx; my = last_my; } /* check which gadget is under the mouse pointer */ new_gi = getGadgetInfoFromMousePosition(mx, my, button); /* check if button state has changed since last invocation */ press_event = (button != 0 && last_button == 0); release_event = (button == 0 && last_button != 0); last_button = button; /* check if mouse has been moved since last invocation */ mouse_moving = ((mx != last_mx || my != last_my) && motion_status); last_mx = mx; last_my = my; if (press_event && new_gi != last_gi) { pressed_mx = mx; pressed_my = my; } mouse_released_where_pressed = (release_event && mx == pressed_mx && my == pressed_my); mouse_inside_select_line = insideSelectboxLine(new_gi, mx, my); mouse_inside_select_area = insideSelectboxArea(new_gi, mx, my); gadget_pressed_off_borders = (press_event && new_gi != last_gi); gadget_pressed_inside_select_line = (press_event && new_gi != NULL && new_gi->type & GD_TYPE_SELECTBOX && new_gi->selectbox.open && insideSelectboxLine(new_gi, mx, my)); /* if mouse button pressed outside text or selectbox gadget, deactivate it */ if (anyTextGadgetActive() && (gadget_pressed_off_borders || (gadget_pressed_inside_select_line && !mouse_inside_select_area))) { struct GadgetInfo *gi = last_gi; boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_LEAVING) != 0); /* check if text gadget has changed its value */ if (gi->type & GD_TYPE_TEXT_INPUT) { CheckRangeOfNumericInputGadget(gi); if (!strEqual(gi->textinput.last_value, gi->textinput.value)) strcpy(gi->textinput.last_value, gi->textinput.value); else gadget_changed = FALSE; } /* selectbox does not change its value when closed by clicking outside */ if (gi->type & GD_TYPE_SELECTBOX) gadget_changed = FALSE; DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->event.type = GD_EVENT_TEXT_LEAVING; if (gadget_changed && !(gi->type & GD_TYPE_SELECTBOX)) gi->callback_action(gi); last_gi = NULL; if (gadget_pressed_inside_select_line) new_gi = NULL; } gadget_pressed = (button != 0 && last_gi == NULL && new_gi != NULL && press_event); gadget_pressed_repeated = (button != 0 && last_gi != NULL && new_gi == last_gi); gadget_pressed_delay_reached = DelayReached(&pressed_delay, pressed_delay_value); gadget_released = (release_event && last_gi != NULL); gadget_released_inside = (gadget_released && new_gi == last_gi); gadget_released_off_borders = (gadget_released && new_gi != last_gi); gadget_moving = (button != 0 && last_gi != NULL && mouse_moving); gadget_moving_inside = (gadget_moving && new_gi == last_gi); gadget_moving_off_borders = (gadget_moving && new_gi != last_gi); /* when handling selectbox, set additional state values */ if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX)) { gadget_released_inside_select_line = insideSelectboxLine(last_gi, mx, my); gadget_released_inside_select_area = insideSelectboxArea(last_gi, mx, my); } else { gadget_released_inside_select_line = FALSE; gadget_released_inside_select_area = FALSE; } /* setting state for handling over-large selectbox */ if (keep_selectbox_open && (press_event || !mouse_inside_select_line)) keep_selectbox_open = FALSE; /* if new gadget pressed, store this gadget */ if (gadget_pressed) last_gi = new_gi; /* 'gi' is actually handled gadget */ gi = last_gi; /* if gadget is scrollbar, choose mouse position value */ if (gi && gi->type & GD_TYPE_SCROLLBAR) scrollbar_mouse_pos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y); /* if mouse button released, no gadget needs to be handled anymore */ if (gadget_released) { if (gi->type & GD_TYPE_SELECTBOX && (keep_selectbox_open || mouse_released_where_pressed || !gadget_released_inside_select_area)) /* selectbox stays open */ { gi->selectbox.stay_open = TRUE; pressed_mx = 0; pressed_my = 0; } else if (!(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ last_gi = NULL; } /* modify event position values even if no gadget is pressed */ if (button == 0 && !release_event) gi = new_gi; /* if new gadget or if no gadget was pressed, release stopped processing */ if (gadget_pressed || new_gi == NULL) gadget_stopped = FALSE; /* if gadget was stopped while being handled, stop gadget processing here */ if (gadget_stopped) return TRUE; if (gi != NULL) { int last_x = gi->event.x; int last_y = gi->event.y; gi->event.x = mx - gi->x; gi->event.y = my - gi->y; if (gi->type == GD_TYPE_DRAWING_AREA) { gi->event.x /= gi->drawing.item_xsize; gi->event.y /= gi->drawing.item_ysize; if (last_x != gi->event.x || last_y != gi->event.y) changed_position = TRUE; } else if (gi->type & GD_TYPE_TEXT_INPUT && button != 0 && !motion_status) { int old_cursor_position = gi->textinput.cursor_position; /* if mouse button pressed inside activated text gadget, set cursor */ gi->textinput.cursor_position = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); if (gi->textinput.cursor_position < 0) gi->textinput.cursor_position = 0; else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) gi->textinput.cursor_position = strlen(gi->textinput.value); if (gi->textinput.cursor_position != old_cursor_position) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_TEXT_AREA && button != 0 && !motion_status) { int old_cursor_position = gi->textarea.cursor_position; int x = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); int y = (my - gi->y - gi->border.ysize) / getFontHeight(gi->font); x = (x < 0 ? 0 : x >= gi->textarea.xsize ? gi->textarea.xsize - 1 : x); y = (y < 0 ? 0 : y >= gi->textarea.ysize ? gi->textarea.ysize - 1 : y); setTextAreaCursorXY(gi, x, y); if (gi->textarea.cursor_position != old_cursor_position) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open && !keep_selectbox_open) { int old_index = gi->selectbox.current_index; /* if mouse moving inside activated selectbox, select value */ if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) gi->selectbox.current_index = (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font); if (gi->selectbox.current_index < 0) gi->selectbox.current_index = 0; else if (gi->selectbox.current_index > gi->selectbox.num_values - 1) gi->selectbox.current_index = gi->selectbox.num_values - 1; if (gi->selectbox.current_index != old_index) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } /* handle gadget popup info text */ if (last_info_gi != new_gi || (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position)) { if (new_gi != NULL && (button == 0 || new_gi == last_gi)) { new_gi->event.type = GD_EVENT_INFO_ENTERING; new_gi->callback_info(new_gi); } else if (last_info_gi != NULL) { last_info_gi->event.type = GD_EVENT_INFO_LEAVING; last_info_gi->callback_info(last_info_gi); } last_info_gi = new_gi; } gadget_draggable = (gi && gi->type & GD_TYPE_SCROLLBAR); /* reset drag position for newly pressed scrollbar to "not dragging" */ if (gadget_pressed && gadget_draggable) gi->scrollbar.drag_position = -1; gadget_dragging = (gadget_draggable && gi->scrollbar.drag_position != -1); /* clicking next to a scrollbar to move it is not considered "moving" */ if (gadget_draggable && !gadget_dragging) gadget_moving = FALSE; /* when leaving scrollbar area when jump-scrolling, stop gadget processing */ if (gadget_draggable && !gadget_dragging && gadget_moving_off_borders) gadget_stopped = TRUE; if ((gadget_pressed) || (gadget_pressed_repeated && gadget_pressed_delay_reached)) { if (gadget_pressed) /* gadget pressed the first time */ { /* initialize delay counter */ DelayReached(&pressed_delay, 0); /* start gadget delay with longer delay after first click on gadget */ pressed_delay_value = GADGET_FRAME_DELAY_FIRST; } else /* gadget hold pressed for some time */ { /* after first repeated gadget click, continue with shorter delay value */ pressed_delay_value = GADGET_FRAME_DELAY; } if (gi->type & GD_TYPE_SCROLLBAR && !gadget_dragging) { int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx : my); int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y); int slider_start = gpos + gi->scrollbar.position; int slider_end = gpos + gi->scrollbar.position + gi->scrollbar.size - 1; boolean inside_slider = (mpos >= slider_start && mpos <= slider_end); if (IS_WHEEL_BUTTON(button) || !inside_slider) { /* click scrollbar one scrollbar length up/left or down/right */ struct GadgetScrollbar *gs = &gi->scrollbar; int old_item_position = gs->item_position; int item_steps = gs->items_visible - 1; int item_direction = (mpos < gpos + gi->scrollbar.position ? -1 : +1); if (IS_WHEEL_BUTTON(button)) { boolean scroll_single_step = ((GetKeyModState() & KMOD_Alt) != 0); item_steps = (scroll_single_step ? 1 : DEFAULT_WHEEL_STEPS); item_direction = (button == MB_WHEEL_UP || button == MB_WHEEL_LEFT ? -1 : +1); } changed_position = FALSE; gs->item_position += item_steps * item_direction; if (gs->item_position < 0) gs->item_position = 0; else if (gs->item_position > gs->items_max - gs->items_visible) gs->item_position = gs->items_max - gs->items_visible; if (old_item_position != gs->item_position) { gi->event.item_position = gs->item_position; changed_position = TRUE; } ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position, GDI_END); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_MOVING; gi->event.off_borders = FALSE; if (gi->event_mask & GD_EVENT_MOVING && changed_position) gi->callback_action(gi); return TRUE; } else { /* don't handle this scrollbar anymore when mouse position reached */ if (gadget_pressed_repeated) { gadget_stopped = TRUE; return TRUE; } } } } if (gadget_pressed) { PlayGadgetSoundActivating(); if (gi->type == GD_TYPE_CHECK_BUTTON) { gi->checked = !gi->checked; } else if (gi->type == GD_TYPE_RADIO_BUTTON) { struct GadgetInfo *rgi = gadget_list_first_entry; while (rgi) { if (rgi->mapped && rgi->type == GD_TYPE_RADIO_BUTTON && rgi->radio_nr == gi->radio_nr && rgi != gi) { rgi->checked = FALSE; DrawGadget(rgi, DG_UNPRESSED, rgi->direct_draw); } rgi = rgi->next; } gi->checked = TRUE; } else if (gi->type & GD_TYPE_SCROLLBAR) { int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx : my); int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y); int slider_start = gpos + gi->scrollbar.position; int slider_end = gpos + gi->scrollbar.position + gi->scrollbar.size - 1; boolean inside_slider = (mpos >= slider_start && mpos <= slider_end); if (!IS_WHEEL_BUTTON(button) && inside_slider) { /* start dragging scrollbar */ gi->scrollbar.drag_position = scrollbar_mouse_pos - gi->scrollbar.position; } } else if (gi->type & GD_TYPE_SELECTBOX) { /* keep selectbox open in case of over-large selectbox */ keep_selectbox_open = (mouse_inside_select_line && mouse_inside_select_area); } DrawGadget(gi, DG_PRESSED, gi->direct_draw); gi->state = GD_BUTTON_PRESSED; gi->event.type = GD_EVENT_PRESSED; gi->event.button = button; gi->event.off_borders = FALSE; if (gi->event_mask & GD_EVENT_PRESSED) gi->callback_action(gi); } if (gadget_pressed_repeated) { gi->event.type = GD_EVENT_PRESSED; if (gi->event_mask & GD_EVENT_REPEATED && gadget_pressed_delay_reached) gi->callback_action(gi); } if (gadget_moving) { if (gi->type & GD_TYPE_BUTTON) { if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED) DrawGadget(gi, DG_PRESSED, gi->direct_draw); else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED) DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_SELECTBOX && !keep_selectbox_open) { int old_index = gi->selectbox.current_index; /* if mouse moving inside activated selectbox, select value */ if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) gi->selectbox.current_index = (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font); if (gi->selectbox.current_index < 0) gi->selectbox.current_index = 0; else if (gi->selectbox.current_index > gi->selectbox.num_values - 1) gi->selectbox.current_index = gi->selectbox.num_values - 1; if (gi->selectbox.current_index != old_index) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_SCROLLBAR) { struct GadgetScrollbar *gs = &gi->scrollbar; int old_item_position = gs->item_position; gs->position = scrollbar_mouse_pos - gs->drag_position; /* make sure to always precisely reach end positions when dragging */ if (gs->position <= 0) { gs->position = 0; gs->item_position = 0; } else if (gs->position >= gs->position_max) { gs->position = gs->position_max; gs->item_position = gs->items_max - gs->items_visible; } else { gs->item_position = gs->items_max * (gs->position + gs->correction) / gs->size_max_cmp; } if (gs->item_position < 0) gs->item_position = 0; if (gs->item_position > gs->items_max - 1) gs->item_position = gs->items_max - 1; if (old_item_position != gs->item_position) { gi->event.item_position = gs->item_position; changed_position = TRUE; } DrawGadget(gi, DG_PRESSED, gi->direct_draw); } gi->state = (gadget_moving_inside || gadget_draggable ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED); gi->event.type = GD_EVENT_MOVING; gi->event.off_borders = gadget_moving_off_borders; if (gi->event_mask & GD_EVENT_MOVING && changed_position && (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS)) gi->callback_action(gi); } if (gadget_released_inside) { boolean deactivate_gadget = TRUE; boolean gadget_changed = TRUE; if (gi->type & GD_TYPE_SELECTBOX) { if (keep_selectbox_open || mouse_released_where_pressed || !gadget_released_inside_select_area) /* selectbox stays open */ { deactivate_gadget = FALSE; gadget_changed = FALSE; } else if (gi->selectbox.index != gi->selectbox.current_index) gi->selectbox.index = gi->selectbox.current_index; else gadget_changed = FALSE; } if (deactivate_gadget && !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_RELEASED; if ((gi->event_mask & GD_EVENT_RELEASED) && gadget_changed) { gi->callback_action(gi); } } if (gadget_released_off_borders) { if (gi->type & GD_TYPE_SCROLLBAR) DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_RELEASED; if (gi->event_mask & GD_EVENT_RELEASED && gi->event_mask & GD_EVENT_OFF_BORDERS) gi->callback_action(gi); } /* handle gadgets unmapped/mapped between pressing and releasing */ if (release_event && !gadget_released && new_gi) new_gi->state = GD_BUTTON_UNPRESSED; return (gadget_pressed || gadget_pressed_repeated || gadget_released || gadget_moving); } static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) { char text[MAX_GADGET_TEXTSIZE + 1]; int cursor_position = gi->textarea.cursor_position; if (strlen(gi->textarea.value) >= MAX_GADGET_TEXTSIZE) /* no space left */ return; strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_position + 1], &text[cursor_position]); gi->textarea.value[cursor_position] = c; setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); } boolean HandleGadgetsKeyInput(Key key) { struct GadgetInfo *gi = last_gi; if (gi == NULL || !gi->mapped || !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA || gi->type & GD_TYPE_SELECTBOX)) return FALSE; if (key == KSYM_Return) /* valid for both text input and selectbox */ { boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_RETURN) != 0); if (gi->type & GD_TYPE_TEXT_INPUT) { CheckRangeOfNumericInputGadget(gi); if (!strEqual(gi->textinput.last_value, gi->textinput.value)) strcpy(gi->textinput.last_value, gi->textinput.value); else gadget_changed = FALSE; } else if (gi->type & GD_TYPE_SELECTBOX) { if (gi->selectbox.index != gi->selectbox.current_index) gi->selectbox.index = gi->selectbox.current_index; else gadget_changed = FALSE; } if (gi->type & GD_TYPE_TEXT_AREA) { insertCharIntoTextArea(gi, '\n'); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else { DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->event.type = GD_EVENT_TEXT_RETURN; last_gi = NULL; } if (gadget_changed) gi->callback_action(gi); } else if (gi->type & GD_TYPE_TEXT_INPUT) /* only valid for text input */ { char text[MAX_GADGET_TEXTSIZE + 1]; int text_length = strlen(gi->textinput.value); int cursor_pos = gi->textinput.cursor_position; char letter = getCharFromKey(key); boolean legal_letter = (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC ? letter >= '0' && letter <= '9' : letter != 0); if (legal_letter && text_length < gi->textinput.size) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos + 1], &text[cursor_pos]); gi->textinput.value[cursor_pos] = letter; gi->textinput.cursor_position++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Left && cursor_pos > 0) { gi->textinput.cursor_position--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Right && cursor_pos < text_length) { gi->textinput.cursor_position++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_BackSpace && cursor_pos > 0) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos - 1], &text[cursor_pos]); gi->textinput.cursor_position--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Delete && cursor_pos < text_length) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos], &text[cursor_pos + 1]); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } else if (gi->type & GD_TYPE_TEXT_AREA) /* only valid for text area */ { char text[MAX_GADGET_TEXTSIZE + 1]; int text_length = strlen(gi->textarea.value); int area_ysize = gi->textarea.ysize; int cursor_x_pref = gi->textarea.cursor_x_preferred; int cursor_y = gi->textarea.cursor_y; int cursor_pos = gi->textarea.cursor_position; char letter = getCharFromKey(key); boolean legal_letter = (letter != 0); if (legal_letter) { insertCharIntoTextArea(gi, letter); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Left && cursor_pos > 0) { setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Right && cursor_pos < text_length) { setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Up && cursor_y > 0) { setTextAreaCursorXY(gi, cursor_x_pref, cursor_y - 1); gi->textarea.cursor_x_preferred = cursor_x_pref; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Down && cursor_y < area_ysize - 1) { setTextAreaCursorXY(gi, cursor_x_pref, cursor_y + 1); gi->textarea.cursor_x_preferred = cursor_x_pref; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_BackSpace && cursor_pos > 0) { strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_pos - 1], &text[cursor_pos]); setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Delete && cursor_pos < text_length) { strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_pos], &text[cursor_pos + 1]); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */ { int index = gi->selectbox.current_index; int num_values = gi->selectbox.num_values; if (key == KSYM_Up && index > 0) { gi->selectbox.current_index--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Down && index < num_values - 1) { gi->selectbox.current_index++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } return TRUE; } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/libgame.h0000644000175000017500000000211411337610722020566 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * libgame.h * ***********************************************************/ #ifndef LIBGAME_H #define LIBGAME_H #define LIBGAME_VERSION_1_0_0 #include "platform.h" #include "types.h" #include "system.h" #include "random.h" #include "gadgets.h" #include "text.h" #include "sound.h" #include "snapshot.h" #include "joystick.h" #include "toons.h" #include "image.h" #include "pcx.h" #include "setup.h" #include "misc.h" #endif /* LIBGAME_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/pcx.c0000644000175000017500000002017710471575143017771 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * pcx.c * ***********************************************************/ #ifndef TARGET_SDL #include #include "pcx.h" #include "misc.h" #define PCX_DEBUG 0 #define PCX_MAGIC 0x0a /* first byte in a PCX image file */ #define PCX_SUPPORTED_VERSION 5 /* last acceptable version number */ #define PCX_ENCODING 1 /* PCX encoding method */ #define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */ #define PCX_MAXCOLORS 256 /* maximum number of colors */ #define PCX_HEADER_SIZE 128 #define PCX_COLORMAP_SIZE (3 * PCX_MAXCOLORS) struct PCX_Header { unsigned char signature; /* PCX file identifier */ unsigned char version; /* version compatibility level */ unsigned char encoding; /* encoding method */ unsigned char bits_per_pixel; /* bits per pixel (not depth!) */ unsigned short xmin; /* X position of left edge */ unsigned short ymin; /* Y position of top edge */ unsigned short xmax; /* X position of right edge */ unsigned short ymax; /* Y position of bottom edge */ unsigned short hres; /* X screen resolution of source image */ unsigned short vres; /* Y screen resolution of source image */ unsigned char palette[16][3]; /* PCX color map */ unsigned char reserved; /* should be 0, 1 if std res fax */ unsigned char color_planes; /* "color planes" in image */ unsigned short bytes_per_line;/* byte delta between scanlines */ unsigned short palette_type; /* 0 = undef, 1 = color, 2 = grayscale */ unsigned char filler[58]; /* fill to struct size of 128 */ }; /* global PCX error value */ int errno_pcx = PCX_Success; static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image) { int width = image->width; int height = image->height; int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; int bytes_per_row = pcx->color_planes * pcx->bytes_per_line; byte *row_buffer = checked_malloc(bytes_per_row); byte *bitmap_ptr = image->data; int y; for (y = 0; y < height; y++) { /* decode a scan line into a temporary buffer first */ byte *dst_ptr = (pcx_depth == 8 ? bitmap_ptr : row_buffer); byte value = 0, count = 0; int value_int; int i; for (i = 0; i < bytes_per_row; i++) { if (count == 0) { if ((value_int = fgetc(file)) == EOF) { free(row_buffer); return FALSE; } value = (byte)value_int; if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ { count = value & 0x3f; /* extract repeat count from byte */ if ((value_int = fgetc(file)) == EOF) { free(row_buffer); return FALSE; } value = (byte)value_int; } else count = 1; } dst_ptr[i] = value; count--; if (pcx_depth == 8) image->rgb.color_used[value] = TRUE; } if (pcx_depth <= 4) /* expand planes to 1 byte/pixel */ { byte *src_ptr = row_buffer; int plane; for (plane = 0; plane < pcx->color_planes; plane++) { int i, j, x = 0; for (i = 0; i < pcx->bytes_per_line; i++) { byte value = *src_ptr++; for (j = 7; j >= 0; j--) { byte bit = (value >> j) & 1; if (i * 8 + j >= width) /* skip padding bits */ continue; bitmap_ptr[x++] |= bit << plane; } } } } else if (pcx_depth == 24) /* de-interlace planes */ { byte *src_ptr = row_buffer; int plane; for (plane = 0; plane < pcx->color_planes; plane++) { int x; dst_ptr = bitmap_ptr + plane; for (x = 0; x < width; x++) { *dst_ptr = *src_ptr++; dst_ptr += pcx->color_planes; } } } bitmap_ptr += image->bytes_per_row; } free(row_buffer); return TRUE; } static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) { int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; int num_colors = (1 << pcx_depth); int i; if (image->depth != 8) return TRUE; if (pcx_depth == 8) { byte value; int value_int; /* look for a 256-colour palette */ do { if ((value_int = fgetc(file)) == EOF) return FALSE; value = (byte)value_int; } while (value != PCX_256COLORS_MAGIC); /* read 256 colors from PCX colormap */ for (i = 0; i < PCX_MAXCOLORS; i++) { image->rgb.red[i] = (byte)fgetc(file) << 8; image->rgb.green[i] = (byte)fgetc(file) << 8; image->rgb.blue[i] = (byte)fgetc(file) << 8; } } else { for (i = 0; i < num_colors; i++) { image->rgb.red[i] = pcx->palette[i][0] << 8; image->rgb.green[i] = pcx->palette[i][1] << 8; image->rgb.blue[i] = pcx->palette[i][2] << 8; } } return TRUE; } Image *Read_PCX_to_Image(char *filename) { FILE *file; byte header_buffer[PCX_HEADER_SIZE]; struct PCX_Header pcx; Image *image; int width, height, depth, pcx_depth; int i; errno_pcx = PCX_Success; if (!(file = fopen(filename, MODE_READ))) { errno_pcx = PCX_OpenFailed; return NULL; } if (fread(header_buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE) { fclose(file); errno_pcx = PCX_ReadFailed; return NULL; } pcx.signature = header_buffer[0]; pcx.version = header_buffer[1]; pcx.encoding = header_buffer[2]; pcx.bits_per_pixel = header_buffer[3]; pcx.xmin = (header_buffer[5] << 8) | header_buffer[4]; pcx.ymin = (header_buffer[7] << 8) | header_buffer[6]; pcx.xmax = (header_buffer[9] << 8) | header_buffer[8]; pcx.ymax = (header_buffer[11] << 8) | header_buffer[10]; pcx.color_planes = header_buffer[65]; pcx.bytes_per_line = (header_buffer[67] << 8) | header_buffer[66]; pcx.palette_type = (header_buffer[69] << 8) | header_buffer[68]; for (i = 0; i < 48; i++) pcx.palette[i / 3][i % 3] = header_buffer[16 + i]; width = pcx.xmax - pcx.xmin + 1; height = pcx.ymax - pcx.ymin + 1; pcx_depth = pcx.bits_per_pixel * pcx.color_planes; depth = ((pcx_depth + 7) / 8) * 8; if (pcx.signature != PCX_MAGIC || pcx.version != PCX_SUPPORTED_VERSION || pcx.encoding != PCX_ENCODING || width < 0 || height < 0) { fclose(file); errno_pcx = PCX_FileInvalid; return NULL; } #if PCX_DEBUG if (options.verbose) { printf("\n"); printf("%s is a %dx%d PC Paintbrush image\n", filename, width, height); printf("depth: %d\n", depth); printf("bits_per_pixel: %d\n", pcx.bits_per_pixel); printf("color_planes: %d\n", pcx.color_planes); printf("bytes_per_line: %d\n", pcx.bytes_per_line); printf("palette type: %s\n", (pcx.palette_type == 1 ? "color" : pcx.palette_type == 2 ? "grayscale" : "undefined")); } #endif /* allocate new image structure */ image = newImage(width, height, depth); /* read compressed bitmap data */ if (!PCX_ReadBitmap(file, &pcx, image)) { fclose(file); freeImage(image); errno_pcx = PCX_FileInvalid; return NULL; } /* read colormap data */ if (!PCX_ReadColormap(file, &pcx, image)) { fclose(file); freeImage(image); errno_pcx = PCX_ColorFailed; return NULL; } fclose(file); if (pcx_depth == 8) { /* determine number of used colormap entries for 8-bit PCX images */ for (i = 0; i < PCX_MAXCOLORS; i++) if (image->rgb.color_used[i]) image->rgb.used++; } #if PCX_DEBUG if (options.verbose) printf("Read_PCX_to_Image: %d colors in colormap\n", image->rgb.used); #endif return image; } #endif /* !TARGET_SDL */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/misc.c0000644000175000017500000024730711375102256020133 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * misc.c * ***********************************************************/ #include #include #include #include #include #include #include #include #include "platform.h" #if !defined(PLATFORM_WIN32) #include #include #endif #include "misc.h" #include "setup.h" #include "random.h" #include "text.h" #include "image.h" /* ========================================================================= */ /* some generic helper functions */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* platform independent wrappers for printf() et al. (newline aware) */ /* ------------------------------------------------------------------------- */ static void vfprintf_newline(FILE *stream, char *format, va_list ap) { char *newline = STRING_NEWLINE; vfprintf(stream, format, ap); fprintf(stream, "%s", newline); } static void fprintf_newline(FILE *stream, char *format, ...) { if (format) { va_list ap; va_start(ap, format); vfprintf_newline(stream, format, ap); va_end(ap); } } void fprintf_line(FILE *stream, char *line_chars, int line_length) { int i; for (i = 0; i < line_length; i++) fprintf(stream, "%s", line_chars); fprintf_newline(stream, ""); } void printf_line(char *line_chars, int line_length) { fprintf_line(stdout, line_chars, line_length); } void printf_line_with_prefix(char *prefix, char *line_chars, int line_length) { fprintf(stdout, "%s", prefix); fprintf_line(stdout, line_chars, line_length); } /* ------------------------------------------------------------------------- */ /* string functions */ /* ------------------------------------------------------------------------- */ /* int2str() returns a number converted to a string; the used memory is static, but will be overwritten by later calls, so if you want to save the result, copy it to a private string buffer; there can be 10 local calls of int2str() without buffering the result -- the 11th call will then destroy the result from the first call and so on. */ char *int2str(int number, int size) { static char shift_array[10][40]; static int shift_counter = 0; char *s = shift_array[shift_counter]; shift_counter = (shift_counter + 1) % 10; if (size > 20) size = 20; if (size > 0) { sprintf(s, " %09d", number); return &s[strlen(s) - size]; } else { sprintf(s, "%d", number); return s; } } /* something similar to "int2str()" above, but allocates its own memory and has a different interface; we cannot use "itoa()", because this seems to be already defined when cross-compiling to the win32 target */ char *i_to_a(unsigned int i) { static char *a = NULL; checked_free(a); if (i > 2147483647) /* yes, this is a kludge */ i = 2147483647; a = checked_malloc(10 + 1); sprintf(a, "%d", i); return a; } /* calculate base-2 logarithm of argument (rounded down to integer; this function returns the number of the highest bit set in argument) */ int log_2(unsigned int x) { int e = 0; while ((1 << e) < x) { x -= (1 << e); /* for rounding down (rounding up: remove this line) */ e++; } return e; } boolean getTokenValueFromString(char *string, char **token, char **value) { return getTokenValueFromSetupLine(string, token, value); } /* ------------------------------------------------------------------------- */ /* counter functions */ /* ------------------------------------------------------------------------- */ #if defined(PLATFORM_MSDOS) volatile unsigned long counter = 0; void increment_counter() { counter++; } END_OF_FUNCTION(increment_counter); #endif /* maximal allowed length of a command line option */ #define MAX_OPTION_LEN 256 #if 1 #ifdef TARGET_SDL static unsigned long getCurrentMS() { return SDL_GetTicks(); } #else /* !TARGET_SDL */ #if defined(PLATFORM_UNIX) static unsigned long getCurrentMS() { struct timeval current_time; gettimeofday(¤t_time, NULL); return current_time.tv_sec * 1000 + current_time.tv_usec / 1000; } #endif /* PLATFORM_UNIX */ #endif /* !TARGET_SDL */ static unsigned long mainCounter(int mode) { static unsigned long base_ms = 0; unsigned long current_ms; /* get current system milliseconds */ current_ms = getCurrentMS(); /* reset base timestamp in case of counter reset or wrap-around */ if (mode == INIT_COUNTER || current_ms < base_ms) base_ms = current_ms; /* return milliseconds since last counter reset */ return current_ms - base_ms; } #else #ifdef TARGET_SDL static unsigned long mainCounter(int mode) { static unsigned long base_ms = 0; unsigned long current_ms; unsigned long counter_ms; current_ms = SDL_GetTicks(); /* reset base time in case of counter initializing or wrap-around */ if (mode == INIT_COUNTER || current_ms < base_ms) base_ms = current_ms; counter_ms = current_ms - base_ms; return counter_ms; /* return milliseconds since last init */ } #else /* !TARGET_SDL */ #if defined(PLATFORM_UNIX) static unsigned long mainCounter(int mode) { static struct timeval base_time = { 0, 0 }; struct timeval current_time; unsigned long counter_ms; gettimeofday(¤t_time, NULL); /* reset base time in case of counter initializing or wrap-around */ if (mode == INIT_COUNTER || current_time.tv_sec < base_time.tv_sec) base_time = current_time; counter_ms = (current_time.tv_sec - base_time.tv_sec) * 1000 + (current_time.tv_usec - base_time.tv_usec) / 1000; return counter_ms; /* return milliseconds since last init */ } #endif /* PLATFORM_UNIX */ #endif /* !TARGET_SDL */ #endif void InitCounter() /* set counter back to zero */ { #if !defined(PLATFORM_MSDOS) mainCounter(INIT_COUNTER); #else LOCK_VARIABLE(counter); LOCK_FUNCTION(increment_counter); install_int_ex(increment_counter, BPS_TO_TIMER(100)); #endif } unsigned long Counter() /* get milliseconds since last call of InitCounter() */ { #if !defined(PLATFORM_MSDOS) return mainCounter(READ_COUNTER); #else return (counter * 10); #endif } static void sleep_milliseconds(unsigned long milliseconds_delay) { boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE); if (do_busy_waiting) { /* we want to wait only a few ms -- if we assume that we have a kernel timer resolution of 10 ms, we would wait far to long; therefore it's better to do a short interval of busy waiting to get our sleeping time more accurate */ unsigned long base_counter = Counter(), actual_counter = Counter(); while (actual_counter < base_counter + milliseconds_delay && actual_counter >= base_counter) actual_counter = Counter(); } else { #if defined(TARGET_SDL) SDL_Delay(milliseconds_delay); #elif defined(TARGET_ALLEGRO) rest(milliseconds_delay); #else struct timeval delay; delay.tv_sec = milliseconds_delay / 1000; delay.tv_usec = 1000 * (milliseconds_delay % 1000); if (select(0, NULL, NULL, NULL, &delay) != 0) Error(ERR_WARN, "sleep_milliseconds(): select() failed"); #endif } } void Delay(unsigned long delay) /* Sleep specified number of milliseconds */ { sleep_milliseconds(delay); } boolean FrameReached(unsigned long *frame_counter_var, unsigned long frame_delay) { unsigned long actual_frame_counter = FrameCounter; if (actual_frame_counter >= *frame_counter_var && actual_frame_counter < *frame_counter_var + frame_delay) return FALSE; *frame_counter_var = actual_frame_counter; return TRUE; } boolean DelayReached(unsigned long *counter_var, unsigned long delay) { unsigned long actual_counter = Counter(); if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) return FALSE; *counter_var = actual_counter; return TRUE; } void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) { unsigned long actual_counter; while (1) { actual_counter = Counter(); if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) sleep_milliseconds((*counter_var + delay - actual_counter) / 2); else break; } *counter_var = actual_counter; } /* ------------------------------------------------------------------------- */ /* random generator functions */ /* ------------------------------------------------------------------------- */ unsigned int init_random_number(int nr, long seed) { if (seed == NEW_RANDOMIZE) { /* default random seed */ seed = (long)time(NULL); // seconds since the epoch #if !defined(PLATFORM_WIN32) /* add some more randomness */ struct timeval current_time; gettimeofday(¤t_time, NULL); seed += (long)current_time.tv_usec; // microseconds since the epoch #endif #if defined(TARGET_SDL) /* add some more randomness */ seed += (long)SDL_GetTicks(); // milliseconds since SDL init #endif #if 1 /* add some more randomness */ seed += GetSimpleRandom(1000000); #endif } srandom_linux_libc(nr, (unsigned int) seed); return (unsigned int) seed; } unsigned int get_random_number(int nr, int max) { return (max > 0 ? random_linux_libc(nr) % max : 0); } /* ------------------------------------------------------------------------- */ /* system info functions */ /* ------------------------------------------------------------------------- */ #if !defined(PLATFORM_MSDOS) static char *get_corrected_real_name(char *real_name) { char *real_name_new = checked_malloc(MAX_USERNAME_LEN + 1); char *from_ptr = real_name; char *to_ptr = real_name_new; /* copy the name string, but not more than MAX_USERNAME_LEN characters */ while (*from_ptr && (long)(to_ptr - real_name_new) < MAX_USERNAME_LEN - 1) { /* the name field read from "passwd" file may also contain additional user information, separated by commas, which will be removed here */ if (*from_ptr == ',') break; /* the user's real name may contain 'ß' characters (german sharp s), which have no equivalent in upper case letters (used by our fonts) */ if (*from_ptr == 'ß') { from_ptr++; *to_ptr++ = 's'; *to_ptr++ = 's'; } else *to_ptr++ = *from_ptr++; } *to_ptr = '\0'; return real_name_new; } #endif char *getLoginName() { static char *login_name = NULL; #if defined(PLATFORM_WIN32) if (login_name == NULL) { unsigned long buffer_size = MAX_USERNAME_LEN + 1; login_name = checked_malloc(buffer_size); if (GetUserName(login_name, &buffer_size) == 0) strcpy(login_name, ANONYMOUS_NAME); } #else if (login_name == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) == NULL) login_name = ANONYMOUS_NAME; else login_name = getStringCopy(pwd->pw_name); } #endif return login_name; } char *getRealName() { static char *real_name = NULL; #if defined(PLATFORM_WIN32) if (real_name == NULL) { static char buffer[MAX_USERNAME_LEN + 1]; unsigned long buffer_size = MAX_USERNAME_LEN + 1; if (GetUserName(buffer, &buffer_size) != 0) real_name = get_corrected_real_name(buffer); else real_name = ANONYMOUS_NAME; } #elif defined(PLATFORM_UNIX) if (real_name == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) != NULL && strlen(pwd->pw_gecos) != 0) real_name = get_corrected_real_name(pwd->pw_gecos); else real_name = ANONYMOUS_NAME; } #else real_name = ANONYMOUS_NAME; #endif return real_name; } time_t getFileTimestampEpochSeconds(char *filename) { struct stat file_status; if (stat(filename, &file_status) != 0) /* cannot stat file */ return 0; return file_status.st_mtime; } /* ------------------------------------------------------------------------- */ /* path manipulation functions */ /* ------------------------------------------------------------------------- */ static char *getLastPathSeparatorPtr(char *filename) { char *last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_UNIX); if (last_separator == NULL) /* also try DOS/Windows variant */ last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_DOS); return last_separator; } char *getBaseNamePtr(char *filename) { char *last_separator = getLastPathSeparatorPtr(filename); if (last_separator != NULL) return last_separator + 1; /* separator found: strip base path */ else return filename; /* no separator found: filename has no path */ } char *getBaseName(char *filename) { return getStringCopy(getBaseNamePtr(filename)); } char *getBasePath(char *filename) { char *basepath = getStringCopy(filename); char *last_separator = getLastPathSeparatorPtr(basepath); if (last_separator != NULL) *last_separator = '\0'; /* separator found: strip basename */ else basepath = "."; /* no separator found: use current path */ return basepath; } /* ------------------------------------------------------------------------- */ /* various string functions */ /* ------------------------------------------------------------------------- */ char *getStringCat2WithSeparator(char *s1, char *s2, char *sep) { char *complete_string = checked_malloc(strlen(s1) + strlen(sep) + strlen(s2) + 1); sprintf(complete_string, "%s%s%s", s1, sep, s2); return complete_string; } char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep) { char *complete_string = checked_malloc(strlen(s1) + strlen(sep) + strlen(s2) + strlen(sep) + strlen(s3) + 1); sprintf(complete_string, "%s%s%s%s%s", s1, sep, s2, sep, s3); return complete_string; } char *getStringCat2(char *s1, char *s2) { return getStringCat2WithSeparator(s1, s2, ""); } char *getStringCat3(char *s1, char *s2, char *s3) { return getStringCat3WithSeparator(s1, s2, s3, ""); } char *getPath2(char *path1, char *path2) { return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR); } char *getPath3(char *path1, char *path2, char *path3) { return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR); } char *getStringCopy(char *s) { char *s_copy; if (s == NULL) return NULL; s_copy = checked_malloc(strlen(s) + 1); strcpy(s_copy, s); return s_copy; } char *getStringCopyN(char *s, int n) { char *s_copy; int s_len = MAX(0, n); if (s == NULL) return NULL; s_copy = checked_malloc(s_len + 1); strncpy(s_copy, s, s_len); s_copy[s_len] = '\0'; return s_copy; } char *getStringToLower(char *s) { char *s_copy = checked_malloc(strlen(s) + 1); char *s_ptr = s_copy; while (*s) *s_ptr++ = tolower(*s++); *s_ptr = '\0'; return s_copy; } void setString(char **old_value, char *new_value) { checked_free(*old_value); *old_value = getStringCopy(new_value); } boolean strEqual(char *s1, char *s2) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : s1 != NULL && s2 == NULL ? FALSE : strcmp(s1, s2) == 0); } boolean strEqualN(char *s1, char *s2, int n) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : s1 != NULL && s2 == NULL ? FALSE : strncmp(s1, s2, n) == 0); } boolean strPrefix(char *s, char *prefix) { return (s == NULL && prefix == NULL ? TRUE : s == NULL && prefix != NULL ? FALSE : s != NULL && prefix == NULL ? FALSE : strncmp(s, prefix, strlen(prefix)) == 0); } boolean strSuffix(char *s, char *suffix) { return (s == NULL && suffix == NULL ? TRUE : s == NULL && suffix != NULL ? FALSE : s != NULL && suffix == NULL ? FALSE : strlen(s) < strlen(suffix) ? FALSE : strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0); } boolean strPrefixLower(char *s, char *prefix) { char *s_lower = getStringToLower(s); boolean match = strPrefix(s_lower, prefix); free(s_lower); return match; } boolean strSuffixLower(char *s, char *suffix) { char *s_lower = getStringToLower(s); boolean match = strSuffix(s_lower, suffix); free(s_lower); return match; } /* ------------------------------------------------------------------------- */ /* command line option handling functions */ /* ------------------------------------------------------------------------- */ void GetOptions(char *argv[], void (*print_usage_function)(void)) { char *ro_base_path = RO_BASE_PATH; char *rw_base_path = RW_BASE_PATH; char **options_left = &argv[1]; #if !defined(PLATFORM_MACOSX) /* if the program is configured to start from current directory (default), determine program package directory (KDE/Konqueror does not do this by itself and fails otherwise); on Mac OS X, the program binary is stored in an application package directory -- do not try to use this directory as the program data directory (Mac OS X handles this correctly anyway) */ if (strEqual(ro_base_path, ".")) ro_base_path = program.command_basepath; if (strEqual(rw_base_path, ".")) rw_base_path = program.command_basepath; #endif /* initialize global program options */ options.display_name = NULL; options.server_host = NULL; options.server_port = 0; options.ro_base_directory = ro_base_path; options.rw_base_directory = rw_base_path; options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY); options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY); options.sounds_directory = getPath2(ro_base_path, SOUNDS_DIRECTORY); options.music_directory = getPath2(ro_base_path, MUSIC_DIRECTORY); options.docs_directory = getPath2(ro_base_path, DOCS_DIRECTORY); options.execute_command = NULL; options.special_flags = NULL; options.serveronly = FALSE; options.network = FALSE; options.verbose = FALSE; options.debug = FALSE; options.debug_x11_sync = FALSE; #if !defined(PLATFORM_UNIX) if (*options_left == NULL) /* no options given -- enable verbose mode */ options.verbose = TRUE; #endif while (*options_left) { char option_str[MAX_OPTION_LEN]; char *option = options_left[0]; char *next_option = options_left[1]; char *option_arg = NULL; int option_len = strlen(option); if (option_len >= MAX_OPTION_LEN) Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); strcpy(option_str, option); /* copy argument into buffer */ option = option_str; if (strEqual(option, "--")) /* stop scanning arguments */ break; if (strPrefix(option, "--")) /* treat '--' like '-' */ option++; option_arg = strchr(option, '='); if (option_arg == NULL) /* no '=' in option */ option_arg = next_option; else { *option_arg++ = '\0'; /* cut argument from option */ if (*option_arg == '\0') /* no argument after '=' */ Error(ERR_EXIT_HELP, "option '%s' has invalid argument", option_str); } option_len = strlen(option); if (strEqual(option, "-")) Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); else if (strncmp(option, "-help", option_len) == 0) { print_usage_function(); exit(0); } else if (strncmp(option, "-display", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.display_name = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-basepath", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); /* this should be extended to separate options for ro and rw data */ options.ro_base_directory = ro_base_path = option_arg; options.rw_base_directory = rw_base_path = option_arg; if (option_arg == next_option) options_left++; /* adjust paths for sub-directories in base directory accordingly */ options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY); options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY); options.sounds_directory = getPath2(ro_base_path, SOUNDS_DIRECTORY); options.music_directory = getPath2(ro_base_path, MUSIC_DIRECTORY); options.docs_directory = getPath2(ro_base_path, DOCS_DIRECTORY); } else if (strncmp(option, "-levels", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.level_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-graphics", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.graphics_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-sounds", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.sounds_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-music", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.music_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-network", option_len) == 0) { options.network = TRUE; } else if (strncmp(option, "-serveronly", option_len) == 0) { options.serveronly = TRUE; } else if (strncmp(option, "-verbose", option_len) == 0) { options.verbose = TRUE; } else if (strncmp(option, "-debug", option_len) == 0) { options.debug = TRUE; } else if (strncmp(option, "-debug-x11-sync", option_len) == 0) { options.debug_x11_sync = TRUE; } else if (strPrefix(option, "-D")) { #if 1 options.special_flags = getStringCopy(&option[2]); #else char *flags_string = &option[2]; unsigned long flags_value; if (*flags_string == '\0') Error(ERR_EXIT_HELP, "empty flag ignored"); flags_value = get_special_flags_function(flags_string); if (flags_value == 0) Error(ERR_EXIT_HELP, "unknown flag '%s'", flags_string); options.special_flags |= flags_value; #endif } else if (strncmp(option, "-execute", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.execute_command = option_arg; if (option_arg == next_option) options_left++; /* when doing batch processing, always enable verbose mode (warnings) */ options.verbose = TRUE; } else if (*option == '-') { Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str); } else if (options.server_host == NULL) { options.server_host = *options_left; } else if (options.server_port == 0) { options.server_port = atoi(*options_left); if (options.server_port < 1024) Error(ERR_EXIT_HELP, "bad port number '%d'", options.server_port); } else Error(ERR_EXIT_HELP, "too many arguments"); options_left++; } } /* ------------------------------------------------------------------------- */ /* error handling functions */ /* ------------------------------------------------------------------------- */ /* used by SetError() and GetError() to store internal error messages */ static char internal_error[1024]; /* this is bad */ void SetError(char *format, ...) { va_list ap; va_start(ap, format); vsprintf(internal_error, format, ap); va_end(ap); } char *GetError() { return internal_error; } void Error(int mode, char *format, ...) { static boolean last_line_was_separator = FALSE; char *process_name = ""; /* display warnings only when running in verbose mode */ if (mode & ERR_WARN && !options.verbose) return; if (mode == ERR_INFO_LINE) { if (!last_line_was_separator) fprintf_line(program.error_file, format, 79); last_line_was_separator = TRUE; return; } last_line_was_separator = FALSE; if (mode & ERR_SOUND_SERVER) process_name = " sound server"; else if (mode & ERR_NETWORK_SERVER) process_name = " network server"; else if (mode & ERR_NETWORK_CLIENT) process_name = " network client **"; if (format) { va_list ap; fprintf(program.error_file, "%s%s: ", program.command_basename, process_name); if (mode & ERR_WARN) fprintf(program.error_file, "warning: "); va_start(ap, format); vfprintf_newline(program.error_file, format, ap); va_end(ap); } if (mode & ERR_HELP) fprintf_newline(program.error_file, "%s: Try option '--help' for more information.", program.command_basename); if (mode & ERR_EXIT) fprintf_newline(program.error_file, "%s%s: aborting", program.command_basename, process_name); if (mode & ERR_EXIT) { if (mode & ERR_FROM_SERVER) exit(1); /* child process: normal exit */ else program.exit_function(1); /* main process: clean up stuff */ } } /* ------------------------------------------------------------------------- */ /* checked memory allocation and freeing functions */ /* ------------------------------------------------------------------------- */ void *checked_malloc(unsigned long size) { void *ptr; ptr = malloc(size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void *checked_calloc(unsigned long size) { void *ptr; ptr = calloc(1, size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void *checked_realloc(void *ptr, unsigned long size) { ptr = realloc(ptr, size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void checked_free(void *ptr) { if (ptr != NULL) /* this check should be done by free() anyway */ free(ptr); } void clear_mem(void *ptr, unsigned long size) { #if defined(PLATFORM_WIN32) /* for unknown reason, memset() sometimes crashes when compiled with MinGW */ char *cptr = (char *)ptr; while (size--) *cptr++ = 0; #else memset(ptr, 0, size); #endif } /* ------------------------------------------------------------------------- */ /* various helper functions */ /* ------------------------------------------------------------------------- */ inline void swap_numbers(int *i1, int *i2) { int help = *i1; *i1 = *i2; *i2 = help; } inline 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; } /* the "put" variants of the following file access functions check for the file pointer being != NULL and return the number of bytes they have or would have written; this allows for chunk writing functions to first determine the size of the (not yet written) chunk, write the correct chunk size and finally write the chunk itself */ int getFile8BitInteger(FILE *file) { return fgetc(file); } int putFile8BitInteger(FILE *file, int value) { if (file != NULL) fputc(value, file); return 1; } int getFile16BitInteger(FILE *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) return ((fgetc(file) << 8) | (fgetc(file) << 0)); else /* BYTE_ORDER_LITTLE_ENDIAN */ return ((fgetc(file) << 0) | (fgetc(file) << 8)); } int putFile16BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) { fputc((value >> 8) & 0xff, file); fputc((value >> 0) & 0xff, file); } else /* BYTE_ORDER_LITTLE_ENDIAN */ { fputc((value >> 0) & 0xff, file); fputc((value >> 8) & 0xff, file); } } return 2; } int getFile32BitInteger(FILE *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) return ((fgetc(file) << 24) | (fgetc(file) << 16) | (fgetc(file) << 8) | (fgetc(file) << 0)); else /* BYTE_ORDER_LITTLE_ENDIAN */ return ((fgetc(file) << 0) | (fgetc(file) << 8) | (fgetc(file) << 16) | (fgetc(file) << 24)); } int putFile32BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) { fputc((value >> 24) & 0xff, file); fputc((value >> 16) & 0xff, file); fputc((value >> 8) & 0xff, file); fputc((value >> 0) & 0xff, file); } else /* BYTE_ORDER_LITTLE_ENDIAN */ { fputc((value >> 0) & 0xff, file); fputc((value >> 8) & 0xff, file); fputc((value >> 16) & 0xff, file); fputc((value >> 24) & 0xff, file); } } return 4; } boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size, int byte_order) { const int chunk_name_length = 4; /* read chunk name */ fgets(chunk_name, chunk_name_length + 1, file); if (chunk_size != NULL) { /* read chunk size */ *chunk_size = getFile32BitInteger(file, byte_order); } return (feof(file) || ferror(file) ? FALSE : TRUE); } int putFileChunk(FILE *file, char *chunk_name, int chunk_size, int byte_order) { int num_bytes = 0; /* write chunk name */ if (file != NULL) fputs(chunk_name, file); num_bytes += strlen(chunk_name); if (chunk_size >= 0) { /* write chunk size */ if (file != NULL) putFile32BitInteger(file, chunk_size, byte_order); num_bytes += 4; } return num_bytes; } int getFileVersion(FILE *file) { int version_major = fgetc(file); int version_minor = fgetc(file); int version_patch = fgetc(file); int version_build = fgetc(file); return VERSION_IDENT(version_major, version_minor, version_patch, version_build); } int putFileVersion(FILE *file, int version) { if (file != NULL) { int version_major = VERSION_MAJOR(version); int version_minor = VERSION_MINOR(version); int version_patch = VERSION_PATCH(version); int version_build = VERSION_BUILD(version); fputc(version_major, file); fputc(version_minor, file); fputc(version_patch, file); fputc(version_build, file); } return 4; } void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes) { int i; for(i = 0; i < bytes && !feof(file); i++) buffer[i] = fgetc(file); } void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes) { int i; for(i = 0; i < bytes; i++) fputc(buffer[i], file); } void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes) { while (bytes-- && !feof(file)) fgetc(file); } void WriteUnusedBytesToFile(FILE *file, unsigned long bytes) { while (bytes--) fputc(0, file); } /* ------------------------------------------------------------------------- */ /* functions to translate key identifiers between different format */ /* ------------------------------------------------------------------------- */ #define TRANSLATE_KEYSYM_TO_KEYNAME 0 #define TRANSLATE_KEYSYM_TO_X11KEYNAME 1 #define TRANSLATE_KEYNAME_TO_KEYSYM 2 #define TRANSLATE_X11KEYNAME_TO_KEYSYM 3 void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { static struct { Key key; char *x11name; char *name; } translate_key[] = { /* normal cursor keys */ { KSYM_Left, "XK_Left", "cursor left" }, { KSYM_Right, "XK_Right", "cursor right" }, { KSYM_Up, "XK_Up", "cursor up" }, { KSYM_Down, "XK_Down", "cursor down" }, /* keypad cursor keys */ #ifdef KSYM_KP_Left { KSYM_KP_Left, "XK_KP_Left", "keypad left" }, { KSYM_KP_Right, "XK_KP_Right", "keypad right" }, { KSYM_KP_Up, "XK_KP_Up", "keypad up" }, { KSYM_KP_Down, "XK_KP_Down", "keypad down" }, #endif /* other keypad keys */ #ifdef KSYM_KP_Enter { KSYM_KP_Enter, "XK_KP_Enter", "keypad enter" }, { KSYM_KP_Add, "XK_KP_Add", "keypad +" }, { KSYM_KP_Subtract, "XK_KP_Subtract", "keypad -" }, { KSYM_KP_Multiply, "XK_KP_Multiply", "keypad mltply" }, { KSYM_KP_Divide, "XK_KP_Divide", "keypad /" }, { KSYM_KP_Separator,"XK_KP_Separator", "keypad ," }, #endif /* modifier keys */ { KSYM_Shift_L, "XK_Shift_L", "left shift" }, { KSYM_Shift_R, "XK_Shift_R", "right shift" }, { KSYM_Control_L, "XK_Control_L", "left control" }, { KSYM_Control_R, "XK_Control_R", "right control" }, { KSYM_Meta_L, "XK_Meta_L", "left meta" }, { KSYM_Meta_R, "XK_Meta_R", "right meta" }, { KSYM_Alt_L, "XK_Alt_L", "left alt" }, { KSYM_Alt_R, "XK_Alt_R", "right alt" }, { KSYM_Super_L, "XK_Super_L", "left super" }, /* Win-L */ { KSYM_Super_R, "XK_Super_R", "right super" }, /* Win-R */ { KSYM_Mode_switch, "XK_Mode_switch", "mode switch" }, /* Alt-R */ { KSYM_Multi_key, "XK_Multi_key", "multi key" }, /* Ctrl-R */ /* some special keys */ { KSYM_BackSpace, "XK_BackSpace", "backspace" }, { KSYM_Delete, "XK_Delete", "delete" }, { KSYM_Insert, "XK_Insert", "insert" }, { KSYM_Tab, "XK_Tab", "tab" }, { KSYM_Home, "XK_Home", "home" }, { KSYM_End, "XK_End", "end" }, { KSYM_Page_Up, "XK_Page_Up", "page up" }, { KSYM_Page_Down, "XK_Page_Down", "page down" }, { KSYM_Menu, "XK_Menu", "menu" }, /* Win-Menu */ /* ASCII 0x20 to 0x40 keys (except numbers) */ { KSYM_space, "XK_space", "space" }, { KSYM_exclam, "XK_exclam", "!" }, { KSYM_quotedbl, "XK_quotedbl", "\"" }, { KSYM_numbersign, "XK_numbersign", "#" }, { KSYM_dollar, "XK_dollar", "$" }, { KSYM_percent, "XK_percent", "%" }, { KSYM_ampersand, "XK_ampersand", "&" }, { KSYM_apostrophe, "XK_apostrophe", "'" }, { KSYM_parenleft, "XK_parenleft", "(" }, { KSYM_parenright, "XK_parenright", ")" }, { KSYM_asterisk, "XK_asterisk", "*" }, { KSYM_plus, "XK_plus", "+" }, { KSYM_comma, "XK_comma", "," }, { KSYM_minus, "XK_minus", "-" }, { KSYM_period, "XK_period", "." }, { KSYM_slash, "XK_slash", "/" }, { KSYM_colon, "XK_colon", ":" }, { KSYM_semicolon, "XK_semicolon", ";" }, { KSYM_less, "XK_less", "<" }, { KSYM_equal, "XK_equal", "=" }, { KSYM_greater, "XK_greater", ">" }, { KSYM_question, "XK_question", "?" }, { KSYM_at, "XK_at", "@" }, /* more ASCII keys */ { KSYM_bracketleft, "XK_bracketleft", "[" }, { KSYM_backslash, "XK_backslash", "\\" }, { KSYM_bracketright,"XK_bracketright", "]" }, { KSYM_asciicircum, "XK_asciicircum", "^" }, { KSYM_underscore, "XK_underscore", "_" }, { KSYM_grave, "XK_grave", "grave" }, { KSYM_quoteleft, "XK_quoteleft", "quote left" }, { KSYM_braceleft, "XK_braceleft", "brace left" }, { KSYM_bar, "XK_bar", "bar" }, { KSYM_braceright, "XK_braceright", "brace right" }, { KSYM_asciitilde, "XK_asciitilde", "~" }, /* special (non-ASCII) keys */ { KSYM_degree, "XK_degree", "°" }, { KSYM_Adiaeresis, "XK_Adiaeresis", "Ä" }, { KSYM_Odiaeresis, "XK_Odiaeresis", "Ö" }, { KSYM_Udiaeresis, "XK_Udiaeresis", "Ü" }, { KSYM_adiaeresis, "XK_adiaeresis", "ä" }, { KSYM_odiaeresis, "XK_odiaeresis", "ö" }, { KSYM_udiaeresis, "XK_udiaeresis", "ü" }, { KSYM_ssharp, "XK_ssharp", "sharp s" }, /* end-of-array identifier */ { 0, NULL, NULL } }; int i; if (mode == TRANSLATE_KEYSYM_TO_KEYNAME) { static char name_buffer[30]; Key key = *keysym; if (key >= KSYM_A && key <= KSYM_Z) sprintf(name_buffer, "%c", 'A' + (char)(key - KSYM_A)); else if (key >= KSYM_a && key <= KSYM_z) sprintf(name_buffer, "%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0)); else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0)); else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) strcpy(name_buffer, "(undefined)"); else { i = 0; do { if (key == translate_key[i].key) { strcpy(name_buffer, translate_key[i].name); break; } } while (translate_key[++i].name); if (!translate_key[i].name) strcpy(name_buffer, "(unknown)"); } *name = name_buffer; } else if (mode == TRANSLATE_KEYSYM_TO_X11KEYNAME) { static char name_buffer[30]; Key key = *keysym; if (key >= KSYM_A && key <= KSYM_Z) sprintf(name_buffer, "XK_%c", 'A' + (char)(key - KSYM_A)); else if (key >= KSYM_a && key <= KSYM_z) sprintf(name_buffer, "XK_%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "XK_%c", '0' + (char)(key - KSYM_0)); else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - KSYM_KP_0)); else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "XK_F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) strcpy(name_buffer, "[undefined]"); else { i = 0; do { if (key == translate_key[i].key) { strcpy(name_buffer, translate_key[i].x11name); break; } } while (translate_key[++i].x11name); if (!translate_key[i].x11name) sprintf(name_buffer, "0x%04lx", (unsigned long)key); } *x11name = name_buffer; } else if (mode == TRANSLATE_KEYNAME_TO_KEYSYM) { Key key = KSYM_UNDEFINED; i = 0; do { if (strEqual(translate_key[i].name, *name)) { key = translate_key[i].key; break; } } while (translate_key[++i].x11name); if (key == KSYM_UNDEFINED) Error(ERR_WARN, "getKeyFromKeyName(): not completely implemented"); *keysym = key; } else if (mode == TRANSLATE_X11KEYNAME_TO_KEYSYM) { Key key = KSYM_UNDEFINED; char *name_ptr = *x11name; if (strPrefix(name_ptr, "XK_") && strlen(name_ptr) == 4) { char c = name_ptr[3]; if (c >= 'A' && c <= 'Z') key = KSYM_A + (Key)(c - 'A'); else if (c >= 'a' && c <= 'z') key = KSYM_a + (Key)(c - 'a'); else if (c >= '0' && c <= '9') key = KSYM_0 + (Key)(c - '0'); } else if (strPrefix(name_ptr, "XK_KP_") && strlen(name_ptr) == 7) { char c = name_ptr[6]; if (c >= '0' && c <= '9') key = KSYM_KP_0 + (Key)(c - '0'); } else if (strPrefix(name_ptr, "XK_F") && strlen(name_ptr) <= 6) { char c1 = name_ptr[4]; char c2 = name_ptr[5]; int d = 0; if ((c1 >= '0' && c1 <= '9') && ((c2 >= '0' && c1 <= '9') || c2 == '\0')) d = atoi(&name_ptr[4]); if (d >= 1 && d <= KSYM_NUM_FKEYS) key = KSYM_F1 + (Key)(d - 1); } else if (strPrefix(name_ptr, "XK_")) { i = 0; do { if (strEqual(name_ptr, translate_key[i].x11name)) { key = translate_key[i].key; break; } } while (translate_key[++i].x11name); } else if (strPrefix(name_ptr, "0x")) { unsigned long value = 0; name_ptr += 2; while (name_ptr) { char c = *name_ptr++; int d = -1; if (c >= '0' && c <= '9') d = (int)(c - '0'); else if (c >= 'a' && c <= 'f') d = (int)(c - 'a' + 10); else if (c >= 'A' && c <= 'F') d = (int)(c - 'A' + 10); if (d == -1) { value = -1; break; } value = value * 16 + d; } if (value != -1) key = (Key)value; } *keysym = key; } } char *getKeyNameFromKey(Key key) { char *name; translate_keyname(&key, NULL, &name, TRANSLATE_KEYSYM_TO_KEYNAME); return name; } char *getX11KeyNameFromKey(Key key) { char *x11name; translate_keyname(&key, &x11name, NULL, TRANSLATE_KEYSYM_TO_X11KEYNAME); return x11name; } Key getKeyFromKeyName(char *name) { Key key; translate_keyname(&key, NULL, &name, TRANSLATE_KEYNAME_TO_KEYSYM); return key; } Key getKeyFromX11KeyName(char *x11name) { Key key; translate_keyname(&key, &x11name, NULL, TRANSLATE_X11KEYNAME_TO_KEYSYM); return key; } char getCharFromKey(Key key) { char *keyname = getKeyNameFromKey(key); char c = 0; if (strlen(keyname) == 1) c = keyname[0]; else if (strEqual(keyname, "space")) c = ' '; return c; } char getValidConfigValueChar(char c) { if (c == '#' || /* used to mark comments */ c == '\\') /* used to mark continued lines */ c = 0; return c; } /* ------------------------------------------------------------------------- */ /* functions to translate string identifiers to integer or boolean value */ /* ------------------------------------------------------------------------- */ int get_integer_from_string(char *s) { static char *number_text[][3] = { { "0", "zero", "null", }, { "1", "one", "first" }, { "2", "two", "second" }, { "3", "three", "third" }, { "4", "four", "fourth" }, { "5", "five", "fifth" }, { "6", "six", "sixth" }, { "7", "seven", "seventh" }, { "8", "eight", "eighth" }, { "9", "nine", "ninth" }, { "10", "ten", "tenth" }, { "11", "eleven", "eleventh" }, { "12", "twelve", "twelfth" }, { NULL, NULL, NULL }, }; int i, j; char *s_lower = getStringToLower(s); int result = -1; for (i = 0; number_text[i][0] != NULL; i++) for (j = 0; j < 3; j++) if (strEqual(s_lower, number_text[i][j])) result = i; if (result == -1) { if (strEqual(s_lower, "false") || strEqual(s_lower, "no") || strEqual(s_lower, "off")) result = 0; else if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on")) result = 1; else result = atoi(s); } free(s_lower); return result; } boolean get_boolean_from_string(char *s) { char *s_lower = getStringToLower(s); boolean result = FALSE; if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on") || get_integer_from_string(s) == 1) result = TRUE; free(s_lower); return result; } int get_switch3_from_string(char *s) { char *s_lower = getStringToLower(s); int result = FALSE; if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on") || get_integer_from_string(s) == 1) result = TRUE; else if (strEqual(s_lower, "auto")) result = AUTO; free(s_lower); return result; } /* ------------------------------------------------------------------------- */ /* functions for generic lists */ /* ------------------------------------------------------------------------- */ ListNode *newListNode() { return checked_calloc(sizeof(ListNode)); } void addNodeToList(ListNode **node_first, char *key, void *content) { ListNode *node_new = newListNode(); node_new->key = getStringCopy(key); node_new->content = content; node_new->next = *node_first; *node_first = node_new; } void deleteNodeFromList(ListNode **node_first, char *key, void (*destructor_function)(void *)) { if (node_first == NULL || *node_first == NULL) return; if (strEqual((*node_first)->key, key)) { checked_free((*node_first)->key); if (destructor_function) destructor_function((*node_first)->content); *node_first = (*node_first)->next; } else deleteNodeFromList(&(*node_first)->next, key, destructor_function); } ListNode *getNodeFromKey(ListNode *node_first, char *key) { if (node_first == NULL) return NULL; if (strEqual(node_first->key, key)) return node_first; else return getNodeFromKey(node_first->next, key); } int getNumNodes(ListNode *node_first) { return (node_first ? 1 + getNumNodes(node_first->next) : 0); } void dumpList(ListNode *node_first) { ListNode *node = node_first; while (node) { printf("['%s' (%d)]\n", node->key, ((struct ListNodeInfo *)node->content)->num_references); node = node->next; } printf("[%d nodes]\n", getNumNodes(node_first)); } /* ------------------------------------------------------------------------- */ /* functions for checking files and filenames */ /* ------------------------------------------------------------------------- */ boolean fileExists(char *filename) { if (filename == NULL) return FALSE; return (access(filename, F_OK) == 0); } boolean fileHasPrefix(char *basename, char *prefix) { static char *basename_lower = NULL; int basename_length, prefix_length; checked_free(basename_lower); if (basename == NULL || prefix == NULL) return FALSE; basename_lower = getStringToLower(basename); basename_length = strlen(basename_lower); prefix_length = strlen(prefix); if (basename_length > prefix_length + 1 && basename_lower[prefix_length] == '.' && strncmp(basename_lower, prefix, prefix_length) == 0) return TRUE; return FALSE; } boolean fileHasSuffix(char *basename, char *suffix) { static char *basename_lower = NULL; int basename_length, suffix_length; checked_free(basename_lower); if (basename == NULL || suffix == NULL) return FALSE; basename_lower = getStringToLower(basename); basename_length = strlen(basename_lower); suffix_length = strlen(suffix); if (basename_length > suffix_length + 1 && basename_lower[basename_length - suffix_length - 1] == '.' && strEqual(&basename_lower[basename_length - suffix_length], suffix)) return TRUE; return FALSE; } boolean FileIsGraphic(char *filename) { char *basename = getBaseNamePtr(filename); return fileHasSuffix(basename, "pcx"); } boolean FileIsSound(char *filename) { char *basename = getBaseNamePtr(filename); return fileHasSuffix(basename, "wav"); } boolean FileIsMusic(char *filename) { char *basename = getBaseNamePtr(filename); if (FileIsSound(basename)) return TRUE; #if defined(TARGET_SDL) if ((fileHasPrefix(basename, "mod") && !fileHasSuffix(basename, "txt")) || fileHasSuffix(basename, "mod") || fileHasSuffix(basename, "s3m") || fileHasSuffix(basename, "it") || fileHasSuffix(basename, "xm") || fileHasSuffix(basename, "midi") || fileHasSuffix(basename, "mid") || fileHasSuffix(basename, "mp3") || fileHasSuffix(basename, "ogg")) return TRUE; #endif return FALSE; } boolean FileIsArtworkType(char *basename, int type) { if ((type == TREE_TYPE_GRAPHICS_DIR && FileIsGraphic(basename)) || (type == TREE_TYPE_SOUNDS_DIR && FileIsSound(basename)) || (type == TREE_TYPE_MUSIC_DIR && FileIsMusic(basename))) return TRUE; return FALSE; } /* ------------------------------------------------------------------------- */ /* functions for loading artwork configuration information */ /* ------------------------------------------------------------------------- */ char *get_mapped_token(char *token) { /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */ static char *map_token_prefix[][2] = { { "char_procent", "char_percent" }, { NULL, } }; int i; for (i = 0; map_token_prefix[i][0] != NULL; i++) { int len_token_prefix = strlen(map_token_prefix[i][0]); if (strncmp(token, map_token_prefix[i][0], len_token_prefix) == 0) return getStringCat2(map_token_prefix[i][1], &token[len_token_prefix]); } return NULL; } /* This function checks if a string of the format "string1, string2, ..." exactly contains a string . */ static boolean string_has_parameter(char *s, char *s_contained) { char *substring; if (s == NULL || s_contained == NULL) return FALSE; if (strlen(s_contained) > strlen(s)) return FALSE; if (strncmp(s, s_contained, strlen(s_contained)) == 0) { char next_char = s[strlen(s_contained)]; /* check if next character is delimiter or whitespace */ return (next_char == ',' || next_char == '\0' || next_char == ' ' || next_char == '\t' ? TRUE : FALSE); } /* check if string contains another parameter string after a comma */ substring = strchr(s, ','); if (substring == NULL) /* string does not contain a comma */ return FALSE; /* advance string pointer to next character after the comma */ substring++; /* skip potential whitespaces after the comma */ while (*substring == ' ' || *substring == '\t') substring++; return string_has_parameter(substring, s_contained); } int get_parameter_value(char *value_raw, char *suffix, int type) { char *value = getStringToLower(value_raw); int result = 0; /* probably a save default value */ if (strEqual(suffix, ".direction")) { result = (strEqual(value, "left") ? MV_LEFT : strEqual(value, "right") ? MV_RIGHT : strEqual(value, "up") ? MV_UP : strEqual(value, "down") ? MV_DOWN : MV_NONE); } else if (strEqual(suffix, ".align")) { result = (strEqual(value, "left") ? ALIGN_LEFT : strEqual(value, "right") ? ALIGN_RIGHT : strEqual(value, "center") ? ALIGN_CENTER : strEqual(value, "middle") ? ALIGN_CENTER : ALIGN_DEFAULT); } else if (strEqual(suffix, ".valign")) { result = (strEqual(value, "top") ? VALIGN_TOP : strEqual(value, "bottom") ? VALIGN_BOTTOM : strEqual(value, "middle") ? VALIGN_MIDDLE : strEqual(value, "center") ? VALIGN_MIDDLE : VALIGN_DEFAULT); } else if (strEqual(suffix, ".anim_mode")) { result = (string_has_parameter(value, "none") ? ANIM_NONE : string_has_parameter(value, "loop") ? ANIM_LOOP : string_has_parameter(value, "linear") ? ANIM_LINEAR : string_has_parameter(value, "pingpong") ? ANIM_PINGPONG : string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 : string_has_parameter(value, "random") ? ANIM_RANDOM : string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE : string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE : string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY : string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL : string_has_parameter(value, "vertical") ? ANIM_VERTICAL : string_has_parameter(value, "centered") ? ANIM_CENTERED : ANIM_DEFAULT); if (string_has_parameter(value, "reverse")) result |= ANIM_REVERSE; if (string_has_parameter(value, "opaque_player")) result |= ANIM_OPAQUE_PLAYER; if (string_has_parameter(value, "static_panel")) result |= ANIM_STATIC_PANEL; } else if (strEqual(suffix, ".class")) { result = get_hash_from_key(value); } else if (strEqual(suffix, ".style")) { result = STYLE_DEFAULT; if (string_has_parameter(value, "accurate_borders")) result |= STYLE_ACCURATE_BORDERS; if (string_has_parameter(value, "inner_corners")) result |= STYLE_INNER_CORNERS; } else if (strEqual(suffix, ".fade_mode")) { result = (string_has_parameter(value, "none") ? FADE_MODE_NONE : string_has_parameter(value, "fade") ? FADE_MODE_FADE : string_has_parameter(value, "crossfade") ? FADE_MODE_CROSSFADE : string_has_parameter(value, "melt") ? FADE_MODE_MELT : FADE_MODE_DEFAULT); } #if 1 else if (strPrefix(suffix, ".font")) /* (may also be ".font_xyz") */ #else else if (strEqualN(suffix, ".font", 5)) /* (may also be ".font_xyz") */ #endif { result = gfx.get_font_from_token_function(value); } else /* generic parameter of type integer or boolean */ { result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE : type == TYPE_INTEGER ? get_integer_from_string(value) : type == TYPE_BOOLEAN ? get_boolean_from_string(value) : ARG_UNDEFINED_VALUE); } free(value); return result; } struct ScreenModeInfo *get_screen_mode_from_string(char *screen_mode_string) { static struct ScreenModeInfo screen_mode; char *screen_mode_string_x = strchr(screen_mode_string, 'x'); char *screen_mode_string_copy; char *screen_mode_string_pos_w; char *screen_mode_string_pos_h; if (screen_mode_string_x == NULL) /* invalid screen mode format */ return NULL; screen_mode_string_copy = getStringCopy(screen_mode_string); screen_mode_string_pos_w = screen_mode_string_copy; screen_mode_string_pos_h = strchr(screen_mode_string_copy, 'x'); *screen_mode_string_pos_h++ = '\0'; screen_mode.width = atoi(screen_mode_string_pos_w); screen_mode.height = atoi(screen_mode_string_pos_h); return &screen_mode; } void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *screen_mode, int *x, int *y) { float aspect_ratio = (float)screen_mode->width / (float)screen_mode->height; float aspect_ratio_new; int i = 1; do { *x = i * aspect_ratio + 0.000001; *y = i; aspect_ratio_new = (float)*x / (float)*y; i++; } while (aspect_ratio_new != aspect_ratio && *y < screen_mode->height); } static void FreeCustomArtworkList(struct ArtworkListInfo *, struct ListNodeInfo ***, int *); struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, struct ConfigTypeInfo *suffix_list, char **ignore_tokens, int num_file_list_entries) { struct FileInfo *file_list; int num_file_list_entries_found = 0; int num_suffix_list_entries = 0; int list_pos; int i, j; file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo)); for (i = 0; suffix_list[i].token != NULL; i++) num_suffix_list_entries++; /* always start with reliable default values */ for (i = 0; i < num_file_list_entries; i++) { file_list[i].token = NULL; file_list[i].default_filename = NULL; file_list[i].filename = NULL; if (num_suffix_list_entries > 0) { int parameter_array_size = num_suffix_list_entries * sizeof(char *); file_list[i].default_parameter = checked_calloc(parameter_array_size); file_list[i].parameter = checked_calloc(parameter_array_size); for (j = 0; j < num_suffix_list_entries; j++) { setString(&file_list[i].default_parameter[j], suffix_list[j].value); setString(&file_list[i].parameter[j], suffix_list[j].value); } file_list[i].redefined = FALSE; file_list[i].fallback_to_default = FALSE; file_list[i].default_is_cloned = FALSE; } } list_pos = 0; for (i = 0; config_list[i].token != NULL; i++) { int len_config_token = strlen(config_list[i].token); int len_config_value = strlen(config_list[i].value); boolean is_file_entry = TRUE; for (j = 0; suffix_list[j].token != NULL; j++) { int len_suffix = strlen(suffix_list[j].token); if (len_suffix < len_config_token && strEqual(&config_list[i].token[len_config_token - len_suffix], suffix_list[j].token)) { setString(&file_list[list_pos].default_parameter[j], config_list[i].value); is_file_entry = FALSE; break; } } /* the following tokens are no file definitions, but other config tokens */ for (j = 0; ignore_tokens[j] != NULL; j++) if (strEqual(config_list[i].token, ignore_tokens[j])) is_file_entry = FALSE; if (is_file_entry) { if (i > 0) list_pos++; if (list_pos >= num_file_list_entries) break; /* simple sanity check if this is really a file definition */ if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") && !strEqual(&config_list[i].value[len_config_value - 4], ".wav") && !strEqual(config_list[i].value, UNDEFINED_FILENAME)) { Error(ERR_INFO, "Configuration directive '%s' -> '%s':", config_list[i].token, config_list[i].value); Error(ERR_EXIT, "This seems to be no valid definition -- please fix"); } file_list[list_pos].token = config_list[i].token; file_list[list_pos].default_filename = config_list[i].value; #if 0 printf("::: '%s' => '%s'\n", config_list[i].token, config_list[i].value); #endif } if (strSuffix(config_list[i].token, ".clone_from")) file_list[list_pos].default_is_cloned = TRUE; } num_file_list_entries_found = list_pos + 1; if (num_file_list_entries_found != num_file_list_entries) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "inconsistant config list information:"); Error(ERR_INFO, "- should be: %d (according to 'src/conf_xxx.h')", num_file_list_entries); Error(ERR_INFO, "- found to be: %d (according to 'src/conf_xxx.c')", num_file_list_entries_found); Error(ERR_EXIT, "please fix"); } #if 0 printf("::: ---------- DONE ----------\n"); #endif return file_list; } static boolean token_suffix_match(char *token, char *suffix, int start_pos) { int len_token = strlen(token); int len_suffix = strlen(suffix); if (start_pos < 0) /* compare suffix from end of string */ start_pos += len_token; if (start_pos < 0 || start_pos + len_suffix > len_token) return FALSE; if (strncmp(&token[start_pos], suffix, len_suffix) != 0) return FALSE; if (token[start_pos + len_suffix] == '\0') return TRUE; if (token[start_pos + len_suffix] == '.') return TRUE; return FALSE; } #define KNOWN_TOKEN_VALUE "[KNOWN_TOKEN_VALUE]" static void read_token_parameters(SetupFileHash *setup_file_hash, struct ConfigTypeInfo *suffix_list, struct FileInfo *file_list_entry) { /* check for config token that is the base token without any suffixes */ char *filename = getHashEntry(setup_file_hash, file_list_entry->token); char *known_token_value = KNOWN_TOKEN_VALUE; int i; if (filename != NULL) { setString(&file_list_entry->filename, filename); /* when file definition found, set all parameters to default values */ for (i = 0; suffix_list[i].token != NULL; i++) setString(&file_list_entry->parameter[i], suffix_list[i].value); file_list_entry->redefined = TRUE; /* mark config file token as well known from default config */ setHashEntry(setup_file_hash, file_list_entry->token, known_token_value); } /* check for config tokens that can be build by base token and suffixes */ for (i = 0; suffix_list[i].token != NULL; i++) { char *token = getStringCat2(file_list_entry->token, suffix_list[i].token); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) { setString(&file_list_entry->parameter[i], value); /* mark config file token as well known from default config */ setHashEntry(setup_file_hash, token, known_token_value); } free(token); } } static void add_dynamic_file_list_entry(struct FileInfo **list, int *num_list_entries, SetupFileHash *extra_file_hash, struct ConfigTypeInfo *suffix_list, int num_suffix_list_entries, char *token) { struct FileInfo *new_list_entry; int parameter_array_size = num_suffix_list_entries * sizeof(char *); (*num_list_entries)++; *list = checked_realloc(*list, *num_list_entries * sizeof(struct FileInfo)); new_list_entry = &(*list)[*num_list_entries - 1]; new_list_entry->token = getStringCopy(token); new_list_entry->default_filename = NULL; new_list_entry->filename = NULL; new_list_entry->parameter = checked_calloc(parameter_array_size); new_list_entry->redefined = FALSE; new_list_entry->fallback_to_default = FALSE; new_list_entry->default_is_cloned = FALSE; read_token_parameters(extra_file_hash, suffix_list, new_list_entry); } static void add_property_mapping(struct PropertyMapping **list, int *num_list_entries, int base_index, int ext1_index, int ext2_index, int ext3_index, int artwork_index) { struct PropertyMapping *new_list_entry; (*num_list_entries)++; *list = checked_realloc(*list, *num_list_entries * sizeof(struct PropertyMapping)); new_list_entry = &(*list)[*num_list_entries - 1]; new_list_entry->base_index = base_index; new_list_entry->ext1_index = ext1_index; new_list_entry->ext2_index = ext2_index; new_list_entry->ext3_index = ext3_index; new_list_entry->artwork_index = artwork_index; } static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info, char *filename) { struct FileInfo *file_list = artwork_info->file_list; struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list; char **base_prefixes = artwork_info->base_prefixes; char **ext1_suffixes = artwork_info->ext1_suffixes; char **ext2_suffixes = artwork_info->ext2_suffixes; char **ext3_suffixes = artwork_info->ext3_suffixes; char **ignore_tokens = artwork_info->ignore_tokens; int num_file_list_entries = artwork_info->num_file_list_entries; int num_suffix_list_entries = artwork_info->num_suffix_list_entries; int num_base_prefixes = artwork_info->num_base_prefixes; int num_ext1_suffixes = artwork_info->num_ext1_suffixes; int num_ext2_suffixes = artwork_info->num_ext2_suffixes; int num_ext3_suffixes = artwork_info->num_ext3_suffixes; int num_ignore_tokens = artwork_info->num_ignore_tokens; SetupFileHash *setup_file_hash, *valid_file_hash; SetupFileHash *extra_file_hash, *empty_file_hash; char *known_token_value = KNOWN_TOKEN_VALUE; int i, j, k, l; if (filename == NULL) return; #if 0 printf("LoadArtworkConfigFromFilename '%s' ...\n", filename); #endif if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; /* separate valid (defined) from empty (undefined) config token values */ valid_file_hash = newSetupFileHash(); empty_file_hash = newSetupFileHash(); BEGIN_HASH_ITERATION(setup_file_hash, itr) { char *value = HASH_ITERATION_VALUE(itr); setHashEntry(*value ? valid_file_hash : empty_file_hash, HASH_ITERATION_TOKEN(itr), value); } END_HASH_ITERATION(setup_file_hash, itr) /* at this point, we do not need the setup file hash anymore -- free it */ freeSetupFileHash(setup_file_hash); /* map deprecated to current tokens (using prefix match and replace) */ BEGIN_HASH_ITERATION(valid_file_hash, itr) { char *token = HASH_ITERATION_TOKEN(itr); char *mapped_token = get_mapped_token(token); if (mapped_token != NULL) { char *value = HASH_ITERATION_VALUE(itr); /* add mapped token */ setHashEntry(valid_file_hash, mapped_token, value); /* ignore old token (by setting it to "known" keyword) */ setHashEntry(valid_file_hash, token, known_token_value); free(mapped_token); } } END_HASH_ITERATION(valid_file_hash, itr) /* read parameters for all known config file tokens */ for (i = 0; i < num_file_list_entries; i++) read_token_parameters(valid_file_hash, suffix_list, &file_list[i]); /* set all tokens that can be ignored here to "known" keyword */ for (i = 0; i < num_ignore_tokens; i++) setHashEntry(valid_file_hash, ignore_tokens[i], known_token_value); /* copy all unknown config file tokens to extra config hash */ extra_file_hash = newSetupFileHash(); BEGIN_HASH_ITERATION(valid_file_hash, itr) { char *value = HASH_ITERATION_VALUE(itr); if (!strEqual(value, known_token_value)) setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value); } END_HASH_ITERATION(valid_file_hash, itr) /* at this point, we do not need the valid file hash anymore -- free it */ freeSetupFileHash(valid_file_hash); /* now try to determine valid, dynamically defined config tokens */ BEGIN_HASH_ITERATION(extra_file_hash, itr) { struct FileInfo **dynamic_file_list = &artwork_info->dynamic_file_list; int *num_dynamic_file_list_entries = &artwork_info->num_dynamic_file_list_entries; struct PropertyMapping **property_mapping = &artwork_info->property_mapping; int *num_property_mapping_entries = &artwork_info->num_property_mapping_entries; int current_summarized_file_list_entry = artwork_info->num_file_list_entries + artwork_info->num_dynamic_file_list_entries; char *token = HASH_ITERATION_TOKEN(itr); int len_token = strlen(token); int start_pos; boolean base_prefix_found = FALSE; boolean parameter_suffix_found = FALSE; #if 0 printf("::: examining '%s' -> '%s'\n", token, HASH_ITERATION_VALUE(itr)); #endif /* skip all parameter definitions (handled by read_token_parameters()) */ for (i = 0; i < num_suffix_list_entries && !parameter_suffix_found; i++) { int len_suffix = strlen(suffix_list[i].token); if (token_suffix_match(token, suffix_list[i].token, -len_suffix)) parameter_suffix_found = TRUE; } if (parameter_suffix_found) continue; /* ---------- step 0: search for matching base prefix ---------- */ start_pos = 0; for (i = 0; i < num_base_prefixes && !base_prefix_found; i++) { char *base_prefix = base_prefixes[i]; int len_base_prefix = strlen(base_prefix); boolean ext1_suffix_found = FALSE; boolean ext2_suffix_found = FALSE; boolean ext3_suffix_found = FALSE; boolean exact_match = FALSE; int base_index = -1; int ext1_index = -1; int ext2_index = -1; int ext3_index = -1; base_prefix_found = token_suffix_match(token, base_prefix, start_pos); if (!base_prefix_found) continue; base_index = i; #if 0 if (IS_PARENT_PROCESS()) printf("===> MATCH: '%s', '%s'\n", token, base_prefix); #endif if (start_pos + len_base_prefix == len_token) /* exact match */ { exact_match = TRUE; #if 0 if (IS_PARENT_PROCESS()) printf("===> EXACT MATCH: '%s', '%s'\n", token, base_prefix); #endif add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, -1, -1, -1, current_summarized_file_list_entry); continue; } #if 0 if (IS_PARENT_PROCESS()) printf("---> examining token '%s': search 1st suffix ...\n", token); #endif /* ---------- step 1: search for matching first suffix ---------- */ start_pos += len_base_prefix; for (j = 0; j < num_ext1_suffixes && !ext1_suffix_found; j++) { char *ext1_suffix = ext1_suffixes[j]; int len_ext1_suffix = strlen(ext1_suffix); ext1_suffix_found = token_suffix_match(token, ext1_suffix, start_pos); if (!ext1_suffix_found) continue; ext1_index = j; #if 0 if (IS_PARENT_PROCESS()) printf("===> MATCH: '%s', '%s'\n", token, ext1_suffix); #endif if (start_pos + len_ext1_suffix == len_token) /* exact match */ { exact_match = TRUE; #if 0 if (IS_PARENT_PROCESS()) printf("===> EXACT MATCH: '%s', '%s'\n", token, ext1_suffix); #endif add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, -1, -1, current_summarized_file_list_entry); continue; } start_pos += len_ext1_suffix; } if (exact_match) break; #if 0 if (IS_PARENT_PROCESS()) printf("---> examining token '%s': search 2nd suffix ...\n", token); #endif /* ---------- step 2: search for matching second suffix ---------- */ for (k = 0; k < num_ext2_suffixes && !ext2_suffix_found; k++) { char *ext2_suffix = ext2_suffixes[k]; int len_ext2_suffix = strlen(ext2_suffix); ext2_suffix_found = token_suffix_match(token, ext2_suffix, start_pos); if (!ext2_suffix_found) continue; ext2_index = k; #if 0 if (IS_PARENT_PROCESS()) printf("===> MATCH: '%s', '%s'\n", token, ext2_suffix); #endif if (start_pos + len_ext2_suffix == len_token) /* exact match */ { exact_match = TRUE; #if 0 if (IS_PARENT_PROCESS()) printf("===> EXACT MATCH: '%s', '%s'\n", token, ext2_suffix); #endif add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, ext2_index, -1, current_summarized_file_list_entry); continue; } start_pos += len_ext2_suffix; } if (exact_match) break; #if 0 if (IS_PARENT_PROCESS()) printf("---> examining token '%s': search 3rd suffix ...\n",token); #endif /* ---------- step 3: search for matching third suffix ---------- */ for (l = 0; l < num_ext3_suffixes && !ext3_suffix_found; l++) { char *ext3_suffix = ext3_suffixes[l]; int len_ext3_suffix = strlen(ext3_suffix); ext3_suffix_found = token_suffix_match(token, ext3_suffix, start_pos); if (!ext3_suffix_found) continue; ext3_index = l; #if 0 if (IS_PARENT_PROCESS()) printf("===> MATCH: '%s', '%s'\n", token, ext3_suffix); #endif if (start_pos + len_ext3_suffix == len_token) /* exact match */ { exact_match = TRUE; #if 0 if (IS_PARENT_PROCESS()) printf("===> EXACT MATCH: '%s', '%s'\n", token, ext3_suffix); #endif add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, ext2_index, ext3_index, current_summarized_file_list_entry); continue; } } } } END_HASH_ITERATION(extra_file_hash, itr) if (artwork_info->num_dynamic_file_list_entries > 0) { artwork_info->dynamic_artwork_list = checked_calloc(artwork_info->num_dynamic_file_list_entries * artwork_info->sizeof_artwork_list_entry); } if (options.verbose && IS_PARENT_PROCESS()) { SetupFileList *setup_file_list, *list; boolean dynamic_tokens_found = FALSE; boolean unknown_tokens_found = FALSE; boolean undefined_values_found = (hashtable_count(empty_file_hash) != 0); if ((setup_file_list = loadSetupFileList(filename)) == NULL) Error(ERR_EXIT, "loadSetupFileHash works, but loadSetupFileList fails"); BEGIN_HASH_ITERATION(extra_file_hash, itr) { if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value)) dynamic_tokens_found = TRUE; else unknown_tokens_found = TRUE; } END_HASH_ITERATION(extra_file_hash, itr) if (options.debug && dynamic_tokens_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "dynamic token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(extra_file_hash, list->token); if (value != NULL && strEqual(value, known_token_value)) Error(ERR_INFO, "- dynamic token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } if (unknown_tokens_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(extra_file_hash, list->token); if (value != NULL && !strEqual(value, known_token_value)) Error(ERR_INFO, "- dynamic token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } if (undefined_values_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: undefined values found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(empty_file_hash, list->token); if (value != NULL) Error(ERR_INFO, "- undefined value for token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } freeSetupFileList(setup_file_list); } freeSetupFileHash(extra_file_hash); freeSetupFileHash(empty_file_hash); #if 0 for (i = 0; i < num_file_list_entries; i++) { printf("'%s' ", file_list[i].token); if (file_list[i].filename) printf("-> '%s'\n", file_list[i].filename); else printf("-> UNDEFINED [-> '%s']\n", file_list[i].default_filename); } #endif } void LoadArtworkConfig(struct ArtworkListInfo *artwork_info) { struct FileInfo *file_list = artwork_info->file_list; int num_file_list_entries = artwork_info->num_file_list_entries; int num_suffix_list_entries = artwork_info->num_suffix_list_entries; char *filename_base = UNDEFINED_FILENAME, *filename_local; int i, j; DrawInitText("Loading artwork config", 120, FC_GREEN); DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW); /* always start with reliable default values */ for (i = 0; i < num_file_list_entries; i++) { setString(&file_list[i].filename, file_list[i].default_filename); for (j = 0; j < num_suffix_list_entries; j++) setString(&file_list[i].parameter[j], file_list[i].default_parameter[j]); file_list[i].redefined = FALSE; file_list[i].fallback_to_default = FALSE; } /* free previous dynamic artwork file array */ if (artwork_info->dynamic_file_list != NULL) { for (i = 0; i < artwork_info->num_dynamic_file_list_entries; i++) { free(artwork_info->dynamic_file_list[i].token); free(artwork_info->dynamic_file_list[i].filename); free(artwork_info->dynamic_file_list[i].parameter); } free(artwork_info->dynamic_file_list); artwork_info->dynamic_file_list = NULL; FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list, &artwork_info->num_dynamic_file_list_entries); } /* free previous property mapping */ if (artwork_info->property_mapping != NULL) { free(artwork_info->property_mapping); artwork_info->property_mapping = NULL; artwork_info->num_property_mapping_entries = 0; } #if 1 if (!GFX_OVERRIDE_ARTWORK(artwork_info->type)) #else if (!SETUP_OVERRIDE_ARTWORK(setup, artwork_info->type)) #endif { /* first look for special artwork configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type); #if 0 printf("::: filename_base == '%s' [%s, %s]\n", filename_base, leveldir_current->graphics_set, leveldir_current->graphics_path); #endif if (fileExists(filename_base)) LoadArtworkConfigFromFilename(artwork_info, filename_base); } filename_local = getCustomArtworkConfigFilename(artwork_info->type); if (filename_local != NULL && !strEqual(filename_base, filename_local)) LoadArtworkConfigFromFilename(artwork_info, filename_local); } static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode) { if (*listnode) { char *filename = (*listnode)->source_filename; if (--(*listnode)->num_references <= 0) deleteNodeFromList(&artwork_info->content_list, filename, artwork_info->free_artwork); *listnode = NULL; } } static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode, struct FileInfo *file_list_entry) { char *init_text[] = { "Loading graphics", "Loading sounds", "Loading music" }; ListNode *node; char *basename = file_list_entry->filename; char *filename = getCustomArtworkFilename(basename, artwork_info->type); if (filename == NULL) { Error(ERR_WARN, "cannot find artwork file '%s'", basename); basename = file_list_entry->default_filename; /* fail for cloned default artwork that has no default filename defined */ if (file_list_entry->default_is_cloned && strEqual(basename, UNDEFINED_FILENAME)) { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "token '%s' was cloned and has no default filename", file_list_entry->token); return; } /* dynamic artwork has no default filename / skip empty default artwork */ if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME)) return; file_list_entry->fallback_to_default = TRUE; Error(ERR_WARN, "trying default artwork file '%s'", basename); filename = getCustomArtworkFilename(basename, artwork_info->type); if (filename == NULL) { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "cannot find default artwork file '%s'", basename); return; } } /* check if the old and the new artwork file are the same */ if (*listnode && strEqual((*listnode)->source_filename, filename)) { /* The old and new artwork are the same (have the same filename and path). This usually means that this artwork does not exist in this artwork set and a fallback to the existing artwork is done. */ #if 0 printf("[artwork '%s' already exists (same list entry)]\n", filename); #endif return; } /* delete existing artwork file entry */ deleteArtworkListEntry(artwork_info, listnode); /* check if the new artwork file already exists in the list of artworks */ if ((node = getNodeFromKey(artwork_info->content_list, filename)) != NULL) { #if 0 printf("[artwork '%s' already exists (other list entry)]\n", filename); #endif *listnode = (struct ListNodeInfo *)node->content; (*listnode)->num_references++; return; } DrawInitText(init_text[artwork_info->type], 120, FC_GREEN); DrawInitText(basename, 150, FC_YELLOW); if ((*listnode = artwork_info->load_artwork(filename)) != NULL) { #if 0 printf("[adding new artwork '%s']\n", filename); #endif (*listnode)->num_references = 1; addNodeToList(&artwork_info->content_list, (*listnode)->source_filename, *listnode); } else { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "cannot load artwork file '%s'", basename); return; } } static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode, struct FileInfo *file_list_entry) { #if 0 printf("GOT CUSTOM ARTWORK FILE '%s'\n", file_list_entry->filename); #endif if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME)) { deleteArtworkListEntry(artwork_info, listnode); return; } replaceArtworkListEntry(artwork_info, listnode, file_list_entry); } void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info) { struct FileInfo *file_list = artwork_info->file_list; struct FileInfo *dynamic_file_list = artwork_info->dynamic_file_list; int num_file_list_entries = artwork_info->num_file_list_entries; int num_dynamic_file_list_entries = artwork_info->num_dynamic_file_list_entries; int i; for (i = 0; i < num_file_list_entries; i++) LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i], &file_list[i]); for (i = 0; i < num_dynamic_file_list_entries; i++) LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i], &dynamic_file_list[i]); #if 0 dumpList(artwork_info->content_list); #endif } static void FreeCustomArtworkList(struct ArtworkListInfo *artwork_info, struct ListNodeInfo ***list, int *num_list_entries) { int i; if (*list == NULL) return; for (i = 0; i < *num_list_entries; i++) deleteArtworkListEntry(artwork_info, &(*list)[i]); free(*list); *list = NULL; *num_list_entries = 0; } void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info) { if (artwork_info == NULL) return; FreeCustomArtworkList(artwork_info, &artwork_info->artwork_list, &artwork_info->num_file_list_entries); FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list, &artwork_info->num_dynamic_file_list_entries); } /* ------------------------------------------------------------------------- */ /* functions only needed for non-Unix (non-command-line) systems */ /* (MS-DOS only; SDL/Windows creates files "stdout.txt" and "stderr.txt") */ /* (now also added for Windows, to create files in user data directory) */ /* ------------------------------------------------------------------------- */ char *getErrorFilename(char *basename) { return getPath2(getUserGameDataDir(), basename); } void openErrorFile() { InitUserDataDirectory(); if ((program.error_file = fopen(program.error_filename, MODE_WRITE)) == NULL) fprintf_newline(stderr, "ERROR: cannot open file '%s' for writing!", program.error_filename); } void closeErrorFile() { if (program.error_file != stderr) /* do not close stream 'stderr' */ fclose(program.error_file); } void dumpErrorFile() { FILE *error_file = fopen(program.error_filename, MODE_READ); if (error_file != NULL) { while (!feof(error_file)) fputc(fgetc(error_file), stderr); fclose(error_file); } } void NotifyUserAboutErrorFile() { #if defined(PLATFORM_WIN32) char *title_text = getStringCat2(program.program_title, " Error Message"); char *error_text = getStringCat2("The program was aborted due to an error; " "for details, see the following error file:" STRING_NEWLINE, program.error_filename); MessageBox(NULL, error_text, title_text, MB_OK); #endif } /* ------------------------------------------------------------------------- */ /* the following is only for debugging purpose and normally not used */ /* ------------------------------------------------------------------------- */ #if DEBUG #define DEBUG_NUM_TIMESTAMPS 5 #define DEBUG_TIME_IN_MICROSECONDS 0 #if DEBUG_TIME_IN_MICROSECONDS static double Counter_Microseconds() { static struct timeval base_time = { 0, 0 }; struct timeval current_time; double counter; gettimeofday(¤t_time, NULL); /* reset base time in case of wrap-around */ if (current_time.tv_sec < base_time.tv_sec) base_time = current_time; counter = ((double)(current_time.tv_sec - base_time.tv_sec)) * 1000000 + ((double)(current_time.tv_usec - base_time.tv_usec)); return counter; /* return microseconds since last init */ } #endif char *debug_print_timestamp_get_padding(int padding_size) { static char *padding = NULL; int max_padding_size = 100; if (padding == NULL) { padding = checked_calloc(max_padding_size + 1); memset(padding, ' ', max_padding_size); } return &padding[MAX(0, max_padding_size - padding_size)]; } void debug_print_timestamp(int counter_nr, char *message) { int indent_size = 8; int padding_size = 40; float timestamp_interval; if (counter_nr < 0) Error(ERR_EXIT, "debugging: invalid negative counter"); else if (counter_nr >= DEBUG_NUM_TIMESTAMPS) Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c"); #if DEBUG_TIME_IN_MICROSECONDS static double counter[DEBUG_NUM_TIMESTAMPS][2]; char *unit = "ms"; counter[counter_nr][0] = Counter_Microseconds(); #else static long counter[DEBUG_NUM_TIMESTAMPS][2]; char *unit = "s"; counter[counter_nr][0] = Counter(); #endif timestamp_interval = counter[counter_nr][0] - counter[counter_nr][1]; counter[counter_nr][1] = counter[counter_nr][0]; if (message) printf("%s%s%s %.3f %s\n", debug_print_timestamp_get_padding(counter_nr * indent_size), message, debug_print_timestamp_get_padding(padding_size - strlen(message)), timestamp_interval / 1000, unit); } void debug_print_parent_only(char *format, ...) { if (!IS_PARENT_PROCESS()) return; if (format) { va_list ap; va_start(ap, format); vprintf(format, ap); va_end(ap); printf("\n"); } } #endif rocksndiamonds-3.3.0.1+dfsg1/src/libgame/sdl.c0000644000175000017500000014071011355375765017767 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * sdl.c * ***********************************************************/ #include "system.h" #include "sound.h" #include "joystick.h" #include "misc.h" #include "setup.h" #if defined(TARGET_SDL) /* ========================================================================= */ /* video functions */ /* ========================================================================= */ /* functions from SGE library */ void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32); /* stuff needed to work around SDL/Windows fullscreen drawing bug */ static int fullscreen_width; static int fullscreen_height; static int fullscreen_xoffset; static int fullscreen_yoffset; static int video_xoffset; static int video_yoffset; static void setFullscreenParameters(char *fullscreen_mode_string) { struct ScreenModeInfo *fullscreen_mode; int i; fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string); if (fullscreen_mode == NULL) return; for (i = 0; video.fullscreen_modes[i].width != -1; i++) { if (fullscreen_mode->width == video.fullscreen_modes[i].width && fullscreen_mode->height == video.fullscreen_modes[i].height) { fullscreen_width = fullscreen_mode->width; fullscreen_height = fullscreen_mode->height; fullscreen_xoffset = (fullscreen_width - video.width) / 2; fullscreen_yoffset = (fullscreen_height - video.height) / 2; break; } } } static void SDLSetWindowIcon(char *basename) { /* (setting the window icon on Mac OS X would replace the high-quality dock icon with the currently smaller (and uglier) icon from file) */ #if !defined(PLATFORM_MACOSX) char *filename = getCustomImageFilename(basename); SDL_Surface *surface; if (filename == NULL) { Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename); return; } if ((surface = IMG_Load(filename)) == NULL) { Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError()); return; } /* set transparent color */ SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, 0x00, 0x00, 0x00)); SDL_WM_SetIcon(surface, NULL); #endif } void SDLInitVideoDisplay(void) { if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT)) SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver)); SDL_putenv("SDL_VIDEO_CENTERED=1"); /* initialize SDL video */ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError()); /* set default SDL depth */ video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel; } void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window, boolean fullscreen) { static int screen_xy[][2] = { { 640, 480 }, { 800, 600 }, { 1024, 768 }, { -1, -1 } }; SDL_Rect **modes; int i, j; /* default: normal game window size */ fullscreen_width = video.width; fullscreen_height = video.height; fullscreen_xoffset = 0; fullscreen_yoffset = 0; for (i = 0; screen_xy[i][0] != -1; i++) { if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height) { fullscreen_width = screen_xy[i][0]; fullscreen_height = screen_xy[i][1]; break; } } fullscreen_xoffset = (fullscreen_width - video.width) / 2; fullscreen_yoffset = (fullscreen_height - video.height) / 2; #if 1 checked_free(video.fullscreen_modes); video.fullscreen_modes = NULL; video.fullscreen_mode_current = NULL; #endif /* get available hardware supported fullscreen modes */ modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); if (modes == NULL) { /* no screen modes available => no fullscreen mode support */ video.fullscreen_available = FALSE; } else if (modes == (SDL_Rect **)-1) { /* fullscreen resolution is not restricted -- all resolutions available */ video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo)); /* use native video buffer size for fullscreen mode */ video.fullscreen_modes[0].width = video.width; video.fullscreen_modes[0].height = video.height; video.fullscreen_modes[1].width = -1; video.fullscreen_modes[1].height = -1; } else { /* in this case, a certain number of screen modes is available */ int num_modes = 0; for(i = 0; modes[i] != NULL; i++) { boolean found_mode = FALSE; /* screen mode is smaller than video buffer size -- skip it */ if (modes[i]->w < video.width || modes[i]->h < video.height) continue; if (video.fullscreen_modes != NULL) for (j = 0; video.fullscreen_modes[j].width != -1; j++) if (modes[i]->w == video.fullscreen_modes[j].width && modes[i]->h == video.fullscreen_modes[j].height) found_mode = TRUE; if (found_mode) /* screen mode already stored -- skip it */ continue; /* new mode found; add it to list of available fullscreen modes */ num_modes++; video.fullscreen_modes = checked_realloc(video.fullscreen_modes, (num_modes + 1) * sizeof(struct ScreenModeInfo)); video.fullscreen_modes[num_modes - 1].width = modes[i]->w; video.fullscreen_modes[num_modes - 1].height = modes[i]->h; video.fullscreen_modes[num_modes].width = -1; video.fullscreen_modes[num_modes].height = -1; } if (num_modes == 0) { /* no appropriate screen modes available => no fullscreen mode support */ video.fullscreen_available = FALSE; } } /* set window icon */ SDLSetWindowIcon(program.sdl_icon_filename); /* open SDL video output device (window or fullscreen mode) */ if (!SDLSetVideoMode(backbuffer, fullscreen)) Error(ERR_EXIT, "setting video mode failed"); /* set window and icon title */ SDL_WM_SetCaption(program.window_title, program.window_title); /* SDL cannot directly draw to the visible video framebuffer like X11, but always uses a backbuffer, which is then blitted to the visible video framebuffer with 'SDL_UpdateRect' (or replaced with the current visible video framebuffer with 'SDL_Flip', if the hardware supports this). Therefore do not use an additional backbuffer for drawing, but use a symbolic buffer (distinguishable from the SDL backbuffer) called 'window', which indicates that the SDL backbuffer should be updated to the visible video framebuffer when attempting to blit to it. For convenience, it seems to be a good idea to create this symbolic buffer 'window' at the same size as the SDL backbuffer. Although it should never be drawn to directly, it would do no harm nevertheless. */ /* create additional (symbolic) buffer for double-buffering */ #if 1 ReCreateBitmap(window, video.width, video.height, video.depth); #else *window = CreateBitmap(video.width, video.height, video.depth); #endif } boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen) { boolean success = TRUE; int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN; int surface_flags_window = SURFACE_FLAGS; SDL_Surface *new_surface = NULL; if (*backbuffer == NULL) *backbuffer = CreateBitmapStruct(); /* (real bitmap might be larger in fullscreen mode with video offsets) */ (*backbuffer)->width = video.width; (*backbuffer)->height = video.height; if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available) { setFullscreenParameters(setup.fullscreen_mode); video_xoffset = fullscreen_xoffset; video_yoffset = fullscreen_yoffset; /* switch display to fullscreen mode, if available */ if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height, video.depth, surface_flags_fullscreen)) == NULL) { /* switching display to fullscreen mode failed */ Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError()); /* do not try it again */ video.fullscreen_available = FALSE; success = FALSE; } else { (*backbuffer)->surface = new_surface; video.fullscreen_enabled = TRUE; video.fullscreen_mode_current = setup.fullscreen_mode; success = TRUE; } } if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL) { video_xoffset = 0; video_yoffset = 0; /* switch display to window mode */ if ((new_surface = SDL_SetVideoMode(video.width, video.height, video.depth, surface_flags_window)) == NULL) { /* switching display to window mode failed -- should not happen */ Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError()); success = FALSE; } else { (*backbuffer)->surface = new_surface; video.fullscreen_enabled = FALSE; success = TRUE; } } #if 1 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); #if defined(PLATFORM_WIN32) { SDL_SysWMinfo wminfo; HWND hwnd; SDL_VERSION(&wminfo.version); SDL_GetWMInfo(&wminfo); hwnd = wminfo.window; DragAcceptFiles(hwnd, TRUE); } #endif #endif return success; } void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height, int depth) { SDL_Surface *surface_tmp, *surface_native; if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0, 0, 0, 0)) == NULL) Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL) Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError()); SDL_FreeSurface(surface_tmp); new_bitmap->surface = surface_native; } void SDLFreeBitmapPointers(Bitmap *bitmap) { if (bitmap->surface) SDL_FreeSurface(bitmap->surface); if (bitmap->surface_masked) SDL_FreeSurface(bitmap->surface_masked); bitmap->surface = NULL; bitmap->surface_masked = NULL; } void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap); SDL_Rect src_rect, dst_rect; if (src_bitmap == backbuffer) { src_x += video_xoffset; src_y += video_yoffset; } src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; if (dst_bitmap == backbuffer || dst_bitmap == window) { dst_x += video_xoffset; dst_y += video_yoffset; } dst_rect.x = dst_x; dst_rect.y = dst_y; dst_rect.w = width; dst_rect.h = height; if (src_bitmap != backbuffer || dst_bitmap != window) SDL_BlitSurface((mask_mode == BLIT_MASKED ? src_bitmap->surface_masked : src_bitmap->surface), &src_rect, real_dst_bitmap->surface, &dst_rect); if (dst_bitmap == window) SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height); } void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height, Uint32 color) { Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap); SDL_Rect rect; if (dst_bitmap == backbuffer || dst_bitmap == window) { x += video_xoffset; y += video_yoffset; } rect.x = x; rect.y = y; rect.w = width; rect.h = height; SDL_FillRect(real_dst_bitmap->surface, &rect, color); if (dst_bitmap == window) SDL_UpdateRect(backbuffer->surface, x, y, width, height); } void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { static boolean initialization_needed = TRUE; static SDL_Surface *surface_source = NULL; static SDL_Surface *surface_target = NULL; static SDL_Surface *surface_black = NULL; SDL_Surface *surface_screen = backbuffer->surface; SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL); SDL_Rect src_rect, dst_rect; int src_x = x, src_y = y; int dst_x = x, dst_y = y; unsigned int time_last, time_current; /* check if screen size has changed */ if (surface_source != NULL && (video.width != surface_source->w || video.height != surface_source->h)) { SDL_FreeSurface(surface_source); SDL_FreeSurface(surface_target); SDL_FreeSurface(surface_black); initialization_needed = TRUE; } src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; dst_x += video_xoffset; dst_y += video_yoffset; dst_rect.x = dst_x; dst_rect.y = dst_y; dst_rect.w = width; /* (ignored) */ dst_rect.h = height; /* (ignored) */ if (initialization_needed) { unsigned int flags = SDL_SRCALPHA; /* use same surface type as screen surface */ if ((surface_screen->flags & SDL_HWSURFACE)) flags |= SDL_HWSURFACE; else flags |= SDL_SWSURFACE; /* create surface for temporary copy of screen buffer (source) */ if ((surface_source = SDL_CreateRGBSurface(flags, video.width, video.height, surface_screen->format->BitsPerPixel, surface_screen->format->Rmask, surface_screen->format->Gmask, surface_screen->format->Bmask, surface_screen->format->Amask)) == NULL) Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); /* create surface for cross-fading screen buffer (target) */ if ((surface_target = SDL_CreateRGBSurface(flags, video.width, video.height, surface_screen->format->BitsPerPixel, surface_screen->format->Rmask, surface_screen->format->Gmask, surface_screen->format->Bmask, surface_screen->format->Amask)) == NULL) Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); /* create black surface for fading from/to black */ if ((surface_black = SDL_CreateRGBSurface(flags, video.width, video.height, surface_screen->format->BitsPerPixel, surface_screen->format->Rmask, surface_screen->format->Gmask, surface_screen->format->Bmask, surface_screen->format->Amask)) == NULL) Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); /* completely fill the surface with black color pixels */ SDL_FillRect(surface_black, NULL, SDL_MapRGB(surface_screen->format, 0, 0, 0)); initialization_needed = FALSE; } /* copy source and target surfaces to temporary surfaces for fading */ if (fade_mode & FADE_TYPE_TRANSFORM) { SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect); SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect); } else if (fade_mode & FADE_TYPE_FADE_IN) { SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect); SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect); } else /* FADE_TYPE_FADE_OUT */ { SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect); SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect); } time_current = SDL_GetTicks(); if (fade_mode == FADE_MODE_MELT) { boolean done = FALSE; int melt_pixels = 2; int melt_columns = width / melt_pixels; int ypos[melt_columns]; int max_steps = height / 8 + 32; int steps_done = 0; float steps = 0; int i; SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */ ypos[0] = -GetSimpleRandom(16); for (i = 1 ; i < melt_columns; i++) { int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */ ypos[i] = ypos[i - 1] + r; if (ypos[i] > 0) ypos[i] = 0; else if (ypos[i] == -16) ypos[i] = -15; } while (!done) { int steps_final; time_last = time_current; time_current = SDL_GetTicks(); steps += max_steps * ((float)(time_current - time_last) / fade_delay); steps_final = MIN(MAX(0, steps), max_steps); steps_done++; done = (steps_done >= steps_final); for (i = 0 ; i < melt_columns; i++) { if (ypos[i] < 0) { ypos[i]++; done = FALSE; } else if (ypos[i] < height) { int y1 = 16; int y2 = 8; int y3 = 8; int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3); if (ypos[i] + dy >= height) dy = height - ypos[i]; /* copy part of (appearing) target surface to upper area */ src_rect.x = src_x + i * melt_pixels; // src_rect.y = src_y + ypos[i]; src_rect.y = src_y; src_rect.w = melt_pixels; // src_rect.h = dy; src_rect.h = ypos[i] + dy; dst_rect.x = dst_x + i * melt_pixels; // dst_rect.y = dst_y + ypos[i]; dst_rect.y = dst_y; if (steps_done >= steps_final) SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); ypos[i] += dy; /* copy part of (disappearing) source surface to lower area */ src_rect.x = src_x + i * melt_pixels; src_rect.y = src_y; src_rect.w = melt_pixels; src_rect.h = height - ypos[i]; dst_rect.x = dst_x + i * melt_pixels; dst_rect.y = dst_y + ypos[i]; if (steps_done >= steps_final) SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); done = FALSE; } else { src_rect.x = src_x + i * melt_pixels; src_rect.y = src_y; src_rect.w = melt_pixels; src_rect.h = height; dst_rect.x = dst_x + i * melt_pixels; dst_rect.y = dst_y; if (steps_done >= steps_final) SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); } } if (steps_done >= steps_final) { if (draw_border_function != NULL) draw_border_function(); SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height); } } } else { float alpha; int alpha_final; for (alpha = 0.0; alpha < 255.0;) { time_last = time_current; time_current = SDL_GetTicks(); alpha += 255 * ((float)(time_current - time_last) / fade_delay); alpha_final = MIN(MAX(0, alpha), 255); /* draw existing (source) image to screen buffer */ SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); /* draw new (target) image to screen buffer using alpha blending */ SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final); SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); if (draw_border_function != NULL) draw_border_function(); #if 1 /* only update the region of the screen that is affected from fading */ SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height); #else SDL_Flip(surface_screen); #endif } } Delay(post_delay); } void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y, int to_x, int to_y, Uint32 color) { SDL_Surface *surface = dst_bitmap->surface; SDL_Rect rect; if (from_x > to_x) swap_numbers(&from_x, &to_x); if (from_y > to_y) swap_numbers(&from_y, &to_y); rect.x = from_x; rect.y = from_y; rect.w = (to_x - from_x + 1); rect.h = (to_y - from_y + 1); if (dst_bitmap == backbuffer || dst_bitmap == window) { rect.x += video_xoffset; rect.y += video_yoffset; } SDL_FillRect(surface, &rect, color); } void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y, int to_x, int to_y, Uint32 color) { if (dst_bitmap == backbuffer || dst_bitmap == window) { from_x += video_xoffset; from_y += video_yoffset; to_x += video_xoffset; to_y += video_yoffset; } sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color); } #if 0 void SDLDrawLines(SDL_Surface *surface, struct XY *points, int num_points, Uint32 color) { int i, x, y; int line_width = 4; for (i = 0; i < num_points - 1; i++) { for (x = 0; x < line_width; x++) { for (y = 0; y < line_width; y++) { int dx = x - line_width / 2; int dy = y - line_width / 2; if ((x == 0 && y == 0) || (x == 0 && y == line_width - 1) || (x == line_width - 1 && y == 0) || (x == line_width - 1 && y == line_width - 1)) continue; sge_Line(surface, points[i].x + dx, points[i].y + dy, points[i+1].x + dx, points[i+1].y + dy, color); } } } } #endif Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y) { SDL_Surface *surface = src_bitmap->surface; if (src_bitmap == backbuffer || src_bitmap == window) { x += video_xoffset; y += video_yoffset; } switch (surface->format->BytesPerPixel) { case 1: /* assuming 8-bpp */ { return *((Uint8 *)surface->pixels + y * surface->pitch + x); } break; case 2: /* probably 15-bpp or 16-bpp */ { return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x); } break; case 3: /* slow 24-bpp mode; usually not used */ { /* does this work? */ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3; Uint32 color = 0; int shift; shift = surface->format->Rshift; color |= *(pix + shift / 8) >> shift; shift = surface->format->Gshift; color |= *(pix + shift / 8) >> shift; shift = surface->format->Bshift; color |= *(pix + shift / 8) >> shift; return color; } break; case 4: /* probably 32-bpp */ { return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x); } break; } return 0; } /* ========================================================================= */ /* The following functions were taken from the SGE library */ /* (SDL Graphics Extension Library) by Anders Lindström */ /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */ /* ========================================================================= */ void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1) { switch (surface->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color; } break; case 2: { /* Probably 15-bpp or 16-bpp */ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } break; case 4: { /* Probably 32-bpp */ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color; } break; } } } void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B) { _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B)); } void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint8 *)surface->pixels + y*surface->pitch + x) = color; } void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color; } void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color; } void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color) { switch (dest->format->BytesPerPixel) { case 1: *((Uint8 *)dest->pixels + y*dest->pitch + x) = color; break; case 2: *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color; break; case 3: _PutPixel24(dest,x,y,color); break; case 4: *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color; break; } } void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { if (SDL_MUSTLOCK(surface)) { if (SDL_LockSurface(surface) < 0) { return; } } _PutPixel(surface, x, y, color); if (SDL_MUSTLOCK(surface)) { SDL_UnlockSurface(surface); } } void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b) { sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b)); } Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y) { if (y >= 0 && y <= dest->h - 1) { switch (dest->format->BytesPerPixel) { case 1: return y*dest->pitch; break; case 2: return y*dest->pitch/2; break; case 3: return y*dest->pitch; break; case 4: return y*dest->pitch/4; break; } } return -1; } void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color) { if (x >= 0 && x <= surface->w - 1 && ypitch >= 0) { switch (surface->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ *((Uint8 *)surface->pixels + ypitch + x) = color; } break; case 2: { /* Probably 15-bpp or 16-bpp */ *((Uint16 *)surface->pixels + ypitch + x) = color; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + ypitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } break; case 4: { /* Probably 32-bpp */ *((Uint32 *)surface->pixels + ypitch + x) = color; } break; } } } void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) { SDL_Rect l; if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) { return; } } if (x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; } /* Do the clipping */ if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0) return; if (x1 < 0) x1 = 0; if (x2 > Surface->w - 1) x2 = Surface->w - 1; l.x = x1; l.y = y; l.w = x2 - x1 + 1; l.h = 1; SDL_FillRect(Surface, &l, Color); if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B) { sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B)); } void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) { SDL_Rect l; if (x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; } /* Do the clipping */ if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0) return; if (x1 < 0) x1 = 0; if (x2 > Surface->w - 1) x2 = Surface->w - 1; l.x = x1; l.y = y; l.w = x2 - x1 + 1; l.h = 1; SDL_FillRect(Surface, &l, Color); } void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) { SDL_Rect l; if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) { return; } } if (y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; } /* Do the clipping */ if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0) return; if (y1 < 0) y1 = 0; if (y2 > Surface->h - 1) y2 = Surface->h - 1; l.x = x; l.y = y1; l.w = 1; l.h = y2 - y1 + 1; SDL_FillRect(Surface, &l, Color); if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) { sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B)); } void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) { SDL_Rect l; if (y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; } /* Do the clipping */ if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0) return; if (y1 < 0) y1 = 0; if (y2 > Surface->h - 1) y2 = Surface->h - 1; l.x = x; l.y = y1; l.w = 1; l.h = y2 - y1 + 1; SDL_FillRect(Surface, &l, Color); } void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)) { Sint16 dx, dy, sdx, sdy, x, y, px, py; dx = x2 - x1; dy = y2 - y1; sdx = (dx < 0) ? -1 : 1; sdy = (dy < 0) ? -1 : 1; dx = sdx * dx + 1; dy = sdy * dy + 1; x = y = 0; px = x1; py = y1; if (dx >= dy) { for (x = 0; x < dx; x++) { Callback(Surface, px, py, Color); y += dy; if (y >= dx) { y -= dx; py += sdy; } px += sdx; } } else { for (y = 0; y < dy; y++) { Callback(Surface, px, py, Color); x += dx; if (x >= dy) { x -= dy; px += sdx; } py += sdy; } } } void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1, Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)) { sge_DoLine(Surface, X1, Y1, X2, Y2, SDL_MapRGB(Surface->format, R, G, B), Callback); } void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color) { if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) return; } /* Draw the line */ sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel); /* unlock the display */ if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) { sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B)); } void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel) { if (dst_bitmap == backbuffer || dst_bitmap == window) { x += video_xoffset; y += video_yoffset; } sge_PutPixel(dst_bitmap->surface, x, y, pixel); } /* ----------------------------------------------------------------------------- quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface ----------------------------------------------------------------------------- */ void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y, int width, int height, Uint32 color) { int x, y; for (y = src_y; y < src_y + height; y++) { for (x = src_x; x < src_x + width; x++) { Uint32 pixel = SDLGetPixel(bitmap, x, y); SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL); } } } void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y); if (pixel != BLACK_PIXEL) SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL); } } } /* ========================================================================= */ /* The following functions were taken from the SDL_gfx library version 2.0.3 */ /* (Rotozoomer) by Andreas Schiffler */ /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */ /* ========================================================================= */ /* ----------------------------------------------------------------------------- 32 bit zoomer zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface. ----------------------------------------------------------------------------- */ typedef struct { Uint8 r; Uint8 g; Uint8 b; Uint8 a; } tColorRGBA; int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst) { int x, y; tColorRGBA *sp, *csp, *dp; int sgap, dgap; /* pointer setup */ sp = csp = (tColorRGBA *) src->pixels; dp = (tColorRGBA *) dst->pixels; sgap = src->pitch - src->w * 4; dgap = dst->pitch - dst->w * 4; for (y = 0; y < dst->h; y++) { sp = csp; for (x = 0; x < dst->w; x++) { tColorRGBA *sp0 = sp; tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch); tColorRGBA *sp00 = &sp0[0]; tColorRGBA *sp01 = &sp0[1]; tColorRGBA *sp10 = &sp1[0]; tColorRGBA *sp11 = &sp1[1]; tColorRGBA new; /* create new color pixel from all four source color pixels */ new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4; new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4; new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4; new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4; /* draw */ *dp = new; /* advance source pointers */ sp += 2; /* advance destination pointer */ dp++; } /* advance source pointer */ csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch); /* advance destination pointers */ dp = (tColorRGBA *) ((Uint8 *) dp + dgap); } return 0; } int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst) { int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy; tColorRGBA *sp, *csp, *dp; int sgap, dgap; /* use specialized zoom function when scaling down to exactly half size */ if (src->w == 2 * dst->w && src->h == 2 * dst->h) return zoomSurfaceRGBA_scaleDownBy2(src, dst); /* variable setup */ sx = (int) (65536.0 * (float) src->w / (float) dst->w); sy = (int) (65536.0 * (float) src->h / (float) dst->h); /* allocate memory for row increments */ sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32)); say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32)); /* precalculate row increments */ csx = 0; csax = sax; for (x = 0; x <= dst->w; x++) { *csax = csx; csax++; csx &= 0xffff; csx += sx; } csy = 0; csay = say; for (y = 0; y <= dst->h; y++) { *csay = csy; csay++; csy &= 0xffff; csy += sy; } /* pointer setup */ sp = csp = (tColorRGBA *) src->pixels; dp = (tColorRGBA *) dst->pixels; sgap = src->pitch - src->w * 4; dgap = dst->pitch - dst->w * 4; csay = say; for (y = 0; y < dst->h; y++) { sp = csp; csax = sax; for (x = 0; x < dst->w; x++) { /* draw */ *dp = *sp; /* advance source pointers */ csax++; sp += (*csax >> 16); /* advance destination pointer */ dp++; } /* advance source pointer */ csay++; csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch); /* advance destination pointers */ dp = (tColorRGBA *) ((Uint8 *) dp + dgap); } free(sax); free(say); return 0; } /* ----------------------------------------------------------------------------- 8 bit zoomer zoomes 8 bit palette/Y 'src' surface to 'dst' surface ----------------------------------------------------------------------------- */ int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst) { Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy; Uint8 *sp, *dp, *csp; int dgap; /* variable setup */ sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w); sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h); /* allocate memory for row increments */ sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32)); say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32)); /* precalculate row increments */ csx = 0; csax = sax; for (x = 0; x < dst->w; x++) { csx += sx; *csax = (csx >> 16); csx &= 0xffff; csax++; } csy = 0; csay = say; for (y = 0; y < dst->h; y++) { csy += sy; *csay = (csy >> 16); csy &= 0xffff; csay++; } csx = 0; csax = sax; for (x = 0; x < dst->w; x++) { csx += (*csax); csax++; } csy = 0; csay = say; for (y = 0; y < dst->h; y++) { csy += (*csay); csay++; } /* pointer setup */ sp = csp = (Uint8 *) src->pixels; dp = (Uint8 *) dst->pixels; dgap = dst->pitch - dst->w; /* draw */ csay = say; for (y = 0; y < dst->h; y++) { csax = sax; sp = csp; for (x = 0; x < dst->w; x++) { /* draw */ *dp = *sp; /* advance source pointers */ sp += (*csax); csax++; /* advance destination pointer */ dp++; } /* advance source pointer (for row) */ csp += ((*csay) * src->pitch); csay++; /* advance destination pointers */ dp += dgap; } free(sax); free(say); return 0; } /* ----------------------------------------------------------------------------- zoomSurface() Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface. 'zoomx' and 'zoomy' are scaling factors for width and height. If the surface is not 8bit or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. ----------------------------------------------------------------------------- */ SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height) { SDL_Surface *zoom_src = NULL; SDL_Surface *zoom_dst = NULL; boolean is_converted = FALSE; boolean is_32bit; int i; if (src == NULL) return NULL; /* determine if source surface is 32 bit or 8 bit */ is_32bit = (src->format->BitsPerPixel == 32); if (is_32bit || src->format->BitsPerPixel == 8) { /* use source surface 'as is' */ zoom_src = src; } else { /* new source surface is 32 bit with a defined RGB ordering */ zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0); SDL_BlitSurface(src, NULL, zoom_src, NULL); is_32bit = TRUE; is_converted = TRUE; } /* allocate surface to completely contain the zoomed surface */ if (is_32bit) { /* target surface is 32 bit with source RGBA/ABGR ordering */ zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32, zoom_src->format->Rmask, zoom_src->format->Gmask, zoom_src->format->Bmask, 0); } else { /* target surface is 8 bit */ zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8, 0, 0, 0, 0); } /* lock source surface */ SDL_LockSurface(zoom_src); /* check which kind of surface we have */ if (is_32bit) { /* call the 32 bit transformation routine to do the zooming */ zoomSurfaceRGBA(zoom_src, zoom_dst); } else { /* copy palette */ for (i = 0; i < zoom_src->format->palette->ncolors; i++) zoom_dst->format->palette->colors[i] = zoom_src->format->palette->colors[i]; zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors; /* call the 8 bit transformation routine to do the zooming */ zoomSurfaceY(zoom_src, zoom_dst); } /* unlock source surface */ SDL_UnlockSurface(zoom_src); /* free temporary surface */ if (is_converted) SDL_FreeSurface(zoom_src); /* return destination surface */ return zoom_dst; } void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap) { SDL_Surface *sdl_surface_tmp; int dst_width = dst_bitmap->width; int dst_height = dst_bitmap->height; /* throw away old destination surface */ SDL_FreeSurface(dst_bitmap->surface); /* create zoomed temporary surface from source surface */ sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height); /* create native format destination surface from zoomed temporary surface */ dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp); /* free temporary surface */ SDL_FreeSurface(sdl_surface_tmp); } /* ========================================================================= */ /* load image to bitmap */ /* ========================================================================= */ Bitmap *SDLLoadImage(char *filename) { Bitmap *new_bitmap = CreateBitmapStruct(); SDL_Surface *sdl_image_tmp; /* load image to temporary surface */ if ((sdl_image_tmp = IMG_Load(filename)) == NULL) { SetError("IMG_Load(): %s", SDL_GetError()); return NULL; } UPDATE_BUSY_STATE(); /* create native non-transparent surface for current image */ if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL) { SetError("SDL_DisplayFormat(): %s", SDL_GetError()); return NULL; } UPDATE_BUSY_STATE(); /* create native transparent surface for current image */ SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY, SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00)); if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL) { SetError("SDL_DisplayFormat(): %s", SDL_GetError()); return NULL; } UPDATE_BUSY_STATE(); /* free temporary surface */ SDL_FreeSurface(sdl_image_tmp); new_bitmap->width = new_bitmap->surface->w; new_bitmap->height = new_bitmap->surface->h; return new_bitmap; } /* ------------------------------------------------------------------------- */ /* custom cursor fuctions */ /* ------------------------------------------------------------------------- */ static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info) { return SDL_CreateCursor(cursor_info->data, cursor_info->mask, cursor_info->width, cursor_info->height, cursor_info->hot_x, cursor_info->hot_y); } void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info) { static struct MouseCursorInfo *last_cursor_info = NULL; static struct MouseCursorInfo *last_cursor_info2 = NULL; static SDL_Cursor *cursor_default = NULL; static SDL_Cursor *cursor_current = NULL; /* if invoked for the first time, store the SDL default cursor */ if (cursor_default == NULL) cursor_default = SDL_GetCursor(); /* only create new cursor if cursor info (custom only) has changed */ if (cursor_info != NULL && cursor_info != last_cursor_info) { cursor_current = create_cursor(cursor_info); last_cursor_info = cursor_info; } /* only set new cursor if cursor info (custom or NULL) has changed */ if (cursor_info != last_cursor_info2) SDL_SetCursor(cursor_info ? cursor_current : cursor_default); last_cursor_info2 = cursor_info; } /* ========================================================================= */ /* audio functions */ /* ========================================================================= */ void SDLOpenAudio(void) { if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT)) SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver)); if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError()); return; } if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT, AUDIO_NUM_CHANNELS_STEREO, setup.system.audio_fragment_size) < 0) { Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError()); return; } audio.sound_available = TRUE; audio.music_available = TRUE; audio.loops_available = TRUE; audio.sound_enabled = TRUE; /* set number of available mixer channels */ audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS); audio.music_channel = MUSIC_CHANNEL; audio.first_sound_channel = FIRST_SOUND_CHANNEL; Mixer_InitChannels(); } void SDLCloseAudio(void) { Mix_HaltMusic(); Mix_HaltChannel(-1); Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); } /* ========================================================================= */ /* event functions */ /* ========================================================================= */ void SDLNextEvent(Event *event) { SDL_WaitEvent(event); if (event->type == EVENT_BUTTONPRESS || event->type == EVENT_BUTTONRELEASE) { if (((ButtonEvent *)event)->x > video_xoffset) ((ButtonEvent *)event)->x -= video_xoffset; else ((ButtonEvent *)event)->x = 0; if (((ButtonEvent *)event)->y > video_yoffset) ((ButtonEvent *)event)->y -= video_yoffset; else ((ButtonEvent *)event)->y = 0; } else if (event->type == EVENT_MOTIONNOTIFY) { if (((MotionEvent *)event)->x > video_xoffset) ((MotionEvent *)event)->x -= video_xoffset; else ((MotionEvent *)event)->x = 0; if (((MotionEvent *)event)->y > video_yoffset) ((MotionEvent *)event)->y -= video_yoffset; else ((MotionEvent *)event)->y = 0; } } void SDLHandleWindowManagerEvent(Event *event) { #if defined(PLATFORM_WIN32) SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event; SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg); if (syswmmsg->msg == WM_DROPFILES) { HDROP hdrop = (HDROP)syswmmsg->wParam; int i, num_files; printf("::: SDL_SYSWMEVENT:\n"); num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0); for (i = 0; i < num_files; i++) { int buffer_len = DragQueryFile(hdrop, i, NULL, 0); char buffer[buffer_len + 1]; DragQueryFile(hdrop, i, buffer, buffer_len + 1); printf("::: - '%s'\n", buffer); } DragFinish((HDROP)syswmmsg->wParam); } #endif } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL }; static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; static boolean SDLOpenJoystick(int nr) { if (nr < 0 || nr > MAX_PLAYERS) return FALSE; return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE); } static void SDLCloseJoystick(int nr) { if (nr < 0 || nr > MAX_PLAYERS) return; SDL_JoystickClose(sdl_joystick[nr]); } static boolean SDLCheckJoystickOpened(int nr) { if (nr < 0 || nr > MAX_PLAYERS) return FALSE; return (SDL_JoystickOpened(nr) ? TRUE : FALSE); } void HandleJoystickEvent(Event *event) { switch(event->type) { case SDL_JOYAXISMOTION: if (event->jaxis.axis < 2) sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value; break; case SDL_JOYBUTTONDOWN: if (event->jbutton.button < 2) sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE; break; case SDL_JOYBUTTONUP: if (event->jbutton.button < 2) sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE; break; default: break; } } void SDLInitJoysticks() { static boolean sdl_joystick_subsystem_initialized = FALSE; boolean print_warning = !sdl_joystick_subsystem_initialized; int i; if (!sdl_joystick_subsystem_initialized) { sdl_joystick_subsystem_initialized = TRUE; if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError()); return; } } for (i = 0; i < MAX_PLAYERS; i++) { /* get configured joystick for this player */ char *device_name = setup.input[i].joy.device_name; int joystick_nr = getJoystickNrFromDeviceName(device_name); if (joystick_nr >= SDL_NumJoysticks()) { if (setup.input[i].use_joystick && print_warning) Error(ERR_WARN, "cannot find joystick %d", joystick_nr); joystick_nr = -1; } /* misuse joystick file descriptor variable to store joystick number */ joystick.fd[i] = joystick_nr; if (joystick_nr == -1) continue; /* this allows subsequent calls to 'InitJoysticks' for re-initialization */ if (SDLCheckJoystickOpened(joystick_nr)) SDLCloseJoystick(joystick_nr); if (!setup.input[i].use_joystick) continue; if (!SDLOpenJoystick(joystick_nr)) { if (print_warning) Error(ERR_WARN, "cannot open joystick %d", joystick_nr); continue; } joystick.status = JOYSTICK_ACTIVATED; } } boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { if (nr < 0 || nr >= MAX_PLAYERS) return FALSE; if (x != NULL) *x = sdl_js_axis[nr][0]; if (y != NULL) *y = sdl_js_axis[nr][1]; if (b1 != NULL) *b1 = sdl_js_button[nr][0]; if (b2 != NULL) *b2 = sdl_js_button[nr][1]; return TRUE; } #endif /* TARGET_SDL */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/system.h0000644000175000017500000010777211403520460020523 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * system.h * ***********************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #include "platform.h" #include "types.h" #if defined(PLATFORM_MACOSX) #include "macosx.h" #elif defined(PLATFORM_WIN32) #include "windows.h" #elif defined(PLATFORM_MSDOS) #include "msdos.h" #endif #if defined(TARGET_SDL) #include "sdl.h" #elif defined(TARGET_X11) #include "x11.h" #endif /* the additional 'b' is needed for Win32 to open files in binary mode */ #define MODE_READ "rb" #define MODE_WRITE "wb" #define MODE_APPEND "ab" #define DEFAULT_DEPTH 0 #define BLIT_OPAQUE 0 #define BLIT_MASKED 1 #define BLIT_INVERSE 2 #define BLIT_ON_BACKGROUND 3 #define FULLSCREEN_NOT_AVAILABLE FALSE #define FULLSCREEN_AVAILABLE TRUE /* default input keys */ #define DEFAULT_KEY_LEFT KSYM_Left #define DEFAULT_KEY_RIGHT KSYM_Right #define DEFAULT_KEY_UP KSYM_Up #define DEFAULT_KEY_DOWN KSYM_Down #if defined(PLATFORM_MACOSX) #define DEFAULT_KEY_SNAP KSYM_Control_L #define DEFAULT_KEY_DROP KSYM_KP_Enter #else #define DEFAULT_KEY_SNAP KSYM_Control_L #define DEFAULT_KEY_DROP KSYM_Control_R #endif #define DEFAULT_KEY_OKAY KSYM_Return #define DEFAULT_KEY_CANCEL KSYM_Escape /* default shortcut keys */ #define DEFAULT_KEY_SAVE_GAME KSYM_F1 #define DEFAULT_KEY_LOAD_GAME KSYM_F2 #define DEFAULT_KEY_TOGGLE_PAUSE KSYM_space #define DEFAULT_KEY_FOCUS_PLAYER_1 KSYM_F5 #define DEFAULT_KEY_FOCUS_PLAYER_2 KSYM_F6 #define DEFAULT_KEY_FOCUS_PLAYER_3 KSYM_F7 #define DEFAULT_KEY_FOCUS_PLAYER_4 KSYM_F8 #define DEFAULT_KEY_FOCUS_PLAYER_ALL KSYM_F9 #define DEFAULT_KEY_TAPE_EJECT KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_STOP KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_PAUSE KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_RECORD KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_PLAY KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_SIMPLE KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_LOOPS KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_MUSIC KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_LEFT KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_RIGHT KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_UP KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_DOWN KSYM_UNDEFINED /* values for key_status */ #define KEY_NOT_PRESSED FALSE #define KEY_RELEASED FALSE #define KEY_PRESSED TRUE /* values for button status */ #define MB_NOT_PRESSED FALSE #define MB_NOT_RELEASED TRUE #define MB_RELEASED FALSE #define MB_PRESSED TRUE #define MB_MENU_CHOICE FALSE #define MB_MENU_MARK TRUE #define MB_MENU_INITIALIZE (-1) #define MB_MENU_LEAVE (-2) #define MB_LEFTBUTTON 1 #define MB_MIDDLEBUTTON 2 #define MB_RIGHTBUTTON 3 #define MB_WHEEL_UP 4 #define MB_WHEEL_DOWN 5 #define MB_WHEEL_LEFT 6 #define MB_WHEEL_RIGHT 7 #define IS_WHEEL_BUTTON_VERTICAL(b) ((b) >= MB_WHEEL_UP && \ (b) <= MB_WHEEL_DOWN) #define IS_WHEEL_BUTTON_HORIZONTAL(b) ((b) >= MB_WHEEL_LEFT && \ (b) <= MB_WHEEL_RIGHT) #define IS_WHEEL_BUTTON(b) ((b) >= MB_WHEEL_UP && \ (b) <= MB_WHEEL_DOWN) #define DEFAULT_WHEEL_STEPS 3 /* values for move directions */ #define MV_BIT_LEFT 0 #define MV_BIT_RIGHT 1 #define MV_BIT_UP 2 #define MV_BIT_DOWN 3 #define NUM_DIRECTIONS 4 /* diagonal movement directions are used in a different contect than buttons */ #define MV_BIT_UPLEFT 4 #define MV_BIT_UPRIGHT 5 #define MV_BIT_DOWNLEFT 6 #define MV_BIT_DOWNRIGHT 7 #define NUM_DIRECTIONS_FULL 8 /* values for special "button" bitmasks */ #define BUTTON_1 4 #define BUTTON_2 5 #define NUM_PLAYER_ACTIONS 6 /* values for special "focus player" bitmasks */ #define BIT_SET_FOCUS 6 /* values for move directions and special "button" key bitmasks */ #define MV_NONE 0 #define MV_LEFT (1 << MV_BIT_LEFT) #define MV_RIGHT (1 << MV_BIT_RIGHT) #define MV_UP (1 << MV_BIT_UP) #define MV_DOWN (1 << MV_BIT_DOWN) #define MV_UPLEFT (MV_UP | MV_LEFT) #define MV_UPRIGHT (MV_UP | MV_RIGHT) #define MV_DOWNLEFT (MV_DOWN | MV_LEFT) #define MV_DOWNRIGHT (MV_DOWN | MV_RIGHT) #define MV_HORIZONTAL (MV_LEFT | MV_RIGHT) #define MV_VERTICAL (MV_UP | MV_DOWN) #define MV_ALL_DIRECTIONS (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN) #define MV_ANY_DIRECTION (MV_ALL_DIRECTIONS) #define MV_NO_DIRECTION (MV_NONE) #define KEY_BUTTON_1 (1 << BUTTON_1) #define KEY_BUTTON_2 (1 << BUTTON_2) #define KEY_BUTTON_SNAP KEY_BUTTON_1 #define KEY_BUTTON_DROP KEY_BUTTON_2 #define KEY_MOTION (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN) #define KEY_BUTTON (KEY_BUTTON_1 | KEY_BUTTON_2) #define KEY_ACTION (KEY_MOTION | KEY_BUTTON) #define KEY_SET_FOCUS (1 << BIT_SET_FOCUS) #define MV_DIR_FROM_BIT(x) ((x) < NUM_DIRECTIONS ? 1 << (x) : \ (x) == MV_BIT_UPLEFT ? MV_UPLEFT : \ (x) == MV_BIT_UPRIGHT ? MV_UPRIGHT : \ (x) == MV_BIT_DOWNLEFT ? MV_DOWNLEFT : \ (x) == MV_BIT_DOWNRIGHT ? MV_DOWNRIGHT : \ MV_NONE) #define MV_DIR_TO_BIT(x) ((x) == MV_LEFT ? MV_BIT_LEFT : \ (x) == MV_RIGHT ? MV_BIT_RIGHT : \ (x) == MV_UP ? MV_BIT_UP : \ (x) == MV_DOWN ? MV_BIT_DOWN : \ (x) == MV_UPLEFT ? MV_BIT_UPLEFT : \ (x) == MV_UPRIGHT ? MV_BIT_UPRIGHT : \ (x) == MV_DOWNLEFT ? MV_BIT_DOWNLEFT : \ (x) == MV_DOWNRIGHT ? MV_BIT_DOWNRIGHT : \ MV_BIT_DOWN) #define MV_DIR_OPPOSITE(x) ((x) == MV_LEFT ? MV_RIGHT : \ (x) == MV_RIGHT ? MV_LEFT : \ (x) == MV_UP ? MV_DOWN : \ (x) == MV_DOWN ? MV_UP : \ (x) == MV_UPLEFT ? MV_DOWNRIGHT : \ (x) == MV_UPRIGHT ? MV_DOWNLEFT : \ (x) == MV_DOWNLEFT ? MV_UPRIGHT : \ (x) == MV_DOWNRIGHT ? MV_UPLEFT : \ MV_NONE) /* values for animation mode (frame order and direction) */ #define ANIM_NONE 0 #define ANIM_LOOP (1 << 0) #define ANIM_LINEAR (1 << 1) #define ANIM_PINGPONG (1 << 2) #define ANIM_PINGPONG2 (1 << 3) #define ANIM_RANDOM (1 << 4) #define ANIM_CE_VALUE (1 << 5) #define ANIM_CE_SCORE (1 << 6) #define ANIM_CE_DELAY (1 << 7) #define ANIM_REVERSE (1 << 8) #define ANIM_OPAQUE_PLAYER (1 << 9) /* values for special (non game element) animation modes */ #define ANIM_HORIZONTAL (1 << 10) #define ANIM_VERTICAL (1 << 11) #define ANIM_CENTERED (1 << 12) #define ANIM_STATIC_PANEL (1 << 13) #define ANIM_DEFAULT ANIM_LOOP /* values for special drawing styles (currently only for crumbled graphics) */ #define STYLE_NONE 0 #define STYLE_ACCURATE_BORDERS (1 << 0) #define STYLE_INNER_CORNERS (1 << 1) #define STYLE_DEFAULT STYLE_NONE /* values for fade mode */ #define FADE_TYPE_NONE 0 #define FADE_TYPE_FADE_IN (1 << 0) #define FADE_TYPE_FADE_OUT (1 << 1) #define FADE_TYPE_TRANSFORM (1 << 2) #define FADE_TYPE_CROSSFADE (1 << 3) #define FADE_TYPE_MELT (1 << 4) #define FADE_TYPE_SKIP (1 << 5) #define FADE_MODE_NONE (FADE_TYPE_NONE) #define FADE_MODE_FADE_IN (FADE_TYPE_FADE_IN) #define FADE_MODE_FADE_OUT (FADE_TYPE_FADE_OUT) #define FADE_MODE_FADE (FADE_TYPE_FADE_IN | FADE_TYPE_FADE_OUT) #define FADE_MODE_TRANSFORM (FADE_TYPE_TRANSFORM | FADE_TYPE_FADE_IN) #define FADE_MODE_CROSSFADE (FADE_MODE_TRANSFORM | FADE_TYPE_CROSSFADE) #define FADE_MODE_MELT (FADE_MODE_TRANSFORM | FADE_TYPE_MELT) #define FADE_MODE_SKIP_FADE_IN (FADE_TYPE_SKIP | FADE_TYPE_FADE_IN) #define FADE_MODE_SKIP_FADE_OUT (FADE_TYPE_SKIP | FADE_TYPE_FADE_OUT) #define FADE_MODE_DEFAULT FADE_MODE_FADE /* values for text alignment */ #define ALIGN_LEFT (1 << 0) #define ALIGN_RIGHT (1 << 1) #define ALIGN_CENTER (1 << 2) #define ALIGN_DEFAULT ALIGN_LEFT #define VALIGN_TOP (1 << 0) #define VALIGN_BOTTOM (1 << 1) #define VALIGN_MIDDLE (1 << 2) #define VALIGN_DEFAULT VALIGN_TOP #define ALIGNED_XPOS(x,w,a) ((a) == ALIGN_CENTER ? (x) - (w) / 2 : \ (a) == ALIGN_RIGHT ? (x) - (w) : (x)) #define ALIGNED_YPOS(y,h,v) ((v) == VALIGN_MIDDLE ? (y) - (h) / 2 : \ (v) == VALIGN_BOTTOM ? (y) - (h) : (y)) #define ALIGNED_TEXT_XPOS(p) ALIGNED_XPOS((p)->x, (p)->width, (p)->align) #define ALIGNED_TEXT_YPOS(p) ALIGNED_YPOS((p)->y, (p)->height, (p)->valign) /* values for redraw_mask */ #define REDRAW_NONE (0) #define REDRAW_ALL (1 << 0) #define REDRAW_FIELD (1 << 1) #define REDRAW_TILES (1 << 2) #define REDRAW_DOOR_1 (1 << 3) #define REDRAW_VIDEO_1 (1 << 4) #define REDRAW_VIDEO_2 (1 << 5) #define REDRAW_VIDEO_3 (1 << 6) #define REDRAW_MICROLEVEL (1 << 7) #define REDRAW_MICROLABEL (1 << 8) #define REDRAW_FROM_BACKBUFFER (1 << 9) #define REDRAW_DOOR_2 (REDRAW_VIDEO_1 | \ REDRAW_VIDEO_2 | \ REDRAW_VIDEO_3) #define REDRAW_DOOR_3 (1 << 10) #define REDRAW_DOORS (REDRAW_DOOR_1 | \ REDRAW_DOOR_2 | \ REDRAW_DOOR_3) #define REDRAW_MAIN (REDRAW_FIELD | \ REDRAW_TILES | \ REDRAW_MICROLEVEL) #define REDRAW_FPS (1 << 11) #define REDRAWTILES_THRESHOLD (SCR_FIELDX * SCR_FIELDY / 2) #define IN_GFX_SCREEN(x, y) (x >= gfx.sx && x < gfx.sx + gfx.sxsize && \ y >= gfx.sy && y < gfx.sy + gfx.sysize) #define IN_GFX_DOOR(x, y) (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \ y >= gfx.dy && y < gfx.dy + gfx.dysize) #define IN_GFX_VIDEO(x, y) (x >= gfx.vx && x < gfx.vx + gfx.vxsize && \ y >= gfx.vy && y < gfx.vy + gfx.vysize) /* values for mouse cursor */ #define CURSOR_DEFAULT 0 #define CURSOR_NONE 1 #define CURSOR_PLAYFIELD 2 /* fundamental game speed values */ #define ONE_SECOND_DELAY 1000 /* delay value for one second */ #define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */ #define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */ #define FRAMES_PER_SECOND (ONE_SECOND_DELAY / GAME_FRAME_DELAY) /* maximum playfield size supported by libgame functions */ #define MAX_PLAYFIELD_WIDTH 128 #define MAX_PLAYFIELD_HEIGHT 128 /* maximum number of parallel players supported by libgame functions */ #define MAX_PLAYERS 4 /* maximum allowed length of player name */ #define MAX_PLAYER_NAME_LEN 10 /* default name for empty highscore entry */ #define EMPTY_PLAYER_NAME "no name" /* default name for unknown player names */ #define ANONYMOUS_NAME "anonymous" /* default for other unknown names */ #define UNKNOWN_NAME "unknown" /* default name for new levels */ #define NAMELESS_LEVEL_NAME "nameless level" /* default text for non-existant artwork */ #define NOT_AVAILABLE "(not available)" /* default value for undefined filename */ #define UNDEFINED_FILENAME "[NONE]" /* default value for undefined parameter */ #define ARG_DEFAULT "[DEFAULT]" /* default values for undefined configuration file parameters */ #define ARG_UNDEFINED "-1000000" #define ARG_UNDEFINED_VALUE (atoi(ARG_UNDEFINED)) /* definitions for game sub-directories */ #ifndef RO_GAME_DIR #define RO_GAME_DIR "." #endif #ifndef RW_GAME_DIR #define RW_GAME_DIR "." #endif #define RO_BASE_PATH RO_GAME_DIR #define RW_BASE_PATH RW_GAME_DIR /* directory names */ #define GRAPHICS_DIRECTORY "graphics" #define SOUNDS_DIRECTORY "sounds" #define MUSIC_DIRECTORY "music" #define LEVELS_DIRECTORY "levels" #define TAPES_DIRECTORY "tapes" #define SCORES_DIRECTORY "scores" #define DOCS_DIRECTORY "docs" #define CACHE_DIRECTORY "cache" #if !defined(PLATFORM_MSDOS) #define GFX_CLASSIC_SUBDIR "gfx_classic" #define SND_CLASSIC_SUBDIR "snd_classic" #define MUS_CLASSIC_SUBDIR "mus_classic" #else #define GFX_CLASSIC_SUBDIR "gfx_orig" #define SND_CLASSIC_SUBDIR "snd_orig" #define MUS_CLASSIC_SUBDIR "mus_orig" #endif #if defined(CREATE_SPECIAL_EDITION_RND_JUE) #define GFX_DEFAULT_SUBDIR "jue0" #define SND_DEFAULT_SUBDIR "jue0" #define MUS_DEFAULT_SUBDIR "jue0" #else #define GFX_DEFAULT_SUBDIR GFX_CLASSIC_SUBDIR #define SND_DEFAULT_SUBDIR SND_CLASSIC_SUBDIR #define MUS_DEFAULT_SUBDIR MUS_CLASSIC_SUBDIR #endif #if defined(CREATE_SPECIAL_EDITION) #define GFX_FALLBACK_FILENAME "fallback.pcx" #define SND_FALLBACK_FILENAME "fallback.wav" #define MUS_FALLBACK_FILENAME "fallback.wav" #endif /* file names and filename extensions */ #if !defined(PLATFORM_MSDOS) #define LEVELSETUP_DIRECTORY "levelsetup" #define SETUP_FILENAME "setup.conf" #define LEVELSETUP_FILENAME "levelsetup.conf" #define EDITORSETUP_FILENAME "editorsetup.conf" #define EDITORCASCADE_FILENAME "editorcascade.conf" #define HELPANIM_FILENAME "helpanim.conf" #define HELPTEXT_FILENAME "helptext.conf" #define LEVELINFO_FILENAME "levelinfo.conf" #define GRAPHICSINFO_FILENAME "graphicsinfo.conf" #define SOUNDSINFO_FILENAME "soundsinfo.conf" #define MUSICINFO_FILENAME "musicinfo.conf" #define ARTWORKINFO_CACHE_FILE "artworkinfo.cache" #define LEVELFILE_EXTENSION "level" #define TAPEFILE_EXTENSION "tape" #define SCOREFILE_EXTENSION "score" #else #define LEVELSETUP_DIRECTORY "lvlsetup" #define SETUP_FILENAME "setup.cnf" #define LEVELSETUP_FILENAME "lvlsetup.cnf" #define EDITORSETUP_FILENAME "edsetup.cnf" #define EDITORCASCADE_FILENAME "edcascad.conf" #define HELPANIM_FILENAME "helpanim.cnf" #define HELPTEXT_FILENAME "helptext.cnf" #define LEVELINFO_FILENAME "lvlinfo.cnf" #define GRAPHICSINFO_FILENAME "gfxinfo.cnf" #define SOUNDSINFO_FILENAME "sndinfo.cnf" #define MUSICINFO_FILENAME "musinfo.cnf" #define ARTWORKINFO_CACHE_FILE "artinfo.cac" #define LEVELFILE_EXTENSION "lvl" #define TAPEFILE_EXTENSION "tap" #define SCOREFILE_EXTENSION "sco" #endif #define ERROR_BASENAME "stderr.txt" #define CHAR_PATH_SEPARATOR_UNIX '/' #define CHAR_PATH_SEPARATOR_DOS '\\' #define STRING_PATH_SEPARATOR_UNIX "/" #define STRING_PATH_SEPARATOR_DOS "\\" #define STRING_NEWLINE_UNIX "\n" #define STRING_NEWLINE_DOS "\r\n" #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS) #define CHAR_PATH_SEPARATOR CHAR_PATH_SEPARATOR_DOS #define STRING_PATH_SEPARATOR STRING_PATH_SEPARATOR_DOS #define STRING_NEWLINE STRING_NEWLINE_DOS #else #define CHAR_PATH_SEPARATOR CHAR_PATH_SEPARATOR_UNIX #define STRING_PATH_SEPARATOR STRING_PATH_SEPARATOR_UNIX #define STRING_NEWLINE STRING_NEWLINE_UNIX #endif /* areas in bitmap PIX_DOOR */ /* meaning in PIX_DB_DOOR: (3 PAGEs) PAGEX1: 1. buffer for DOOR_1 PAGEX2: 2. buffer for DOOR_1 PAGEX3: buffer for animations */ /* these values are hard-coded to be able to use them in initialization */ #define DOOR_GFX_PAGE_WIDTH 100 /* should be set to "gfx.dxsize" */ #define DOOR_GFX_PAGE_HEIGHT 280 /* should be set to "gfx.dysize" */ #define DOOR_GFX_PAGESIZE (DOOR_GFX_PAGE_WIDTH) #define DOOR_GFX_PAGEX1 (0 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX2 (1 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX3 (2 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX4 (3 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX5 (4 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX6 (5 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX7 (6 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX8 (7 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEY1 (0) #define DOOR_GFX_PAGEY2 (DOOR_GFX_PAGE_HEIGHT) /* macros for version handling */ #define VERSION_MAJOR(x) ((x) / 1000000) #define VERSION_MINOR(x) (((x) % 1000000) / 10000) #define VERSION_PATCH(x) (((x) % 10000) / 100) #define VERSION_BUILD(x) ((x) % 100) #define VERSION_IDENT(a,b,c,d) ((a) * 1000000 + (b) * 10000 + (c) * 100 + (d)) /* macros for parent/child process identification */ #if defined(PLATFORM_UNIX) #define IS_PARENT_PROCESS() (audio.mixer_pid != getpid()) #define IS_CHILD_PROCESS() (audio.mixer_pid == getpid()) #define HAS_CHILD_PROCESS() (audio.mixer_pid > 0) #else #define IS_PARENT_PROCESS() TRUE #define IS_CHILD_PROCESS() FALSE #define HAS_CHILD_PROCESS() FALSE #endif /* values for artwork type */ #define ARTWORK_TYPE_GRAPHICS 0 #define ARTWORK_TYPE_SOUNDS 1 #define ARTWORK_TYPE_MUSIC 2 #define NUM_ARTWORK_TYPES 3 /* values for tree type (chosen to match artwork type) */ #define TREE_TYPE_UNDEFINED -1 #define TREE_TYPE_GRAPHICS_DIR ARTWORK_TYPE_GRAPHICS #define TREE_TYPE_SOUNDS_DIR ARTWORK_TYPE_SOUNDS #define TREE_TYPE_MUSIC_DIR ARTWORK_TYPE_MUSIC #define TREE_TYPE_LEVEL_DIR 3 #define NUM_TREE_TYPES 4 #define INFOTEXT_UNDEFINED "" #define INFOTEXT_GRAPHICS_DIR "Custom Graphics" #define INFOTEXT_SOUNDS_DIR "Custom Sounds" #define INFOTEXT_MUSIC_DIR "Custom Music" #define INFOTEXT_LEVEL_DIR "Level Sets" #define TREE_INFOTEXT(t) ((t) == TREE_TYPE_LEVEL_DIR ? \ INFOTEXT_LEVEL_DIR : \ (t) == TREE_TYPE_GRAPHICS_DIR ? \ INFOTEXT_GRAPHICS_DIR : \ (t) == TREE_TYPE_SOUNDS_DIR ? \ INFOTEXT_SOUNDS_DIR : \ (t) == TREE_TYPE_MUSIC_DIR ? \ INFOTEXT_MUSIC_DIR : \ INFOTEXT_UNDEFINED) /* values for artwork handling */ #define LEVELDIR_ARTWORK_SET_PTR(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(leveldir)->graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(leveldir)->sounds_set : \ &(leveldir)->music_set) #define LEVELDIR_ARTWORK_SET(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (leveldir)->graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (leveldir)->sounds_set : \ (leveldir)->music_set) #define LEVELDIR_ARTWORK_PATH_PTR(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(leveldir)->graphics_path : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(leveldir)->sounds_path : \ &(leveldir)->music_path) #define LEVELDIR_ARTWORK_PATH(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (leveldir)->graphics_path : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (leveldir)->sounds_path : \ (leveldir)->music_path) #define SETUP_ARTWORK_SET(setup, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (setup).graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (setup).sounds_set : \ (setup).music_set) #define SETUP_OVERRIDE_ARTWORK(setup, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (setup).override_level_graphics : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (setup).override_level_sounds : \ (setup).override_level_music) #define GFX_OVERRIDE_ARTWORK(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ gfx.override_level_graphics : \ (type) == ARTWORK_TYPE_SOUNDS ? \ gfx.override_level_sounds : \ gfx.override_level_music) #define ARTWORK_FIRST_NODE(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (artwork).gfx_first : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (artwork).snd_first : \ (artwork).mus_first) #define ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(artwork).gfx_current_identifier : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(artwork).snd_current_identifier : \ &(artwork).mus_current_identifier) #define ARTWORK_CURRENT_IDENTIFIER(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (artwork).gfx_current_identifier : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (artwork).snd_current_identifier : \ (artwork).mus_current_identifier) #define ARTWORKINFO_FILENAME(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ GRAPHICSINFO_FILENAME : \ (type) == ARTWORK_TYPE_SOUNDS ? \ SOUNDSINFO_FILENAME : \ (type) == ARTWORK_TYPE_MUSIC ? \ MUSICINFO_FILENAME : "") #define ARTWORK_DIRECTORY(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ GRAPHICS_DIRECTORY : \ (type) == ARTWORK_TYPE_SOUNDS ? \ SOUNDS_DIRECTORY : \ (type) == ARTWORK_TYPE_MUSIC ? \ MUSIC_DIRECTORY : "") #define OPTIONS_ARTWORK_DIRECTORY(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ options.graphics_directory : \ (type) == ARTWORK_TYPE_SOUNDS ? \ options.sounds_directory : \ (type) == ARTWORK_TYPE_MUSIC ? \ options.music_directory : "") #define UPDATE_BUSY_STATE() \ { \ if (gfx.draw_busy_anim_function != NULL) \ gfx.draw_busy_anim_function(); \ } /* type definitions */ typedef int (*EventFilter)(const Event *); /* structure definitions */ struct ProgramInfo { char *command_basepath; /* directory that contains the program */ char *command_basename; /* base filename of the program binary */ char *userdata_subdir; /* personal user game data directory */ char *userdata_subdir_unix; /* personal user game data directory (Unix) */ char *userdata_path; /* resulting full path to game data directory */ char *program_title; char *window_title; char *icon_title; char *x11_icon_filename; char *x11_iconmask_filename; char *sdl_icon_filename; char *msdos_cursor_filename; char *cookie_prefix; char *filename_prefix; /* prefix to cut off from DOS filenames */ char *error_filename; /* filename where to write error messages to */ FILE *error_file; /* (used instead of 'stderr' on some systems) */ int version_major; int version_minor; int version_patch; void (*exit_function)(int); }; struct OptionInfo { char *display_name; char *server_host; int server_port; char *ro_base_directory; char *rw_base_directory; char *level_directory; char *graphics_directory; char *sounds_directory; char *music_directory; char *docs_directory; char *execute_command; char *special_flags; boolean serveronly; boolean network; boolean verbose; boolean debug; boolean debug_x11_sync; }; struct ScreenModeInfo { int width, height; }; struct VideoSystemInfo { int default_depth; int width, height, depth; boolean fullscreen_available; boolean fullscreen_enabled; struct ScreenModeInfo *fullscreen_modes; char *fullscreen_mode_current; }; struct AudioSystemInfo { boolean sound_available; boolean loops_available; boolean music_available; boolean sound_enabled; boolean sound_deactivated; /* for temporarily disabling sound */ int mixer_pipe[2]; int mixer_pid; char *device_name; int device_fd; int num_channels; int music_channel; int first_sound_channel; }; struct FontBitmapInfo { Bitmap *bitmap; int src_x, src_y; /* start position of animation frames */ int width, height; /* width/height of each animation frame */ int draw_xoffset; /* offset for drawing font characters */ int draw_yoffset; /* offset for drawing font characters */ int num_chars; int num_chars_per_line; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) Pixmap *clip_mask; /* single-char-only clip mask array for X11 */ #endif }; struct GfxInfo { int sx, sy; int sxsize, sysize; int real_sx, real_sy; int full_sxsize, full_sysize; int scrollbuffer_width, scrollbuffer_height; int dx, dy; int dxsize, dysize; int vx, vy; int vxsize, vysize; int win_xsize, win_ysize; int draw_deactivation_mask; int draw_background_mask; Bitmap *field_save_buffer; Bitmap *background_bitmap; int background_bitmap_mask; boolean clipping_enabled; int clip_x, clip_y; int clip_width, clip_height; boolean override_level_graphics; boolean override_level_sounds; boolean override_level_music; boolean draw_init_text; int num_fonts; struct FontBitmapInfo *font_bitmap_info; int (*select_font_function)(int); int (*get_font_from_token_function)(char *); int anim_random_frame; void (*draw_busy_anim_function)(void); }; struct JoystickInfo { int status; int fd[MAX_PLAYERS]; /* file descriptor of player's joystick */ }; struct SetupJoystickInfo { char *device_name; /* device name of player's joystick */ int xleft, xmiddle, xright; int yupper, ymiddle, ylower; int snap, drop; }; struct SetupKeyboardInfo { Key left, right, up, down; Key snap, drop; }; struct SetupInputInfo { boolean use_joystick; struct SetupJoystickInfo joy; struct SetupKeyboardInfo key; }; struct SetupEditorInfo { boolean el_boulderdash; boolean el_emerald_mine; boolean el_emerald_mine_club; boolean el_more; boolean el_sokoban; boolean el_supaplex; boolean el_diamond_caves; boolean el_dx_boulderdash; boolean el_chars; boolean el_steel_chars; boolean el_custom; boolean el_user_defined; boolean el_dynamic; boolean el_headlines; boolean el_by_game; boolean el_by_type; boolean show_element_token; }; struct SetupEditorCascadeInfo { boolean el_bd; boolean el_em; boolean el_emc; boolean el_rnd; boolean el_sb; boolean el_sp; boolean el_dc; boolean el_dx; boolean el_chars; boolean el_steel_chars; boolean el_ce; boolean el_ge; boolean el_ref; boolean el_user; boolean el_dynamic; }; struct SetupShortcutInfo { Key save_game; Key load_game; Key toggle_pause; Key focus_player[MAX_PLAYERS]; Key focus_player_all; Key tape_eject; Key tape_stop; Key tape_pause; Key tape_record; Key tape_play; Key sound_simple; Key sound_loops; Key sound_music; Key snap_left; Key snap_right; Key snap_up; Key snap_down; }; struct SetupSystemInfo { char *sdl_videodriver; char *sdl_audiodriver; int audio_fragment_size; }; struct SetupInfo { char *player_name; boolean sound; boolean sound_loops; boolean sound_music; boolean sound_simple; boolean toons; boolean scroll_delay; boolean scroll_delay_value; boolean soft_scrolling; boolean fade_screens; boolean autorecord; boolean show_titlescreen; boolean quick_doors; boolean team_mode; boolean handicap; boolean skip_levels; boolean time_limit; boolean fullscreen; char *fullscreen_mode; boolean ask_on_escape; boolean ask_on_escape_editor; boolean quick_switch; boolean input_on_focus; boolean prefer_aga_graphics; int game_frame_delay; boolean sp_show_border_elements; char *graphics_set; char *sounds_set; char *music_set; int override_level_graphics; /* not boolean -- can also be "AUTO" */ int override_level_sounds; /* not boolean -- can also be "AUTO" */ int override_level_music; /* not boolean -- can also be "AUTO" */ struct SetupEditorInfo editor; struct SetupEditorCascadeInfo editor_cascade; struct SetupShortcutInfo shortcut; struct SetupInputInfo input[MAX_PLAYERS]; struct SetupSystemInfo system; struct OptionInfo options; }; struct TreeInfo { struct TreeInfo **node_top; /* topmost node in tree */ struct TreeInfo *node_parent; /* parent level directory info */ struct TreeInfo *node_group; /* level group sub-directory info */ struct TreeInfo *next; /* next level series structure node */ int cl_first; /* internal control field for setup screen */ int cl_cursor; /* internal control field for setup screen */ int type; /* type of tree content */ /* fields for "type == TREE_TYPE_LEVEL_DIR" */ char *subdir; /* tree info sub-directory basename (may be ".") */ char *fullpath; /* complete path relative to tree base directory */ char *basepath; /* absolute base path of tree base directory */ char *identifier; /* identifier string for configuration files */ char *name; /* tree info name, as displayed in selection menues */ char *name_sorting; /* optional sorting name for correct name sorting */ char *author; /* level or artwork author name */ char *year; /* optional year of creation for levels or artwork */ char *imported_from; /* optional comment for imported levels or artwork */ char *imported_by; /* optional comment for imported levels or artwork */ char *tested_by; /* optional comment to name people who tested a set */ char *graphics_set_ecs; /* special EMC custom graphics set (ECS graphics) */ char *graphics_set_aga; /* special EMC custom graphics set (AGA graphics) */ char *graphics_set; /* optional custom graphics set (level tree only) */ char *sounds_set; /* optional custom sounds set (level tree only) */ char *music_set; /* optional custom music set (level tree only) */ char *graphics_path; /* path to optional custom graphics set (level only) */ char *sounds_path; /* path to optional custom sounds set (level only) */ char *music_path; /* path to optional custom music set (level only) */ char *level_filename; /* filename of level file (for packed level file) */ char *level_filetype; /* type of levels in level directory or level file */ char *special_flags; /* flags for special actions performed on level file */ int levels; /* number of levels in level series */ int first_level; /* first level number (to allow start with 0 or 1) */ int last_level; /* last level number (automatically calculated) */ int sort_priority; /* sort levels by 'sort_priority' and then by name */ boolean latest_engine;/* force level set to use the latest game engine */ boolean level_group; /* directory contains more level series directories */ boolean parent_link; /* entry links back to parent directory */ boolean in_user_dir; /* user defined levels are stored in home directory */ boolean user_defined; /* levels in user directory and marked as "private" */ boolean readonly; /* readonly levels can not be changed with editor */ boolean handicap; /* level set has no handicap when set to "false" */ boolean skip_levels; /* levels can be skipped when set to "true" */ int color; /* color to use on selection screen for this level */ char *class_desc; /* description of level series class */ int handicap_level; /* number of the lowest unsolved level */ char *infotext; /* optional text to describe the tree type (headline) */ }; typedef struct TreeInfo TreeInfo; typedef struct TreeInfo LevelDirTree; typedef struct TreeInfo ArtworkDirTree; typedef struct TreeInfo GraphicsDirTree; typedef struct TreeInfo SoundsDirTree; typedef struct TreeInfo MusicDirTree; struct ArtworkInfo { GraphicsDirTree *gfx_first; GraphicsDirTree *gfx_current; SoundsDirTree *snd_first; SoundsDirTree *snd_current; MusicDirTree *mus_first; MusicDirTree *mus_current; char *gfx_current_identifier; char *snd_current_identifier; char *mus_current_identifier; }; struct ValueTextInfo { int value; char *text; }; struct ConfigInfo { char *token; char *value; }; struct ConfigTypeInfo { char *token; char *value; int type; }; struct TokenIntPtrInfo { char *token; int *value; }; struct FileInfo { char *token; char *default_filename; char *filename; char **default_parameter; /* array of file parameters */ char **parameter; /* array of file parameters */ boolean redefined; boolean fallback_to_default; boolean default_is_cloned; }; struct SetupFileList { char *token; char *value; struct SetupFileList *next; }; struct ListNodeInfo { char *source_filename; /* primary key for node list */ int num_references; }; struct PropertyMapping { int base_index; int ext1_index; int ext2_index; int ext3_index; int artwork_index; }; struct ArtworkListInfo { int type; /* type of artwork */ int num_file_list_entries; int num_dynamic_file_list_entries; struct FileInfo *file_list; /* static artwork file array */ struct FileInfo *dynamic_file_list; /* dynamic artwrk file array */ int num_suffix_list_entries; struct ConfigTypeInfo *suffix_list; /* parameter suffixes array */ int num_base_prefixes; int num_ext1_suffixes; int num_ext2_suffixes; int num_ext3_suffixes; char **base_prefixes; /* base token prefixes array */ char **ext1_suffixes; /* property suffixes array 1 */ char **ext2_suffixes; /* property suffixes array 2 */ char **ext3_suffixes; /* property suffixes array 3 */ int num_ignore_tokens; char **ignore_tokens; /* file tokens to be ignored */ int num_property_mapping_entries; struct PropertyMapping *property_mapping; /* mapping token -> artwork */ int sizeof_artwork_list_entry; struct ListNodeInfo **artwork_list; /* static artwork node array */ struct ListNodeInfo **dynamic_artwork_list; /* dynamic artwrk node array */ struct ListNode *content_list; /* dynamic artwork node list */ void *(*load_artwork)(char *); /* constructor function */ void (*free_artwork)(void *); /* destructor function */ }; struct XY { int x, y; }; struct Rect { int x, y; int width, height; }; struct RectWithBorder { int x, y; int width, height; int border_size; }; struct MenuPosInfo { int x, y; int width, height; int align, valign; }; struct TextPosInfo { int x, y; int width, height; int align, valign; int size; int font, font_alt; boolean draw_masked; int sort_priority; int id; }; /* ========================================================================= */ /* exported variables */ /* ========================================================================= */ extern struct ProgramInfo program; extern struct OptionInfo options; extern struct VideoSystemInfo video; extern struct AudioSystemInfo audio; extern struct GfxInfo gfx; extern struct AnimInfo anim; extern struct ArtworkInfo artwork; extern struct JoystickInfo joystick; extern struct SetupInfo setup; extern LevelDirTree *leveldir_first_all; extern LevelDirTree *leveldir_first; extern LevelDirTree *leveldir_current; extern int level_nr; extern Display *display; extern Visual *visual; extern int screen; extern Colormap cmap; extern DrawWindow *window; extern DrawBuffer *backbuffer; extern DrawBuffer *drawto; extern int button_status; extern boolean motion_status; extern int redraw_mask; extern int redraw_tiles; extern int FrameCounter; /* function definitions */ void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int); void InitExitFunction(void (*exit_function)(int)); void InitPlatformDependentStuff(void); void ClosePlatformDependentStuff(void); void InitGfxFieldInfo(int, int, int, int, int, int, int, int, Bitmap *); void InitGfxDoor1Info(int, int, int, int); void InitGfxDoor2Info(int, int, int, int); void InitGfxWindowInfo(int, int); void InitGfxScrollbufferInfo(int, int); void InitGfxClipRegion(boolean, int, int, int, int); void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)); void InitGfxCustomArtworkInfo(); void SetDrawDeactivationMask(int); void SetDrawBackgroundMask(int); void SetWindowBackgroundBitmap(Bitmap *); void SetMainBackgroundBitmap(Bitmap *); void SetDoorBackgroundBitmap(Bitmap *); void InitVideoDisplay(void); void CloseVideoDisplay(void); void InitVideoBuffer(int, int, int, boolean); Bitmap *CreateBitmapStruct(void); Bitmap *CreateBitmap(int, int, int); void ReCreateBitmap(Bitmap **, int, int, int); void FreeBitmap(Bitmap *); void BlitBitmap(Bitmap *, Bitmap *, int, int, int, int, int, int); void FadeRectangle(Bitmap *bitmap, int, int, int, int, int, int, int, void (*draw_border_function)(void)); void FillRectangle(Bitmap *, int, int, int, int, Pixel); void ClearRectangle(Bitmap *, int, int, int, int); void ClearRectangleOnBackground(Bitmap *, int, int, int, int); void SetClipMask(Bitmap *, GC, Pixmap); void SetClipOrigin(Bitmap *, GC, int, int); void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int); boolean DrawingOnBackground(int, int); void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int, int); void DrawSimpleBlackLine(Bitmap *, int, int, int, int); void DrawSimpleWhiteLine(Bitmap *, int, int, int, int); void DrawLines(Bitmap *, struct XY *, int, Pixel); Pixel GetPixel(Bitmap *, int, int); Pixel GetPixelFromRGB(Bitmap *, unsigned int,unsigned int,unsigned int); Pixel GetPixelFromRGBcompact(Bitmap *, unsigned int); void FlushDisplay(void); void SyncDisplay(void); void KeyboardAutoRepeatOn(void); void KeyboardAutoRepeatOff(void); boolean PointerInWindow(DrawWindow *); boolean SetVideoMode(boolean); boolean ChangeVideoModeIfNeeded(boolean); Bitmap *LoadImage(char *); Bitmap *LoadCustomImage(char *); void ReloadCustomImage(Bitmap *, char *); Bitmap *ZoomBitmap(Bitmap *, int, int); void CreateBitmapWithSmallBitmaps(Bitmap *, int); void ScaleBitmap(Bitmap *, int); void SetMouseCursor(int); void OpenAudio(void); void CloseAudio(void); void SetAudioMode(boolean); void InitEventFilter(EventFilter); boolean PendingEvent(void); void NextEvent(Event *event); void PeekEvent(Event *event); Key GetEventKey(KeyEvent *, boolean); KeyMod HandleKeyModState(Key, int); KeyMod GetKeyModState(); KeyMod GetKeyModStateFromEvents(); boolean CheckCloseWindowEvent(ClientMessageEvent *); void InitJoysticks(); boolean ReadJoystick(int, int *, int *, boolean *, boolean *); #endif /* SYSTEM_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/text.h0000644000175000017500000000641611364305110020153 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * text.h * ***********************************************************/ #ifndef TEXT_H #define TEXT_H #include "system.h" /* default fonts */ #define FONT_INITIAL_1 0 #define FONT_INITIAL_2 1 #define FONT_INITIAL_3 2 #define FONT_INITIAL_4 3 /* font colors */ #define FC_RED FONT_INITIAL_1 #define FC_BLUE FONT_INITIAL_2 #define FC_GREEN FONT_INITIAL_3 #define FC_YELLOW FONT_INITIAL_4 /* text output definitions */ #define MAX_OUTPUT_LINESIZE 1024 /* special character mapping for default fonts */ #define FONT_ASCII_CURSOR ((char)160) #define FONT_ASCII_BUTTON ((char)128) #define FONT_ASCII_UP ((char)129) #define FONT_ASCII_DOWN ((char)130) #define FONT_ASCII_LEFT ((char)'<') #define FONT_ASCII_RIGHT ((char)'>') #define MAP_FONT_ASCII(c) ((c) >= 'a' && (c) <= 'z' ? 'A' + (c) - 'a' : \ (c) == '©' ? 96 : \ (c) == 'ä' || (c) == 'Ä' ? 97 : \ (c) == 'ö' || (c) == 'Ö' ? 98 : \ (c) == 'ü' || (c) == 'Ü' ? 99 : \ (c) == '°' ? 100 : \ (c) == '®' ? 101 : \ (c) == FONT_ASCII_CURSOR ? 102 : \ (c) == FONT_ASCII_BUTTON ? 109 : \ (c) == FONT_ASCII_UP ? 110 : \ (c) == FONT_ASCII_DOWN ? 111 : \ (c)) /* 64 regular ordered ASCII characters, 6 special characters, 1 cursor char. */ #define MIN_NUM_CHARS_PER_FONT 64 #define DEFAULT_NUM_CHARS_PER_FONT (MIN_NUM_CHARS_PER_FONT + 6 +1) #define DEFAULT_NUM_CHARS_PER_LINE 16 /* font structure definitions */ void InitFontInfo(struct FontBitmapInfo *, int, int (*function1)(int), int (*function2)(char *)); void FreeFontInfo(struct FontBitmapInfo *); struct FontBitmapInfo *getFontBitmapInfo(int); int getFontWidth(int); int getFontHeight(int); int getTextWidth(char *, int); void getFontCharSource(int, char, Bitmap **, int *, int *); int maxWordLengthInString(char *); void DrawInitText(char *, int, int); void DrawInitTextIfNeeded(char *, int, int); void DrawInitTextExt(char *, int, int, boolean); void DrawTextF(int, int, int, char *, ...); void DrawTextFCentered(int, int, char *, ...); void DrawTextS(int, int, int, char *); void DrawTextSCentered(int, int, char *); void DrawTextCentered(int, int, char *); void DrawTextSAligned(int, int, char *, int, int); void DrawTextAligned(int, int, char *, int, int); void DrawText(int, int, char *, int); void DrawTextExt(DrawBuffer *, int, int, char *, int, int); char *GetTextBufferFromFile(char *, int); int DrawTextBuffer(int, int, char *, int, int, int, int, int, int, boolean, boolean, boolean); int DrawTextFile(int, int, char *, int, int, int, int, int, int, boolean, boolean, boolean); #endif /* TEXT_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/image.c0000644000175000017500000007360410701256301020250 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * image.c * ***********************************************************/ #include "image.h" #include "pcx.h" #include "misc.h" #include "setup.h" /* ========================================================================= */ /* PLATFORM SPECIFIC IMAGE FUNCTIONS */ /* ========================================================================= */ #if defined(TARGET_X11) /* for MS-DOS/Allegro, exclude all except newImage() and freeImage() */ Image *newImage(unsigned int width, unsigned int height, unsigned int depth) { Image *image; unsigned int bytes_per_pixel = (depth + 7) / 8; int i; image = checked_calloc(sizeof(Image)); image->data = checked_calloc(width * height * bytes_per_pixel); image->width = width; image->height = height; image->depth = depth; image->bytes_per_pixel = bytes_per_pixel; image->bytes_per_row = width * bytes_per_pixel; image->rgb.used = 0; for (i = 0; i < MAX_COLORS; i++) image->rgb.color_used[i] = FALSE; image->type = (depth < 8 ? IMAGETYPE_BITMAP : depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB); return image; } void freeImage(Image *image) { free(image->data); free(image); } #if defined(PLATFORM_UNIX) /* extra colors to try allocating in private color maps to minimize flashing */ #define NOFLASH_COLORS 256 /* architecture independent value <-> memory conversions; note: the internal format is big endian */ #define memory_to_value(ptr, len) ( \ (len) == 1 ? (unsigned long)( *( (byte *)(ptr)) ) : \ (len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<< 8) \ + ( *(((byte *)(ptr))+1) ) : \ (len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<16) \ + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8) \ + ( *(((byte *)(ptr))+2) ) : \ (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<24) \ + (((unsigned long)(*(((byte *)(ptr))+1)))<<16) \ + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8) \ + ( *(((byte *)(ptr))+3) ) ) #define value_to_memory(value, ptr, len) ( \ (len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ (len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ *(((byte *)(ptr))+1) = ( value ) ) : \ (len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ *(((byte *)(ptr))+2) = ( value ) ) : \ (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \ *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \ *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \ *(((byte *)(ptr))+3) = ( value ) )) static Pixmap Image_to_Mask(Image *image, Display *display, Window window) { byte *src_ptr, *dst_ptr, *dst_ptr2; unsigned int bytes_per_row; unsigned int x, y, i; byte bitmask; byte *mask_data; Pixmap mask_pixmap; bytes_per_row = (image->width + 7) / 8; mask_data = checked_calloc(bytes_per_row * image->height); src_ptr = image->data; dst_ptr = mask_data; /* create bitmap data which can be used by 'XCreateBitmapFromData()' * directly to create a pixmap of depth 1 for use as a clip mask for * the corresponding image pixmap */ for (y = 0; y < image->height; y++) { bitmask = 0x01; /* start with leftmost bit in the byte */ dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ for (x = 0; x < image->width; x++) { for (i = 0; i < image->bytes_per_pixel; i++) if (*src_ptr++) /* source pixel solid? (pixel index != 0) */ *dst_ptr2 |= bitmask; /* then write a bit into the image mask */ if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */ { bitmask = 0x01; /* start again with leftmost bit position */ dst_ptr2++; /* continue with next byte in image mask */ } } dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */ } if ((mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data, image->width, image->height)) == None) Error(ERR_EXIT, "Image_to_Mask(): XCreateBitmapFromData() failed"); free(mask_data); return mask_pixmap; } Pixmap Pixmap_to_Mask(Pixmap src_pixmap, int src_width, int src_height) { XImage *src_ximage; byte *src_ptr, *dst_ptr, *dst_ptr2; int bits_per_pixel; int bytes_per_pixel; unsigned int bytes_per_row; unsigned int x, y, i; byte bitmask; byte *mask_data; Pixmap mask_pixmap; /* copy source pixmap to temporary image */ if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height, AllPlanes, ZPixmap)) == NULL) Error(ERR_EXIT, "Pixmap_to_Mask(): XGetImage() failed"); bits_per_pixel = src_ximage->bits_per_pixel; bytes_per_pixel = (bits_per_pixel + 7) / 8; bytes_per_row = (src_width + 7) / 8; mask_data = checked_calloc(bytes_per_row * src_height); src_ptr = (byte *)src_ximage->data; dst_ptr = mask_data; /* create bitmap data which can be used by 'XCreateBitmapFromData()' * directly to create a pixmap of depth 1 for use as a clip mask for * the corresponding image pixmap */ for (y = 0; y < src_height; y++) { bitmask = 0x01; /* start with leftmost bit in the byte */ dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ for (x = 0; x < src_width; x++) { for (i = 0; i < bytes_per_pixel; i++) if (*src_ptr++) /* source pixel solid? (pixel index != 0) */ *dst_ptr2 |= bitmask; /* then write a bit into the image mask */ if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */ { bitmask = 0x01; /* start again with leftmost bit position */ dst_ptr2++; /* continue with next byte in image mask */ } } dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */ } if ((mask_pixmap = XCreateBitmapFromData(display, window->drawable, (char *)mask_data, src_width, src_height)) == None) Error(ERR_EXIT, "Pixmap_to_Mask(): XCreateBitmapFromData() failed"); free(mask_data); return mask_pixmap; } static int bitsPerPixelAtDepth(Display *display, int screen, int depth) { XPixmapFormatValues *pixmap_format; int i, num_pixmap_formats, bits_per_pixel = -1; /* get Pixmap formats supported by the X server */ pixmap_format = XListPixmapFormats(display, &num_pixmap_formats); /* find format that matches the given depth */ for (i = 0; i < num_pixmap_formats; i++) if (pixmap_format[i].depth == depth) bits_per_pixel = pixmap_format[i].bits_per_pixel; XFree(pixmap_format); if (bits_per_pixel == -1) Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth); return bits_per_pixel; } XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, Window window, GC gc, int depth, Image *image) { static XColor xcolor_private[NOFLASH_COLORS]; static int colorcell_used[NOFLASH_COLORS]; static Colormap global_cmap = 0; static Pixel *global_cmap_index; static int num_cmap_entries, free_cmap_entries; static boolean private_cmap = FALSE; Pixel *redvalue, *greenvalue, *bluevalue; unsigned int display_bytes_per_pixel, display_bits_per_pixel; unsigned int a, c = 0, x, y; XColor xcolor; XImage *ximage; XImageInfo *ximageinfo; byte *src_ptr, *dst_ptr; char *error = "Image_to_Pixmap(): %s"; if (image->type == IMAGETYPE_TRUECOLOR && depth == 8) { SetError(error, "cannot handle true-color images on 8-bit display"); return NULL; } if (!global_cmap) { if (visual == DefaultVisual(display, screen)) global_cmap = DefaultColormap(display, screen); else { global_cmap = XCreateColormap(display, RootWindow(display, screen), visual, AllocNone); private_cmap = TRUE; } } xcolor.flags = DoRed | DoGreen | DoBlue; redvalue = greenvalue = bluevalue = NULL; ximageinfo = checked_malloc(sizeof(XImageInfo)); ximageinfo->display = display; ximageinfo->depth = depth; switch (visual->class) { case TrueColor: case DirectColor: { Pixel pixval; unsigned int redcolors, greencolors, bluecolors; unsigned int redstep, greenstep, bluestep; unsigned int redbottom, greenbottom, bluebottom; unsigned int redtop, greentop, bluetop; redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); ximageinfo->cmap = global_cmap; retry_direct: /* tag we hit if a DirectColor allocation fails on * default colormap */ /* calculate number of distinct colors in each band */ redcolors = greencolors = bluecolors = 1; for (pixval = 1; pixval; pixval <<= 1) { if (pixval & visual->red_mask) redcolors <<= 1; if (pixval & visual->green_mask) greencolors <<= 1; if (pixval & visual->blue_mask) bluecolors <<= 1; } /* consistency check */ if (redcolors > visual->map_entries || greencolors > visual->map_entries || bluecolors > visual->map_entries) Error(ERR_WARN, "inconsistency in color information"); redstep = 256 / redcolors; greenstep = 256 / greencolors; bluestep = 256 / bluecolors; redbottom = greenbottom = bluebottom = 0; redtop = greentop = bluetop = 0; for (a = 0; a < visual->map_entries; a++) { if (redbottom < 256) redtop = redbottom + redstep; if (greenbottom < 256) greentop = greenbottom + greenstep; if (bluebottom < 256) bluetop = bluebottom + bluestep; xcolor.red = (redtop - 1) << 8; xcolor.green = (greentop - 1) << 8; xcolor.blue = (bluetop - 1) << 8; if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) { /* if an allocation fails for a DirectColor default visual then we should create a private colormap and try again. */ if ((visual->class == DirectColor) && (visual == DefaultVisual(display, screen))) { global_cmap = XCopyColormapAndFree(display, global_cmap); ximageinfo->cmap = global_cmap; private_cmap = TRUE; goto retry_direct; } /* something completely unexpected happened */ fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n"); free(redvalue); free(greenvalue); free(bluevalue); free(ximageinfo); return NULL; } /* fill in pixel values for each band at this intensity */ while ((redbottom < 256) && (redbottom < redtop)) redvalue[redbottom++] = xcolor.pixel & visual->red_mask; while ((greenbottom < 256) && (greenbottom < greentop)) greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask; while ((bluebottom < 256) && (bluebottom < bluetop)) bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask; } break; } case PseudoColor: ximageinfo->cmap = global_cmap; for (a = 0; a < MAX_COLORS; a++) { XColor xcolor2; unsigned short mask; int color_found; int i; if (!image->rgb.color_used[a]) continue; xcolor.red = *(image->rgb.red + a); xcolor.green = *(image->rgb.green + a); xcolor.blue = *(image->rgb.blue + a); /* look if this color already exists in our colormap */ if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) { if (!private_cmap) { if (options.verbose) Error(ERR_INFO, "switching to private colormap"); /* we just filled up the default colormap -- get a private one which contains all already allocated colors */ global_cmap = XCopyColormapAndFree(display, global_cmap); ximageinfo->cmap = global_cmap; private_cmap = TRUE; /* allocate the rest of the color cells read/write */ global_cmap_index = (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS); for (i = 0; i < NOFLASH_COLORS; i++) if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0, global_cmap_index + i, 1)) break; num_cmap_entries = free_cmap_entries = i; /* printf("We've got %d free colormap entries.\n", free_cmap_entries); */ /* to minimize colormap flashing, copy default colors and try to keep them as near as possible to the old values */ for (i = 0; i < num_cmap_entries; i++) { xcolor2.pixel = *(global_cmap_index + i); XQueryColor(display, DefaultColormap(display, screen), &xcolor2); XStoreColor(display, global_cmap, &xcolor2); xcolor_private[xcolor2.pixel] = xcolor2; colorcell_used[xcolor2.pixel] = FALSE; } /* now we have the default colormap private: all colors we successfully allocated so far are read-only, which is okay, because we don't want to change them anymore -- if we need an existing color again, we get it by XAllocColor; all other colors are read/write and we can set them by XStoreColor, but we will try to overwrite those color cells with our new color which are as close as possible to our new color */ } /* look for an existing default color close the one we want */ mask = 0xf000; color_found = FALSE; while (!color_found) { for (i = num_cmap_entries - 1; i >= 0; i--) { xcolor2.pixel = *(global_cmap_index + i); xcolor2 = xcolor_private[xcolor2.pixel]; if (colorcell_used[xcolor2.pixel]) continue; if ((xcolor.red & mask) == (xcolor2.red & mask) && (xcolor.green & mask) == (xcolor2.green & mask) && (xcolor.blue & mask) == (xcolor2.blue & mask)) { /* printf("replacing color cell %ld with a close color\n", xcolor2.pixel); */ color_found = TRUE; break; } } if (mask == 0x0000) break; mask = (mask << 1) & 0xffff; } if (!color_found) /* no more free color cells */ { SetError(error, "cannot allocate enough color cells"); return NULL; } xcolor.pixel = xcolor2.pixel; xcolor_private[xcolor.pixel] = xcolor; colorcell_used[xcolor.pixel] = TRUE; XStoreColor(display, ximageinfo->cmap, &xcolor); free_cmap_entries--; } *(ximageinfo->index + a) = xcolor.pixel; } /* printf("still %d free colormap entries\n", free_cmap_entries); */ ximageinfo->no = a; /* number of pixels allocated for this image */ break; default: Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed"); SetError(error, "display class not supported"); return NULL; } #if DEBUG_TIMING debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: "); #endif /* create XImage from internal image structure and convert it to Pixmap */ display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth); display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8; ximage = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, image->width, image->height, 8, image->width * display_bytes_per_pixel); ximage->data = checked_malloc(image->width * image->height * display_bytes_per_pixel); ximage->byte_order = MSBFirst; src_ptr = image->data; dst_ptr = (byte *)ximage->data; switch (visual->class) { case DirectColor: case TrueColor: { Pixel pixval; switch (image->type) { case IMAGETYPE_RGB: { for (y = 0; y < image->height; y++) /* general case */ { for (x = 0; x < image->width; x++) { pixval = *src_ptr++; pixval = redvalue[image->rgb.red[pixval] >> 8] | greenvalue[image->rgb.green[pixval] >> 8] | bluevalue[image->rgb.blue[pixval] >> 8]; value_to_memory(pixval, dst_ptr, display_bytes_per_pixel); dst_ptr += display_bytes_per_pixel; } } break; } case IMAGETYPE_TRUECOLOR: { for (y = 0; y < image->height; y++) /* general case */ { for (x = 0; x < image->width; x++) { pixval = memory_to_value(src_ptr, image->bytes_per_pixel); pixval = redvalue[TRUECOLOR_RED(pixval)] | greenvalue[TRUECOLOR_GREEN(pixval)] | bluevalue[TRUECOLOR_BLUE(pixval)]; value_to_memory(pixval, dst_ptr, display_bytes_per_pixel); src_ptr += image->bytes_per_pixel; dst_ptr += display_bytes_per_pixel; } } break; } default: Error(ERR_INFO, "RGB or TrueColor image needed"); SetError(error, "image type not supported"); return NULL; } break; } case PseudoColor: { if (display_bytes_per_pixel == 1) /* special case */ { for (y = 0; y < image->height; y++) for (x = 0; x < image->width; x++) *dst_ptr++ = ximageinfo->index[c + *src_ptr++]; } else /* general case */ { for (y = 0; y < image->height; y++) { for (x = 0; x < image->width; x++) { value_to_memory(ximageinfo->index[c + *src_ptr++], dst_ptr, display_bytes_per_pixel); dst_ptr += display_bytes_per_pixel; } } } break; } default: Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed"); SetError(error, "display class not supported"); return NULL; } if (redvalue) { free((byte *)redvalue); free((byte *)greenvalue); free((byte *)bluevalue); } #if DEBUG_TIMING debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:"); #endif ximageinfo->pixmap = XCreatePixmap(display, window, ximage->width, ximage->height, ximageinfo->depth); XPutImage(ximageinfo->display, ximageinfo->pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); X11DestroyImage(ximage); return ximageinfo; } /* ----------------------------------------------------------------------------- ZoomPixmap Important note: The scaling code currently only supports scaling of the image up or down by a power of 2 -- other scaling factors currently not supported! Also not supported is scaling of pixmap masks (with depth 1); to scale them, better use Pixmap_to_Mask() for now. ----------------------------------------------------------------------------- */ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap, int src_width, int src_height, int dst_width, int dst_height) { XImage *src_ximage, *dst_ximage; byte *src_ptr, *dst_ptr; int bits_per_pixel; int bytes_per_pixel; int x, y, xx, yy, i; int row_skip, col_skip; int zoom_factor; boolean scale_down = (src_width > dst_width); if (scale_down) { #if 1 zoom_factor = MIN(src_width / dst_width, src_height / dst_height); #else zoom_factor = src_width / dst_width; #endif /* adjust source image size to integer multiple of destination size */ src_width = dst_width * zoom_factor; src_height = dst_height * zoom_factor; } else { #if 1 zoom_factor = MIN(dst_width / src_width, dst_height / src_height); #else zoom_factor = dst_width / src_width; #endif /* no adjustment needed when scaling up (some pixels may be left blank) */ } /* copy source pixmap to temporary image */ if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height, AllPlanes, ZPixmap)) == NULL) Error(ERR_EXIT, "ZoomPixmap(): XGetImage() failed"); bits_per_pixel = src_ximage->bits_per_pixel; bytes_per_pixel = (bits_per_pixel + 7) / 8; if ((dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap, 0, NULL, dst_width, dst_height, 8, dst_width * bytes_per_pixel)) == NULL) Error(ERR_EXIT, "ZoomPixmap(): XCreateImage() failed"); dst_ximage->data = checked_malloc(dst_width * dst_height * bytes_per_pixel); dst_ximage->byte_order = src_ximage->byte_order; src_ptr = (byte *)src_ximage->data; dst_ptr = (byte *)dst_ximage->data; if (scale_down) { col_skip = (zoom_factor - 1) * bytes_per_pixel; row_skip = col_skip * src_width; /* scale image down by scaling factor 'zoom_factor' */ for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip) for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip) for (i = 0; i < bytes_per_pixel; i++) *dst_ptr++ = *src_ptr++; } else { row_skip = src_width * bytes_per_pixel; /* scale image up by scaling factor 'zoom_factor' */ for (y = 0; y < src_height; y++) { for (yy = 0; yy < zoom_factor; yy++) { if (yy > 0) src_ptr -= row_skip; for (x = 0; x < src_width; x++) { for (xx = 0; xx < zoom_factor; xx++) for (i = 0; i < bytes_per_pixel; i++) *dst_ptr++ = *(src_ptr + i); src_ptr += bytes_per_pixel; } } } } /* copy scaled image to destination pixmap */ XPutImage(display, dst_pixmap, gc, dst_ximage, 0, 0, 0, 0, dst_width, dst_height); /* free temporary images */ X11DestroyImage(src_ximage); X11DestroyImage(dst_ximage); } void freeXImage(Image *image, XImageInfo *ximageinfo) { if (ximageinfo->index != NULL && ximageinfo->no > 0) XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index, ximageinfo->no, 0); /* this ^^^^^^^^^^^^^^ is wrong, because the used color cells * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no' * used color cells, but they are not at array position 0 - 'ximageinfo->no' */ free(ximageinfo); } int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, Pixmap *pixmap, Pixmap *pixmap_mask) { Image *image; XImageInfo *ximageinfo; int screen; Visual *visual; int depth; #if DEBUG_TIMING debug_print_timestamp(2, NULL); /* initialize timestamp function */ #endif /* read the graphic file in PCX format to image structure */ if ((image = Read_PCX_to_Image(filename)) == NULL) return errno_pcx; #if DEBUG_TIMING printf("%s:\n", filename); debug_print_timestamp(2, " READING PCX FILE TO IMAGE: "); #endif screen = DefaultScreen(display); visual = DefaultVisual(display, screen); depth = DefaultDepth(display, screen); /* convert image structure to X11 Pixmap */ if (!(ximageinfo = Image_to_Pixmap(display, screen, visual, window, gc, depth, image))) { freeImage(image); return PCX_OtherError; } /* if a private colormap has been created, install it */ if (ximageinfo->cmap != DefaultColormap(display, screen)) XSetWindowColormap(display, window, ximageinfo->cmap); #if DEBUG_TIMING debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:"); #endif /* create clip mask for the image */ ximageinfo->pixmap_mask = Image_to_Mask(image, display, window); #if DEBUG_TIMING debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: "); #endif *pixmap = ximageinfo->pixmap; *pixmap_mask = ximageinfo->pixmap_mask; /* free generic image and ximageinfo after native Pixmap has been created */ free(ximageinfo); freeImage(image); return PCX_Success; } #endif /* PLATFORM_UNIX */ #endif /* TARGET_X11 */ /* ========================================================================= */ /* PLATFORM INDEPENDENT IMAGE FUNCTIONS */ /* ========================================================================= */ struct ImageInfo { char *source_filename; int num_references; Bitmap *bitmap; int original_width; /* original image file width */ int original_height; /* original image file height */ boolean contains_small_images; /* set after adding small images */ boolean scaled_up; /* set after scaling up */ }; typedef struct ImageInfo ImageInfo; static struct ArtworkListInfo *image_info = NULL; static void *Load_PCX(char *filename) { ImageInfo *img_info; #if 0 printf("::: loading PCX file '%s'\n", filename); #endif img_info = checked_calloc(sizeof(ImageInfo)); if ((img_info->bitmap = LoadImage(filename)) == NULL) { Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s", filename, GetError()); free(img_info); return NULL; } img_info->source_filename = getStringCopy(filename); img_info->original_width = img_info->bitmap->width; img_info->original_height = img_info->bitmap->height; img_info->contains_small_images = FALSE; img_info->scaled_up = FALSE; return img_info; } static void FreeImage(void *ptr) { ImageInfo *image = (ImageInfo *)ptr; if (image == NULL) return; if (image->bitmap) FreeBitmap(image->bitmap); if (image->source_filename) free(image->source_filename); free(image); } int getImageListSize() { return (image_info->num_file_list_entries + image_info->num_dynamic_file_list_entries); } struct FileInfo *getImageListEntryFromImageID(int pos) { int num_list_entries = image_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); return (pos < num_list_entries ? &image_info->file_list[list_pos] : &image_info->dynamic_file_list[list_pos]); } static ImageInfo *getImageInfoEntryFromImageID(int pos) { int num_list_entries = image_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); ImageInfo **img_info = (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list : image_info->dynamic_artwork_list); return img_info[list_pos]; } Bitmap *getBitmapFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->bitmap : NULL); } int getOriginalImageWidthFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->original_width : 0); } int getOriginalImageHeightFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->original_height : 0); } char *getTokenFromImageID(int graphic) { struct FileInfo *file_list = getImageListEntryFromImageID(graphic); return (file_list != NULL ? file_list->token : NULL); } int getImageIDFromToken(char *token) { struct FileInfo *file_list = image_info->file_list; int num_list_entries = image_info->num_file_list_entries; int i; for (i = 0; i < num_list_entries; i++) if (strEqual(file_list[i].token, token)) return i; return -1; } char *getImageConfigFilename() { return getCustomArtworkConfigFilename(image_info->type); } int getImageListPropertyMappingSize() { return image_info->num_property_mapping_entries; } struct PropertyMapping *getImageListPropertyMapping() { return image_info->property_mapping; } void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; image_info = checked_calloc(sizeof(struct ArtworkListInfo)); image_info->type = ARTWORK_TYPE_GRAPHICS; /* ---------- initialize file list and suffix lists ---------- */ image_info->num_file_list_entries = num_file_list_entries; image_info->num_dynamic_file_list_entries = 0; image_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); image_info->dynamic_file_list = NULL; image_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) image_info->num_suffix_list_entries++; image_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ image_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) image_info->num_base_prefixes++; image_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) image_info->num_ext1_suffixes++; image_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) image_info->num_ext2_suffixes++; image_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) image_info->num_ext3_suffixes++; image_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) image_info->num_ignore_tokens++; image_info->base_prefixes = base_prefixes; image_info->ext1_suffixes = ext1_suffixes; image_info->ext2_suffixes = ext2_suffixes; image_info->ext3_suffixes = ext3_suffixes; image_info->ignore_tokens = ignore_tokens; image_info->num_property_mapping_entries = 0; image_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *); image_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(ImageInfo *)); image_info->dynamic_artwork_list = NULL; image_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ image_info->load_artwork = Load_PCX; image_info->free_artwork = FreeImage; } void ReloadCustomImages() { #if 0 printf("::: reloading images '%s' ...\n", artwork.gfx_current_identifier); #endif LoadArtworkConfig(image_info); ReloadCustomArtworkList(image_info); } void CreateImageWithSmallImages(int pos, int zoom_factor) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL || img_info->contains_small_images) return; CreateBitmapWithSmallBitmaps(img_info->bitmap, zoom_factor); img_info->contains_small_images = TRUE; img_info->scaled_up = TRUE; } void ScaleImage(int pos, int zoom_factor) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL || img_info->scaled_up) return; if (zoom_factor != 1) ScaleBitmap(img_info->bitmap, zoom_factor); img_info->scaled_up = TRUE; } void FreeAllImages() { FreeCustomArtworkLists(image_info); } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/sdl.h0000644000175000017500000002450411004467704017760 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * sdl.h * ***********************************************************/ #ifndef SDL_H #define SDL_H #include #include #include #include #include #if defined(PLATFORM_WIN32) #include #endif /* definitions needed for "system.c" */ #define SURFACE_FLAGS (SDL_SWSURFACE) /* system dependent definitions */ #define TARGET_STRING "SDL" #define FULLSCREEN_STATUS FULLSCREEN_AVAILABLE #define CURSOR_MAX_WIDTH 32 #define CURSOR_MAX_HEIGHT 32 /* SDL type definitions */ typedef struct SDLSurfaceInfo Bitmap; typedef struct SDLSurfaceInfo DrawBuffer; typedef struct SDLSurfaceInfo DrawWindow; typedef Uint32 Pixel; typedef SDL_Cursor *Cursor; typedef SDLKey Key; typedef unsigned int KeyMod; typedef SDL_Event Event; typedef SDL_MouseButtonEvent ButtonEvent; typedef SDL_MouseMotionEvent MotionEvent; typedef SDL_KeyboardEvent KeyEvent; typedef SDL_Event ExposeEvent; typedef SDL_Event FocusChangeEvent; typedef SDL_Event ClientMessageEvent; typedef int GC; typedef int Pixmap; typedef int Display; typedef int Visual; typedef int Colormap; /* structure definitions */ struct SDLSurfaceInfo { char *source_filename; int width, height; SDL_Surface *surface; SDL_Surface *surface_masked; GC gc; GC stored_clip_gc; }; struct MouseCursorInfo { int width, height; int hot_x, hot_y; byte data[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; byte mask[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; }; /* SDL symbol definitions */ #define None 0L #define BLACK_PIXEL 0x000000 #define WHITE_PIXEL 0xffffff #define EVENT_BUTTONPRESS SDL_MOUSEBUTTONDOWN #define EVENT_BUTTONRELEASE SDL_MOUSEBUTTONUP #define EVENT_MOTIONNOTIFY SDL_MOUSEMOTION #define EVENT_KEYPRESS SDL_KEYDOWN #define EVENT_KEYRELEASE SDL_KEYUP #define EVENT_EXPOSE SDL_USEREVENT + 0 #define EVENT_FOCUSIN SDL_USEREVENT + 1 #define EVENT_FOCUSOUT SDL_USEREVENT + 2 #define EVENT_CLIENTMESSAGE SDL_QUIT #define EVENT_MAPNOTIFY SDL_USEREVENT + 4 #define EVENT_UNMAPNOTIFY SDL_USEREVENT + 5 #define KSYM_UNDEFINED SDLK_UNKNOWN #define KSYM_Return SDLK_RETURN #define KSYM_Escape SDLK_ESCAPE #define KSYM_Left SDLK_LEFT #define KSYM_Right SDLK_RIGHT #define KSYM_Up SDLK_UP #define KSYM_Down SDLK_DOWN #ifdef SDLK_KP_LEFT #define KSYM_KP_Left SDLK_KP_LEFT #define KSYM_KP_Right SDLK_KP_RIGHT #define KSYM_KP_Up SDLK_KP_UP #define KSYM_KP_Down SDLK_KP_DOWN #endif #define KSYM_KP_Enter SDLK_KP_ENTER #define KSYM_KP_Add SDLK_KP_PLUS #define KSYM_KP_Subtract SDLK_KP_MINUS #define KSYM_KP_Multiply SDLK_KP_MULTIPLY #define KSYM_KP_Divide SDLK_KP_DIVIDE #define KSYM_KP_Separator SDLK_KP_PERIOD #define KSYM_Shift_L SDLK_LSHIFT #define KSYM_Shift_R SDLK_RSHIFT #define KSYM_Control_L SDLK_LCTRL #define KSYM_Control_R SDLK_RCTRL #define KSYM_Meta_L SDLK_LMETA #define KSYM_Meta_R SDLK_RMETA #define KSYM_Alt_L SDLK_LALT #define KSYM_Alt_R SDLK_RALT #define KSYM_Super_L SDLK_LSUPER #define KSYM_Super_R SDLK_RSUPER #define KSYM_Mode_switch SDLK_MODE #define KSYM_Multi_key SDLK_RCTRL #define KSYM_BackSpace SDLK_BACKSPACE #define KSYM_Delete SDLK_DELETE #define KSYM_Insert SDLK_INSERT #define KSYM_Tab SDLK_TAB #define KSYM_Home SDLK_HOME #define KSYM_End SDLK_END #define KSYM_Page_Up SDLK_PAGEUP #define KSYM_Page_Down SDLK_PAGEDOWN #define KSYM_Menu SDLK_MENU #define KSYM_space SDLK_SPACE #define KSYM_exclam SDLK_EXCLAIM #define KSYM_quotedbl SDLK_QUOTEDBL #define KSYM_numbersign SDLK_HASH #define KSYM_dollar SDLK_DOLLAR #define KSYM_percent KSYM_UNDEFINED /* undefined */ #define KSYM_ampersand SDLK_AMPERSAND #define KSYM_apostrophe SDLK_QUOTE #define KSYM_parenleft SDLK_LEFTPAREN #define KSYM_parenright SDLK_RIGHTPAREN #define KSYM_asterisk SDLK_ASTERISK #define KSYM_plus SDLK_PLUS #define KSYM_comma SDLK_COMMA #define KSYM_minus SDLK_MINUS #define KSYM_period SDLK_PERIOD #define KSYM_slash SDLK_SLASH #define KSYM_colon SDLK_COLON #define KSYM_semicolon SDLK_SEMICOLON #define KSYM_less SDLK_LESS #define KSYM_equal SDLK_EQUALS #define KSYM_greater SDLK_GREATER #define KSYM_question SDLK_QUESTION #define KSYM_at SDLK_AT #define KSYM_bracketleft SDLK_LEFTBRACKET #define KSYM_backslash SDLK_BACKSLASH #define KSYM_bracketright SDLK_RIGHTBRACKET #define KSYM_asciicircum SDLK_CARET #define KSYM_underscore SDLK_UNDERSCORE #define KSYM_grave SDLK_BACKQUOTE #define KSYM_quoteleft KSYM_UNDEFINED /* undefined */ #define KSYM_braceleft KSYM_UNDEFINED /* undefined */ #define KSYM_bar KSYM_UNDEFINED /* undefined */ #define KSYM_braceright KSYM_UNDEFINED /* undefined */ #define KSYM_asciitilde KSYM_UNDEFINED /* undefined */ #define KSYM_degree SDLK_WORLD_16 #define KSYM_Adiaeresis SDLK_WORLD_36 #define KSYM_Odiaeresis SDLK_WORLD_54 #define KSYM_Udiaeresis SDLK_WORLD_60 #define KSYM_adiaeresis SDLK_WORLD_68 #define KSYM_odiaeresis SDLK_WORLD_86 #define KSYM_udiaeresis SDLK_WORLD_92 #define KSYM_ssharp SDLK_WORLD_63 #ifndef SDLK_A #define SDLK_A 65 #define SDLK_B 66 #define SDLK_C 67 #define SDLK_D 68 #define SDLK_E 69 #define SDLK_F 70 #define SDLK_G 71 #define SDLK_H 72 #define SDLK_I 73 #define SDLK_J 74 #define SDLK_K 75 #define SDLK_L 76 #define SDLK_M 77 #define SDLK_N 78 #define SDLK_O 79 #define SDLK_P 80 #define SDLK_Q 81 #define SDLK_R 82 #define SDLK_S 83 #define SDLK_T 84 #define SDLK_U 85 #define SDLK_V 86 #define SDLK_W 87 #define SDLK_X 88 #define SDLK_Y 89 #define SDLK_Z 90 #endif #define KSYM_A SDLK_A #define KSYM_B SDLK_B #define KSYM_C SDLK_C #define KSYM_D SDLK_D #define KSYM_E SDLK_E #define KSYM_F SDLK_F #define KSYM_G SDLK_G #define KSYM_H SDLK_H #define KSYM_I SDLK_I #define KSYM_J SDLK_J #define KSYM_K SDLK_K #define KSYM_L SDLK_L #define KSYM_M SDLK_M #define KSYM_N SDLK_N #define KSYM_O SDLK_O #define KSYM_P SDLK_P #define KSYM_Q SDLK_Q #define KSYM_R SDLK_R #define KSYM_S SDLK_S #define KSYM_T SDLK_T #define KSYM_U SDLK_U #define KSYM_V SDLK_V #define KSYM_W SDLK_W #define KSYM_X SDLK_X #define KSYM_Y SDLK_Y #define KSYM_Z SDLK_Z #define KSYM_a SDLK_a #define KSYM_b SDLK_b #define KSYM_c SDLK_c #define KSYM_d SDLK_d #define KSYM_e SDLK_e #define KSYM_f SDLK_f #define KSYM_g SDLK_g #define KSYM_h SDLK_h #define KSYM_i SDLK_i #define KSYM_j SDLK_j #define KSYM_k SDLK_k #define KSYM_l SDLK_l #define KSYM_m SDLK_m #define KSYM_n SDLK_n #define KSYM_o SDLK_o #define KSYM_p SDLK_p #define KSYM_q SDLK_q #define KSYM_r SDLK_r #define KSYM_s SDLK_s #define KSYM_t SDLK_t #define KSYM_u SDLK_u #define KSYM_v SDLK_v #define KSYM_w SDLK_w #define KSYM_x SDLK_x #define KSYM_y SDLK_y #define KSYM_z SDLK_z #define KSYM_0 SDLK_0 #define KSYM_1 SDLK_1 #define KSYM_2 SDLK_2 #define KSYM_3 SDLK_3 #define KSYM_4 SDLK_4 #define KSYM_5 SDLK_5 #define KSYM_6 SDLK_6 #define KSYM_7 SDLK_7 #define KSYM_8 SDLK_8 #define KSYM_9 SDLK_9 #define KSYM_KP_0 SDLK_KP0 #define KSYM_KP_1 SDLK_KP1 #define KSYM_KP_2 SDLK_KP2 #define KSYM_KP_3 SDLK_KP3 #define KSYM_KP_4 SDLK_KP4 #define KSYM_KP_5 SDLK_KP5 #define KSYM_KP_6 SDLK_KP6 #define KSYM_KP_7 SDLK_KP7 #define KSYM_KP_8 SDLK_KP8 #define KSYM_KP_9 SDLK_KP9 #define KSYM_F1 SDLK_F1 #define KSYM_F2 SDLK_F2 #define KSYM_F3 SDLK_F3 #define KSYM_F4 SDLK_F4 #define KSYM_F5 SDLK_F5 #define KSYM_F6 SDLK_F6 #define KSYM_F7 SDLK_F7 #define KSYM_F8 SDLK_F8 #define KSYM_F9 SDLK_F9 #define KSYM_F10 SDLK_F10 #define KSYM_F11 SDLK_F11 #define KSYM_F12 SDLK_F12 #define KSYM_F13 SDLK_F13 #define KSYM_F14 SDLK_F14 #define KSYM_F15 SDLK_F15 #define KSYM_F16 KSYM_UNDEFINED #define KSYM_F17 KSYM_UNDEFINED #define KSYM_F18 KSYM_UNDEFINED #define KSYM_F19 KSYM_UNDEFINED #define KSYM_F20 KSYM_UNDEFINED #define KSYM_F21 KSYM_UNDEFINED #define KSYM_F22 KSYM_UNDEFINED #define KSYM_F23 KSYM_UNDEFINED #define KSYM_F24 KSYM_UNDEFINED #define KSYM_FKEY_FIRST KSYM_F1 #define KSYM_FKEY_LAST KSYM_F15 #define KSYM_NUM_FKEYS (KSYM_FKEY_LAST - KSYM_FKEY_FIRST + 1) #define KMOD_None None #define KMOD_Shift_L KMOD_LSHIFT #define KMOD_Shift_R KMOD_RSHIFT #define KMOD_Control_L KMOD_LCTRL #define KMOD_Control_R KMOD_RCTRL #define KMOD_Meta_L KMOD_LMETA #define KMOD_Meta_R KMOD_RMETA #define KMOD_Alt_L KMOD_LALT #define KMOD_Alt_R KMOD_RALT #define KMOD_Shift (KMOD_Shift_L | KMOD_Shift_R) #define KMOD_Control (KMOD_Control_L | KMOD_Control_R) #define KMOD_Meta (KMOD_Meta_L | KMOD_Meta_R) #define KMOD_Alt (KMOD_Alt_L | KMOD_Alt_R) /* SDL function definitions */ void SDLInitVideoDisplay(void); void SDLInitVideoBuffer(DrawBuffer **, DrawWindow **, boolean); boolean SDLSetVideoMode(DrawBuffer **, boolean); void SDLCreateBitmapContent(Bitmap *, int, int, int); void SDLFreeBitmapPointers(Bitmap *); void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int); void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32); void SDLFadeRectangle(Bitmap *, int, int, int, int, int, int, int, void (*draw_border_function)(void)); void SDLDrawSimpleLine(Bitmap *, int, int, int, int, Uint32); void SDLDrawLine(Bitmap *, int, int, int, int, Uint32); Pixel SDLGetPixel(Bitmap *, int, int); void SDLPutPixel(Bitmap *, int, int, Pixel); void SDLInvertArea(Bitmap *, int, int, int, int, Uint32); void SDLCopyInverseMasked(Bitmap *, Bitmap *, int, int, int, int, int, int); void SDLZoomBitmap(Bitmap *, Bitmap *); Bitmap *SDLLoadImage(char *); void SDLSetMouseCursor(struct MouseCursorInfo *); void SDLOpenAudio(void); void SDLCloseAudio(void); void SDLNextEvent(Event *); void SDLHandleWindowManagerEvent(Event *); void HandleJoystickEvent(Event *); void SDLInitJoysticks(void); boolean SDLReadJoystick(int, int *, int *, boolean *, boolean *); #endif /* SDL_H */ rocksndiamonds-3.3.0.1+dfsg1/src/libgame/joystick.c0000644000175000017500000002130110471575013021020 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * joystick.c * ***********************************************************/ #if defined(PLATFORM_FREEBSD) #include #endif #include "joystick.h" #include "misc.h" /* ========================================================================= */ /* platform dependent joystick functions */ /* ========================================================================= */ #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL) void UnixInitJoysticks() { static boolean unix_joystick_subsystem_initialized = FALSE; boolean print_warning = !unix_joystick_subsystem_initialized; int i; for (i = 0; i < MAX_PLAYERS; i++) { char *device_name = setup.input[i].joy.device_name; /* this allows subsequent calls to 'InitJoysticks' for re-initialization */ if (joystick.fd[i] != -1) { close(joystick.fd[i]); joystick.fd[i] = -1; } if (!setup.input[i].use_joystick) continue; if (access(device_name, R_OK) != 0) { if (print_warning) Error(ERR_WARN, "cannot access joystick device '%s'", device_name); continue; } if ((joystick.fd[i] = open(device_name, O_RDONLY)) < 0) { if (print_warning) Error(ERR_WARN, "cannot open joystick device '%s'", device_name); continue; } joystick.status = JOYSTICK_ACTIVATED; } unix_joystick_subsystem_initialized = TRUE; } boolean UnixReadJoystick(int fd, int *x, int *y, boolean *b1, boolean *b2) { #if defined(PLATFORM_FREEBSD) struct joystick joy_ctrl; #else struct joystick_control { int buttons; int x; int y; } joy_ctrl; #endif if (read(fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) return FALSE; if (x != NULL) *x = joy_ctrl.x; if (y != NULL) *y = joy_ctrl.y; #if defined(PLATFORM_FREEBSD) if (b1 != NULL) *b1 = joy_ctrl.b1; if (b2 != NULL) *b2 = joy_ctrl.b2; #else if (b1 != NULL) *b1 = joy_ctrl.buttons & 1; if (b2 != NULL) *b2 = joy_ctrl.buttons & 2; #endif return TRUE; } #endif /* PLATFORM_UNIX && !TARGET_SDL */ /* ========================================================================= */ /* platform independent joystick functions */ /* ========================================================================= */ #define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1 void translate_joyname(int *joysymbol, char **name, int mode) { static struct { int joysymbol; char *name; } translate_joy[] = { { JOY_LEFT, "joystick_left" }, { JOY_RIGHT, "joystick_right" }, { JOY_UP, "joystick_up" }, { JOY_DOWN, "joystick_down" }, { JOY_BUTTON_1, "joystick_button_1" }, { JOY_BUTTON_2, "joystick_button_2" }, }; int i; if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME) { *name = "[undefined]"; for (i = 0; i < 6; i++) { if (*joysymbol == translate_joy[i].joysymbol) { *name = translate_joy[i].name; break; } } } else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL) { *joysymbol = 0; for (i = 0; i < 6; i++) { if (strEqual(*name, translate_joy[i].name)) { *joysymbol = translate_joy[i].joysymbol; break; } } } } char *getJoyNameFromJoySymbol(int joysymbol) { char *name; translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME); return name; } int getJoySymbolFromJoyName(char *name) { int joysymbol; translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL); return joysymbol; } int getJoystickNrFromDeviceName(char *device_name) { char c; int joystick_nr = 0; if (device_name == NULL || device_name[0] == '\0') return 0; c = device_name[strlen(device_name) - 1]; if (c >= '0' && c <= '9') joystick_nr = (int)(c - '0'); if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS) joystick_nr = 0; return joystick_nr; } char *getDeviceNameFromJoystickNr(int joystick_nr) { static char *joystick_device_name[MAX_PLAYERS] = { DEV_JOYSTICK_0, DEV_JOYSTICK_1, DEV_JOYSTICK_2, DEV_JOYSTICK_3 }; return (joystick_nr >= 0 && joystick_nr <= 3 ? joystick_device_name[joystick_nr] : ""); } static int JoystickPositionPercent(int center, int border, int actual) { long range, position; int percent; if (border < center && actual > center) return 0; if (border > center && actual < center) return 0; range = ABS(border - center); position = ABS(actual - center); percent = (int)(position * 100 / range); if (percent > 100) percent = 100; return percent; } void CheckJoystickData() { int i; int distance = 100; for (i = 0; i < MAX_PLAYERS; i++) { if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle) setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance; if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle) setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance; if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle) setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance; if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle) setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance; } } int Joystick(int player_nr) { int joystick_fd = joystick.fd[player_nr]; int js_x, js_y; boolean js_b1, js_b2; int left, right, up, down; int result = JOY_NO_ACTION; if (joystick.status != JOYSTICK_ACTIVATED) return JOY_NO_ACTION; if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) return JOY_NO_ACTION; if (!ReadJoystick(joystick_fd, &js_x, &js_y, &js_b1, &js_b2)) { Error(ERR_WARN, "cannot read joystick device '%s'", setup.input[player_nr].joy.device_name); joystick.status = JOYSTICK_NOT_AVAILABLE; return JOY_NO_ACTION; } left = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle, setup.input[player_nr].joy.xleft, js_x); right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle, setup.input[player_nr].joy.xright, js_x); up = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle, setup.input[player_nr].joy.yupper, js_y); down = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle, setup.input[player_nr].joy.ylower, js_y); if (left > JOYSTICK_PERCENT) result |= JOY_LEFT; else if (right > JOYSTICK_PERCENT) result |= JOY_RIGHT; if (up > JOYSTICK_PERCENT) result |= JOY_UP; else if (down > JOYSTICK_PERCENT) result |= JOY_DOWN; if (js_b1) result |= JOY_BUTTON_1; if (js_b2) result |= JOY_BUTTON_2; return result; } int JoystickButton(int player_nr) { static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 }; int joy_button = (Joystick(player_nr) & JOY_BUTTON); int result; if (joy_button) { if (last_joy_button[player_nr]) result = JOY_BUTTON_PRESSED; else result = JOY_BUTTON_NEW_PRESSED; } else { if (last_joy_button[player_nr]) result = JOY_BUTTON_NEW_RELEASED; else result = JOY_BUTTON_NOT_PRESSED; } last_joy_button[player_nr] = joy_button; return result; } int AnyJoystick() { int i; int result = 0; for (i = 0; i < MAX_PLAYERS; i++) result |= Joystick(i); return result; } int AnyJoystickButton() { int i; int result = JOY_BUTTON_NOT_PRESSED; for (i = 0; i < MAX_PLAYERS; i++) { result = JoystickButton(i); if (result != JOY_BUTTON_NOT_PRESSED) break; } return result; } void DeactivateJoystick() { /* Temporarily deactivate joystick. This is needed for calibration screens, where the player has to select a joystick device that should be calibrated. If there is a totally uncalibrated joystick active, it may be impossible (due to messed up input from joystick) to select the joystick device to calibrate even when trying to use the mouse or keyboard to select the device. */ if (joystick.status & JOYSTICK_AVAILABLE) joystick.status &= ~JOYSTICK_ACTIVE; } void ActivateJoystick() { /* reactivate temporarily deactivated joystick */ if (joystick.status & JOYSTICK_AVAILABLE) joystick.status |= JOYSTICK_ACTIVE; } rocksndiamonds-3.3.0.1+dfsg1/src/libgame/misc.h0000644000175000017500000001605411345451670020135 0ustar dimkadimka/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * misc.h * ***********************************************************/ #ifndef MISC_H #define MISC_H #include #include #include "system.h" /* values for InitCounter() and Counter() */ #define INIT_COUNTER 0 #define READ_COUNTER 1 /* values for InitRND() */ #define NEW_RANDOMIZE 0 #define RANDOM_ENGINE 0 #define RANDOM_SIMPLE 1 #define InitEngineRandom(seed) init_random_number(RANDOM_ENGINE, seed) #define InitSimpleRandom(seed) init_random_number(RANDOM_SIMPLE, seed) #define GetEngineRandom(max) get_random_number(RANDOM_ENGINE, max) #define GetSimpleRandom(max) get_random_number(RANDOM_SIMPLE, max) /* values for Error() */ #define ERR_INFO 0 #define ERR_INFO_LINE (1 << 0) #define ERR_WARN (1 << 1) #define ERR_EXIT (1 << 2) #define ERR_HELP (1 << 3) #define ERR_SOUND_SERVER (1 << 4) #define ERR_NETWORK_SERVER (1 << 5) #define ERR_NETWORK_CLIENT (1 << 6) #define ERR_FROM_SERVER (ERR_SOUND_SERVER | ERR_NETWORK_SERVER) #define ERR_EXIT_HELP (ERR_EXIT | ERR_HELP) #define ERR_EXIT_SOUND_SERVER (ERR_EXIT | ERR_SOUND_SERVER) #define ERR_EXIT_NETWORK_SERVER (ERR_EXIT | ERR_NETWORK_SERVER) #define ERR_EXIT_NETWORK_CLIENT (ERR_EXIT | ERR_NETWORK_CLIENT) /* values for getFile...() and putFile...() */ #define BYTE_ORDER_BIG_ENDIAN 0 #define BYTE_ORDER_LITTLE_ENDIAN 1 /* values for cursor bitmap creation */ #define BIT_ORDER_MSB 0 #define BIT_ORDER_LSB 1 /* values for createDirectory() */ #define PERMS_PRIVATE 0 #define PERMS_PUBLIC 1 /* values for general file handling stuff */ #define MAX_FILENAME_LEN 256 #define MAX_LINE_LEN 1024 /* values for general username handling stuff */ #define MAX_USERNAME_LEN 1024 void fprintf_line(FILE *, char *, int); void printf_line(char *, int); void printf_line_with_prefix(char *, char *, int); char *int2str(int, int); char *i_to_a(unsigned int); int log_2(unsigned int); boolean getTokenValueFromString(char *, char **, char **); void InitCounter(void); unsigned long Counter(void); void Delay(unsigned long); boolean FrameReached(unsigned long *, unsigned long); boolean DelayReached(unsigned long *, unsigned long); void WaitUntilDelayReached(unsigned long *, unsigned long); unsigned int init_random_number(int, long); unsigned int get_random_number(int, int); char *getLoginName(void); char *getRealName(void); time_t getFileTimestampEpochSeconds(char *); char *getBasePath(char *); char *getBaseName(char *); char *getBaseNamePtr(char *); char *getStringCat2WithSeparator(char *, char *, char *); char *getStringCat3WithSeparator(char *, char *, char *, char *); char *getStringCat2(char *, char *); char *getStringCat3(char *, char *, char *); char *getPath2(char *, char *); char *getPath3(char *, char *, char*); char *getStringCopy(char *); char *getStringCopyN(char *, int); char *getStringToLower(char *); void setString(char **, char *); boolean strEqual(char *, char *); boolean strEqualN(char *, char *, int); boolean strPrefix(char *, char *); boolean strSuffix(char *, char *); boolean strPrefixLower(char *, char *); boolean strSuffixLower(char *, char *); void GetOptions(char **, void (*print_usage_function)(void)); void SetError(char *, ...); char *GetError(void); void Error(int, char *, ...); void *checked_malloc(unsigned long); void *checked_calloc(unsigned long); void *checked_realloc(void *, unsigned long); void checked_free(void *); void clear_mem(void *, unsigned long); void swap_numbers(int *, int *); void swap_number_pairs(int *, int *, int *, int *); int getFile8BitInteger(FILE *); int putFile8BitInteger(FILE *, int); int getFile16BitInteger(FILE *, int); int putFile16BitInteger(FILE *, int, int); int getFile32BitInteger(FILE *, int); int putFile32BitInteger(FILE *, int, int); boolean getFileChunk(FILE *, char *, int *, int); int putFileChunk(FILE *, char *, int, int); int getFileVersion(FILE *); int putFileVersion(FILE *, int); void ReadBytesFromFile(FILE *, byte *, unsigned long); void WriteBytesToFile(FILE *, byte *, unsigned long); void ReadUnusedBytesFromFile(FILE *, unsigned long); void WriteUnusedBytesToFile(FILE *, unsigned long); #define getFile8Bit(f) getFile8BitInteger(f) #define putFile8Bit(f,x) putFile8BitInteger(f,x) #define getFile16BitBE(f) getFile16BitInteger(f,BYTE_ORDER_BIG_ENDIAN) #define getFile16BitLE(f) getFile16BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN) #define putFile16BitBE(f,x) putFile16BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN) #define putFile16BitLE(f,x) putFile16BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN) #define getFile32BitBE(f) getFile32BitInteger(f,BYTE_ORDER_BIG_ENDIAN) #define getFile32BitLE(f) getFile32BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN) #define putFile32BitBE(f,x) putFile32BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN) #define putFile32BitLE(f,x) putFile32BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN) #define getFileChunkBE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN) #define getFileChunkLE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN) #define putFileChunkBE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN) #define putFileChunkLE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN) char *getKeyNameFromKey(Key); char *getX11KeyNameFromKey(Key); Key getKeyFromKeyName(char *); Key getKeyFromX11KeyName(char *); char getCharFromKey(Key); char getValidConfigValueChar(char); int get_integer_from_string(char *); boolean get_boolean_from_string(char *); int get_switch3_from_string(char *); ListNode *newListNode(void); void addNodeToList(ListNode **, char *, void *); void deleteNodeFromList(ListNode **, char *, void (*function)(void *)); ListNode *getNodeFromKey(ListNode *, char *); int getNumNodes(ListNode *); boolean fileExists(char *); boolean FileIsGraphic(char *); boolean FileIsSound(char *); boolean FileIsMusic(char *); boolean FileIsArtworkType(char *, int); char *get_mapped_token(char *); int get_parameter_value(char *, char *, int); struct ScreenModeInfo *get_screen_mode_from_string(char *); void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *, int *x, int *y); struct FileInfo *getFileListFromConfigList(struct ConfigInfo *, struct ConfigTypeInfo *, char **, int); void LoadArtworkConfig(struct ArtworkListInfo *); void ReloadCustomArtworkList(struct ArtworkListInfo *); void FreeCustomArtworkLists(struct ArtworkListInfo *); char *getErrorFilename(char *); void openErrorFile(); void closeErrorFile(); void dumpErrorFile(); void NotifyUserAboutErrorFile(); void debug_print_timestamp(int, char *); #endif /* MISC_H */ rocksndiamonds-3.3.0.1+dfsg1/src/config.c0000644000175000017500000000534011101570707017027 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * config.c * ***********************************************************/ #include "libgame/libgame.h" #include "config.h" #include "conftime.h" #define USE_EXTENDED_VERSION 1 char *getCompileDateString() { return COMPILE_DATE_STRING; } char *getProgramReleaseVersionString() { static char program_version_string[32]; #if USE_EXTENDED_VERSION sprintf(program_version_string, "%d.%d.%d.%d", PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH, PROGRAM_VERSION_BUILD); #else sprintf(program_version_string, "%d.%d.%d", PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH); #endif return program_version_string; } char *getProgramFullVersionString() { static char program_version_string[32]; #if USE_EXTENDED_VERSION sprintf(program_version_string, "%d.%d.%d.%d", PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH, PROGRAM_VERSION_BUILD); #else sprintf(program_version_string, "%d.%d.%d-%d", PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH, PROGRAM_VERSION_BUILD); #endif return program_version_string; } char *getProgramVersionString() { #ifdef DEBUG return getProgramFullVersionString(); #else return getProgramReleaseVersionString(); #endif } char *getProgramInitString() { static char *program_init_string = NULL; if (program_init_string == NULL) { program_init_string = checked_malloc(strlen(PROGRAM_TITLE_STRING) + 1 + strlen(getProgramVersionString()) +1 + strlen(TARGET_STRING) + 1); sprintf(program_init_string, "%s %s %s", PROGRAM_TITLE_STRING, getProgramVersionString(), TARGET_STRING); } return program_init_string; } char *getWindowTitleString() { #ifdef DEBUG static char *window_title_string = NULL; if (window_title_string == NULL) { window_title_string = checked_malloc(strlen(getProgramInitString()) + 1 + strlen(getCompileDateString()) + 2 +1); sprintf(window_title_string, "%s [%s]", getProgramInitString(), getCompileDateString()); } return window_title_string; #else return getProgramInitString(); #endif } rocksndiamonds-3.3.0.1+dfsg1/src/main.c0000644000175000017500000025162211364146774016532 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * main.c * ***********************************************************/ #include "libgame/libgame.h" #include "main.h" #include "init.h" #include "game.h" #include "tape.h" #include "events.h" #include "config.h" Bitmap *bitmap_db_store; Bitmap *bitmap_db_cross; Bitmap *bitmap_db_field; Bitmap *bitmap_db_panel; Bitmap *bitmap_db_door; Bitmap *bitmap_db_toons; DrawBuffer *fieldbuffer; DrawBuffer *drawto_field; int game_status = -1; boolean level_editor_test_game = FALSE; boolean network_playing = FALSE; #if defined(TARGET_SDL) boolean network_server = FALSE; SDL_Thread *server_thread; #endif int key_joystick_mapping = 0; #if 1 boolean redraw[MAX_LEV_FIELDX + 2][MAX_LEV_FIELDY + 2]; #else boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; #endif int redraw_x1 = 0, redraw_y1 = 0; short Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short AmoebaCnt[MAX_NUM_AMOEBA]; short AmoebaCnt2[MAX_NUM_AMOEBA]; short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int ActiveElement[MAX_NUM_ELEMENTS]; int ActiveButton[NUM_IMAGE_FILES]; int ActiveFont[NUM_FONTS]; int lev_fieldx, lev_fieldy; int scroll_x, scroll_y; int WIN_XSIZE = 672, WIN_YSIZE = 560; int SCR_FIELDX = 17, SCR_FIELDY = 17; int SX = 8, SY = 8; int REAL_SX = 6, REAL_SY = 6; int DX = 566, DY = 60; int VX = 566, VY = 400; int EX = 566, EY = 356; int dDX, dDY; #if 1 int FX, FY; #else int FX = SX, FY = SY; #endif int ScrollStepSize; int ScreenMovDir = MV_NONE, ScreenMovPos = 0; int ScreenGfxPos = 0; int BorderElement = EL_STEELWALL; int GameFrameDelay = GAME_FRAME_DELAY; int FfwdFrameDelay = FFWD_FRAME_DELAY; #if 1 int BX1, BY1; int BX2, BY2; #else int BX1 = 0, BY1 = 0; int BX2 = SCR_FIELDX - 1, BY2 = SCR_FIELDY - 1; #endif int SBX_Left, SBX_Right; int SBY_Upper, SBY_Lower; int ZX, ZY; int ExitX, ExitY; int AllPlayersGone; int TimeFrames, TimePlayed, TimeLeft, TapeTime; boolean network_player_action_received = FALSE; struct LevelSetInfo levelset; struct LevelInfo level, level_template; struct PlayerInfo stored_player[MAX_PLAYERS], *local_player = NULL; struct HiScore highscore[MAX_SCORE_ENTRIES]; struct TapeInfo tape; struct SetupInfo setup; struct GameInfo game; struct GlobalInfo global; struct BorderInfo border; struct ViewportInfo viewport; struct TitleFadingInfo fading; struct TitleFadingInfo title_initial_default; struct TitleFadingInfo title_default; struct TitleMessageInfo titlemessage_initial_default; struct TitleMessageInfo titlemessage_initial[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo titlemessage_default; struct TitleMessageInfo titlemessage[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo readme; struct InitInfo init, init_last; struct MenuInfo menu; struct DoorInfo door_1, door_2; struct PreviewInfo preview; struct GraphicInfo *graphic_info = NULL; struct SoundInfo *sound_info = NULL; struct MusicInfo *music_info = NULL; struct MusicFileInfo *music_file_info = NULL; struct HelpAnimInfo *helpanim_info = NULL; SetupFileHash *helptext_info = NULL; SetupFileHash *image_config_hash = NULL; SetupFileHash *element_token_hash = NULL; SetupFileHash *graphic_token_hash = NULL; SetupFileHash *font_token_hash = NULL; /* ------------------------------------------------------------------------- */ /* element definitions */ /* ------------------------------------------------------------------------- */ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1]; /* this contains predefined structure elements to initialize "element_info" */ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] = { /* keyword to start parser: "ELEMENT_INFO_START" <-- do not change! */ /* ----------------------------------------------------------------------- */ /* "real" level file elements */ /* ----------------------------------------------------------------------- */ { "empty_space", "empty_space", "empty space" }, { "sand", "sand", "sand" }, { "wall", "wall", "normal wall" }, { "wall_slippery", "wall", "slippery wall" }, { "rock", "rock", "rock" }, { "key_obsolete", "obsolete", "key (OBSOLETE)" }, { "emerald", "emerald", "emerald" }, { "exit_closed", "exit", "closed exit" }, { "player_obsolete", "obsolete", "player (OBSOLETE)" }, { "bug", "bug", "bug (random start direction)" }, { "spaceship", "spaceship", "spaceship (random start direction)" }, { "yamyam", "yamyam", "yam yam (random start direction)" }, { "robot", "robot", "robot" }, { "steelwall", "steelwall", "steel wall" }, { "diamond", "diamond", "diamond" }, { "amoeba_dead", "amoeba", "dead amoeba" }, { "quicksand_empty", "quicksand", "quicksand (empty)" }, { "quicksand_full", "quicksand", "quicksand (with rock)" }, { "amoeba_drop", "amoeba", "amoeba drop" }, { "bomb", "bomb", "bomb" }, { "magic_wall", "magic_wall", "magic wall" }, { "speed_pill", "speed_pill", "speed pill" }, { "acid", "acid", "acid" }, { "amoeba_wet", "amoeba", "dropping amoeba (EM style)" }, { "amoeba_dry", "amoeba", "normal amoeba" }, { "nut", "nut", "nut with emerald" }, { "game_of_life", "game_of_life", "Conway's wall of life" }, { "biomaze", "biomaze", "biomaze" }, { "dynamite.active", "dynamite", "burning dynamite" }, { "stoneblock", "wall", "wall" }, { "robot_wheel", "robot_wheel", "magic wheel" }, { "robot_wheel.active", "robot_wheel", "magic wheel (running)" }, { "key_1", "key", "key 1" }, { "key_2", "key", "key 2" }, { "key_3", "key", "key 3" }, { "key_4", "key", "key 4" }, { "gate_1", "gate", "door 1" }, { "gate_2", "gate", "door 2" }, { "gate_3", "gate", "door 3" }, { "gate_4", "gate", "door 4" }, { "gate_1_gray", "gate", "gray door (opened by key 1)" }, { "gate_2_gray", "gate", "gray door (opened by key 2)" }, { "gate_3_gray", "gate", "gray door (opened by key 3)" }, { "gate_4_gray", "gate", "gray door (opened by key 4)" }, { "dynamite", "dynamite", "dynamite" }, { "pacman", "pacman", "pac man (random start direction)" }, { "invisible_wall", "wall", "invisible normal wall" }, { "lamp", "lamp", "lamp (off)" }, { "lamp.active", "lamp", "lamp (on)" }, { "wall_emerald", "wall", "wall with emerald" }, { "wall_diamond", "wall", "wall with diamond" }, { "amoeba_full", "amoeba", "amoeba with content" }, { "bd_amoeba", "bd_amoeba", "amoeba (BD style)" }, { "time_orb_full", "time_orb_full", "time orb (full)" }, { "time_orb_empty", "time_orb_empty", "time orb (empty)" }, { "expandable_wall", "wall", "growing wall (horizontal, visible)" }, { "bd_diamond", "bd_diamond", "diamond (BD style)" }, { "emerald_yellow", "emerald", "yellow emerald" }, { "wall_bd_diamond", "wall", "wall with BD style diamond" }, { "wall_emerald_yellow", "wall", "wall with yellow emerald" }, { "dark_yamyam", "dark_yamyam", "dark yam yam" }, { "bd_magic_wall", "bd_magic_wall", "magic wall (BD style)" }, { "invisible_steelwall", "steelwall", "invisible steel wall" }, { "sokoban_field_player", "sokoban", "sokoban field with player" }, { "dynabomb_increase_number", "dynabomb", "increases number of bombs" }, { "dynabomb_increase_size", "dynabomb", "increases explosion size" }, { "dynabomb_increase_power", "dynabomb", "increases power of explosion" }, { "sokoban_object", "sokoban", "sokoban object" }, { "sokoban_field_empty", "sokoban", "sokoban empty field" }, { "sokoban_field_full", "sokoban", "sokoban field with object" }, { "bd_butterfly.right", "bd_butterfly", "butterfly (starts moving right)"}, { "bd_butterfly.up", "bd_butterfly", "butterfly (starts moving up)" }, { "bd_butterfly.left", "bd_butterfly", "butterfly (starts moving left)"}, { "bd_butterfly.down", "bd_butterfly", "butterfly (starts moving down)"}, { "bd_firefly.right", "bd_firefly", "firefly (starts moving right)" }, { "bd_firefly.up", "bd_firefly", "firefly (starts moving up)" }, { "bd_firefly.left", "bd_firefly", "firefly (starts moving left)" }, { "bd_firefly.down", "bd_firefly", "firefly (starts moving down)" }, { "bd_butterfly", "bd_butterfly", "butterfly (random start direction)" }, { "bd_firefly", "bd_firefly", "firefly (random start direction)" }, { "player_1", "player", "player 1" }, { "player_2", "player", "player 2" }, { "player_3", "player", "player 3" }, { "player_4", "player", "player 4" }, { "bug.right", "bug", "bug (starts moving right)" }, { "bug.up", "bug", "bug (starts moving up)" }, { "bug.left", "bug", "bug (starts moving left)" }, { "bug.down", "bug", "bug (starts moving down)" }, { "spaceship.right", "spaceship", "spaceship (starts moving right)"}, { "spaceship.up", "spaceship", "spaceship (starts moving up)" }, { "spaceship.left", "spaceship", "spaceship (starts moving left)"}, { "spaceship.down", "spaceship", "spaceship (starts moving down)"}, { "pacman.right", "pacman", "pac man (starts moving right)" }, { "pacman.up", "pacman", "pac man (starts moving up)" }, { "pacman.left", "pacman", "pac man (starts moving left)" }, { "pacman.down", "pacman", "pac man (starts moving down)" }, { "emerald_red", "emerald", "red emerald" }, { "emerald_purple", "emerald", "purple emerald" }, { "wall_emerald_red", "wall", "wall with red emerald" }, { "wall_emerald_purple", "wall", "wall with purple emerald" }, { "acid_pool_topleft", "wall", "acid pool (top left)" }, { "acid_pool_topright", "wall", "acid pool (top right)" }, { "acid_pool_bottomleft", "wall", "acid pool (bottom left)" }, { "acid_pool_bottom", "wall", "acid pool (bottom)" }, { "acid_pool_bottomright", "wall", "acid pool (bottom right)" }, { "bd_wall", "wall", "normal wall (BD style)" }, { "bd_rock", "bd_rock", "rock (BD style)" }, { "exit_open", "exit", "open exit" }, { "black_orb", "black_orb", "black orb bomb" }, { "amoeba_to_diamond", "amoeba", "amoeba" }, { "mole", "mole", "mole (random start direction)" }, { "penguin", "penguin", "penguin" }, { "satellite", "satellite", "satellite" }, { "arrow_left", "arrow", "arrow left" }, { "arrow_right", "arrow", "arrow right" }, { "arrow_up", "arrow", "arrow up" }, { "arrow_down", "arrow", "arrow down" }, { "pig", "pig", "pig" }, { "dragon", "dragon", "fire breathing dragon" }, { "em_key_1_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "char_space", "char", "letter ' '" }, { "char_exclam", "char", "letter '!'" }, { "char_quotedbl", "char", "letter '\"'" }, { "char_numbersign", "char", "letter '#'" }, { "char_dollar", "char", "letter '$'" }, { "char_percent", "char", "letter '%'" }, { "char_ampersand", "char", "letter '&'" }, { "char_apostrophe", "char", "letter '''" }, { "char_parenleft", "char", "letter '('" }, { "char_parenright", "char", "letter ')'" }, { "char_asterisk", "char", "letter '*'" }, { "char_plus", "char", "letter '+'" }, { "char_comma", "char", "letter ','" }, { "char_minus", "char", "letter '-'" }, { "char_period", "char", "letter '.'" }, { "char_slash", "char", "letter '/'" }, { "char_0", "char", "letter '0'" }, { "char_1", "char", "letter '1'" }, { "char_2", "char", "letter '2'" }, { "char_3", "char", "letter '3'" }, { "char_4", "char", "letter '4'" }, { "char_5", "char", "letter '5'" }, { "char_6", "char", "letter '6'" }, { "char_7", "char", "letter '7'" }, { "char_8", "char", "letter '8'" }, { "char_9", "char", "letter '9'" }, { "char_colon", "char", "letter ':'" }, { "char_semicolon", "char", "letter ';'" }, { "char_less", "char", "letter '<'" }, { "char_equal", "char", "letter '='" }, { "char_greater", "char", "letter '>'" }, { "char_question", "char", "letter '?'" }, { "char_at", "char", "letter '@'" }, { "char_a", "char", "letter 'A'" }, { "char_b", "char", "letter 'B'" }, { "char_c", "char", "letter 'C'" }, { "char_d", "char", "letter 'D'" }, { "char_e", "char", "letter 'E'" }, { "char_f", "char", "letter 'F'" }, { "char_g", "char", "letter 'G'" }, { "char_h", "char", "letter 'H'" }, { "char_i", "char", "letter 'I'" }, { "char_j", "char", "letter 'J'" }, { "char_k", "char", "letter 'K'" }, { "char_l", "char", "letter 'L'" }, { "char_m", "char", "letter 'M'" }, { "char_n", "char", "letter 'N'" }, { "char_o", "char", "letter 'O'" }, { "char_p", "char", "letter 'P'" }, { "char_q", "char", "letter 'Q'" }, { "char_r", "char", "letter 'R'" }, { "char_s", "char", "letter 'S'" }, { "char_t", "char", "letter 'T'" }, { "char_u", "char", "letter 'U'" }, { "char_v", "char", "letter 'V'" }, { "char_w", "char", "letter 'W'" }, { "char_x", "char", "letter 'X'" }, { "char_y", "char", "letter 'Y'" }, { "char_z", "char", "letter 'Z'" }, { "char_bracketleft", "char", "letter '['" }, { "char_backslash", "char", "letter '\\'" }, { "char_bracketright", "char", "letter ']'" }, { "char_asciicircum", "char", "letter '^'" }, { "char_underscore", "char", "letter '_'" }, { "char_copyright", "char", "letter '©'" }, { "char_aumlaut", "char", "letter 'Ä'" }, { "char_oumlaut", "char", "letter 'Ö'" }, { "char_uumlaut", "char", "letter 'Ü'" }, { "char_degree", "char", "letter '°'" }, { "char_trademark", "char", "letter '®'" }, { "char_cursor", "char", "letter ' '" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter 'button'" }, { "char_unused", "char", "letter 'up'" }, { "char_unused", "char", "letter 'down'" }, { "expandable_wall_horizontal", "wall", "growing wall (horizontal)" }, { "expandable_wall_vertical", "wall", "growing wall (vertical)" }, { "expandable_wall_any", "wall", "growing wall (any direction)" }, { "em_gate_1", "gate", "door 1 (EM style)" }, { "em_gate_2", "gate", "door 2 (EM style)" }, { "em_gate_3", "gate", "door 3 (EM style)" }, { "em_gate_4", "gate", "door 4 (EM style)" }, { "em_key_2_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "em_key_3_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "em_key_4_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "sp_empty_space", "empty_space", "empty space" }, { "sp_zonk", "sp_zonk", "zonk" }, { "sp_base", "sp_base", "base" }, { "sp_murphy", "player", "murphy" }, { "sp_infotron", "sp_infotron", "infotron" }, { "sp_chip_single", "wall", "chip (single)" }, { "sp_hardware_gray", "wall", "hardware" }, { "sp_exit_closed", "sp_exit", "exit" }, { "sp_disk_orange", "sp_disk_orange", "orange disk" }, { "sp_port_right", "sp_port", "port (leading right)" }, { "sp_port_down", "sp_port", "port (leading down)" }, { "sp_port_left", "sp_port", "port (leading left)" }, { "sp_port_up", "sp_port", "port (leading up)" }, { "sp_gravity_port_right", "sp_gravity_port", "gravity-on/off port (leading right)" }, { "sp_gravity_port_down", "sp_gravity_port", "gravity-on/off port (leading down)" }, { "sp_gravity_port_left", "sp_gravity_port", "gravity-on/off port (leading left)" }, { "sp_gravity_port_up", "sp_gravity_port", "gravity-on/off port (leading up)" }, { "sp_sniksnak", "sp_sniksnak", "snik snak" }, { "sp_disk_yellow", "sp_disk_yellow", "yellow disk" }, { "sp_terminal", "sp_terminal", "terminal" }, { "sp_disk_red", "dynamite", "red disk" }, { "sp_port_vertical", "sp_port", "port (vertical)" }, { "sp_port_horizontal", "sp_port", "port (horizontal)" }, { "sp_port_any", "sp_port", "port (any direction)" }, { "sp_electron", "sp_electron", "electron" }, { "sp_buggy_base", "sp_buggy_base", "buggy base" }, { "sp_chip_left", "wall", "chip (left half)" }, { "sp_chip_right", "wall", "chip (right half)" }, { "sp_hardware_base_1", "wall", "hardware" }, { "sp_hardware_green", "wall", "hardware" }, { "sp_hardware_blue", "wall", "hardware" }, { "sp_hardware_red", "wall", "hardware" }, { "sp_hardware_yellow", "wall", "hardware" }, { "sp_hardware_base_2", "wall", "hardware" }, { "sp_hardware_base_3", "wall", "hardware" }, { "sp_hardware_base_4", "wall", "hardware" }, { "sp_hardware_base_5", "wall", "hardware" }, { "sp_hardware_base_6", "wall", "hardware" }, { "sp_chip_top", "wall", "chip (upper half)" }, { "sp_chip_bottom", "wall", "chip (lower half)" }, { "em_gate_1_gray", "gate", "gray door (EM style, key 1)" }, { "em_gate_2_gray", "gate", "gray door (EM style, key 2)" }, { "em_gate_3_gray", "gate", "gray door (EM style, key 3)" }, { "em_gate_4_gray", "gate", "gray door (EM style, key 4)" }, { "em_dynamite", "dynamite", "dynamite (EM style)" }, { "em_dynamite.active", "dynamite", "burning dynamite (EM style)" }, { "pearl", "pearl", "pearl" }, { "crystal", "crystal", "crystal" }, { "wall_pearl", "wall", "wall with pearl" }, { "wall_crystal", "wall", "wall with crystal" }, { "dc_gate_white", "gate", "white door" }, { "dc_gate_white_gray", "gate", "gray door (opened by white key)" }, { "dc_key_white", "key", "white key" }, { "shield_normal", "shield_normal", "shield (normal)" }, { "extra_time", "extra_time", "extra time" }, { "switchgate_open", "switchgate", "switch gate (open)" }, { "switchgate_closed", "switchgate", "switch gate (closed)" }, { "switchgate_switch_up", "switchgate_switch", "switch for switch gate" }, { "switchgate_switch_down", "switchgate_switch", "switch for switch gate" }, { "unused_269", "unused", "-" }, { "unused_270", "unused", "-" }, { "conveyor_belt_1_left", "conveyor_belt", "conveyor belt 1 (left)" }, { "conveyor_belt_1_middle", "conveyor_belt", "conveyor belt 1 (middle)" }, { "conveyor_belt_1_right", "conveyor_belt", "conveyor belt 1 (right)" }, { "conveyor_belt_1_switch_left", "conveyor_belt_switch", "switch for conveyor belt 1 (left)" }, { "conveyor_belt_1_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 1 (middle)" }, { "conveyor_belt_1_switch_right", "conveyor_belt_switch", "switch for conveyor belt 1 (right)" }, { "conveyor_belt_2_left", "conveyor_belt", "conveyor belt 2 (left)" }, { "conveyor_belt_2_middle", "conveyor_belt", "conveyor belt 2 (middle)" }, { "conveyor_belt_2_right", "conveyor_belt", "conveyor belt 2 (right)" }, { "conveyor_belt_2_switch_left", "conveyor_belt_switch", "switch for conveyor belt 2 (left)" }, { "conveyor_belt_2_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 2 (middle)" }, { "conveyor_belt_2_switch_right", "conveyor_belt_switch", "switch for conveyor belt 2 (right)" }, { "conveyor_belt_3_left", "conveyor_belt", "conveyor belt 3 (left)" }, { "conveyor_belt_3_middle", "conveyor_belt", "conveyor belt 3 (middle)" }, { "conveyor_belt_3_right", "conveyor_belt", "conveyor belt 3 (right)" }, { "conveyor_belt_3_switch_left", "conveyor_belt_switch", "switch for conveyor belt 3 (left)" }, { "conveyor_belt_3_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 3 (middle)" }, { "conveyor_belt_3_switch_right", "conveyor_belt_switch", "switch for conveyor belt 3 (right)" }, { "conveyor_belt_4_left", "conveyor_belt", "conveyor belt 4 (left)" }, { "conveyor_belt_4_middle", "conveyor_belt", "conveyor belt 4 (middle)" }, { "conveyor_belt_4_right", "conveyor_belt", "conveyor belt 4 (right)" }, { "conveyor_belt_4_switch_left", "conveyor_belt_switch", "switch for conveyor belt 4 (left)" }, { "conveyor_belt_4_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 4 (middle)" }, { "conveyor_belt_4_switch_right", "conveyor_belt_switch", "switch for conveyor belt 4 (right)" }, { "landmine", "landmine", "land mine (not removable)" }, { "envelope_obsolete", "obsolete", "envelope (OBSOLETE)" }, { "light_switch", "light_switch", "light switch (off)" }, { "light_switch.active", "light_switch", "light switch (on)" }, { "sign_exclamation", "sign", "sign (exclamation)" }, { "sign_radioactivity", "sign", "sign (radio activity)" }, { "sign_stop", "sign", "sign (stop)" }, { "sign_wheelchair", "sign", "sign (wheel chair)" }, { "sign_parking", "sign", "sign (parking)" }, { "sign_no_entry", "sign", "sign (no entry)" }, { "sign_unused_1", "sign", "sign (unused)" }, { "sign_give_way", "sign", "sign (give way)" }, { "sign_entry_forbidden", "sign", "sign (entry forbidden)" }, { "sign_emergency_exit", "sign", "sign (emergency exit)" }, { "sign_yin_yang", "sign", "sign (yin yang)" }, { "sign_unused_2", "sign", "sign (unused)" }, { "mole.left", "mole", "mole (starts moving left)" }, { "mole.right", "mole", "mole (starts moving right)" }, { "mole.up", "mole", "mole (starts moving up)" }, { "mole.down", "mole", "mole (starts moving down)" }, { "steelwall_slippery", "steelwall", "slippery steel wall" }, { "invisible_sand", "sand", "invisible sand" }, { "dx_unknown_15", "unknown", "dx unknown element 15" }, { "dx_unknown_42", "unknown", "dx unknown element 42" }, { "unused_319", "unused", "(not used)" }, { "unused_320", "unused", "(not used)" }, { "shield_deadly", "shield_deadly", "shield (deadly, kills enemies)" }, { "timegate_open", "timegate", "time gate (open)" }, { "timegate_closed", "timegate", "time gate (closed)" }, { "timegate_switch.active", "timegate_switch", "switch for time gate" }, { "timegate_switch", "timegate_switch", "switch for time gate" }, { "balloon", "balloon", "balloon" }, { "balloon_switch_left", "balloon_switch", "wind switch (left)" }, { "balloon_switch_right", "balloon_switch", "wind switch (right)" }, { "balloon_switch_up", "balloon_switch", "wind switch (up)" }, { "balloon_switch_down", "balloon_switch", "wind switch (down)" }, { "balloon_switch_any", "balloon_switch", "wind switch (any direction)" }, { "emc_steelwall_1", "steelwall", "steel wall" }, { "emc_steelwall_2", "steelwall", "steel wall" }, { "emc_steelwall_3", "steelwall", "steel wall" }, { "emc_steelwall_4", "steelwall", "steel wall" }, { "emc_wall_1", "wall", "normal wall" }, { "emc_wall_2", "wall", "normal wall" }, { "emc_wall_3", "wall", "normal wall" }, { "emc_wall_4", "wall", "normal wall" }, { "emc_wall_5", "wall", "normal wall" }, { "emc_wall_6", "wall", "normal wall" }, { "emc_wall_7", "wall", "normal wall" }, { "emc_wall_8", "wall", "normal wall" }, { "tube_any", "tube", "tube (any direction)" }, { "tube_vertical", "tube", "tube (vertical)" }, { "tube_horizontal", "tube", "tube (horizontal)" }, { "tube_vertical_left", "tube", "tube (vertical & left)" }, { "tube_vertical_right", "tube", "tube (vertical & right)" }, { "tube_horizontal_up", "tube", "tube (horizontal & up)" }, { "tube_horizontal_down", "tube", "tube (horizontal & down)" }, { "tube_left_up", "tube", "tube (left & up)" }, { "tube_left_down", "tube", "tube (left & down)" }, { "tube_right_up", "tube", "tube (right & up)" }, { "tube_right_down", "tube", "tube (right & down)" }, { "spring", "spring", "spring" }, { "trap", "trap", "trap" }, { "dx_supabomb", "bomb", "stable bomb (DX style)" }, { "unused_358", "unused", "-" }, { "unused_359", "unused", "-" }, { "custom_1", "custom", "custom element 1" }, { "custom_2", "custom", "custom element 2" }, { "custom_3", "custom", "custom element 3" }, { "custom_4", "custom", "custom element 4" }, { "custom_5", "custom", "custom element 5" }, { "custom_6", "custom", "custom element 6" }, { "custom_7", "custom", "custom element 7" }, { "custom_8", "custom", "custom element 8" }, { "custom_9", "custom", "custom element 9" }, { "custom_10", "custom", "custom element 10" }, { "custom_11", "custom", "custom element 11" }, { "custom_12", "custom", "custom element 12" }, { "custom_13", "custom", "custom element 13" }, { "custom_14", "custom", "custom element 14" }, { "custom_15", "custom", "custom element 15" }, { "custom_16", "custom", "custom element 16" }, { "custom_17", "custom", "custom element 17" }, { "custom_18", "custom", "custom element 18" }, { "custom_19", "custom", "custom element 19" }, { "custom_20", "custom", "custom element 20" }, { "custom_21", "custom", "custom element 21" }, { "custom_22", "custom", "custom element 22" }, { "custom_23", "custom", "custom element 23" }, { "custom_24", "custom", "custom element 24" }, { "custom_25", "custom", "custom element 25" }, { "custom_26", "custom", "custom element 26" }, { "custom_27", "custom", "custom element 27" }, { "custom_28", "custom", "custom element 28" }, { "custom_29", "custom", "custom element 29" }, { "custom_30", "custom", "custom element 30" }, { "custom_31", "custom", "custom element 31" }, { "custom_32", "custom", "custom element 32" }, { "custom_33", "custom", "custom element 33" }, { "custom_34", "custom", "custom element 34" }, { "custom_35", "custom", "custom element 35" }, { "custom_36", "custom", "custom element 36" }, { "custom_37", "custom", "custom element 37" }, { "custom_38", "custom", "custom element 38" }, { "custom_39", "custom", "custom element 39" }, { "custom_40", "custom", "custom element 40" }, { "custom_41", "custom", "custom element 41" }, { "custom_42", "custom", "custom element 42" }, { "custom_43", "custom", "custom element 43" }, { "custom_44", "custom", "custom element 44" }, { "custom_45", "custom", "custom element 45" }, { "custom_46", "custom", "custom element 46" }, { "custom_47", "custom", "custom element 47" }, { "custom_48", "custom", "custom element 48" }, { "custom_49", "custom", "custom element 49" }, { "custom_50", "custom", "custom element 50" }, { "custom_51", "custom", "custom element 51" }, { "custom_52", "custom", "custom element 52" }, { "custom_53", "custom", "custom element 53" }, { "custom_54", "custom", "custom element 54" }, { "custom_55", "custom", "custom element 55" }, { "custom_56", "custom", "custom element 56" }, { "custom_57", "custom", "custom element 57" }, { "custom_58", "custom", "custom element 58" }, { "custom_59", "custom", "custom element 59" }, { "custom_60", "custom", "custom element 60" }, { "custom_61", "custom", "custom element 61" }, { "custom_62", "custom", "custom element 62" }, { "custom_63", "custom", "custom element 63" }, { "custom_64", "custom", "custom element 64" }, { "custom_65", "custom", "custom element 65" }, { "custom_66", "custom", "custom element 66" }, { "custom_67", "custom", "custom element 67" }, { "custom_68", "custom", "custom element 68" }, { "custom_69", "custom", "custom element 69" }, { "custom_70", "custom", "custom element 70" }, { "custom_71", "custom", "custom element 71" }, { "custom_72", "custom", "custom element 72" }, { "custom_73", "custom", "custom element 73" }, { "custom_74", "custom", "custom element 74" }, { "custom_75", "custom", "custom element 75" }, { "custom_76", "custom", "custom element 76" }, { "custom_77", "custom", "custom element 77" }, { "custom_78", "custom", "custom element 78" }, { "custom_79", "custom", "custom element 79" }, { "custom_80", "custom", "custom element 80" }, { "custom_81", "custom", "custom element 81" }, { "custom_82", "custom", "custom element 82" }, { "custom_83", "custom", "custom element 83" }, { "custom_84", "custom", "custom element 84" }, { "custom_85", "custom", "custom element 85" }, { "custom_86", "custom", "custom element 86" }, { "custom_87", "custom", "custom element 87" }, { "custom_88", "custom", "custom element 88" }, { "custom_89", "custom", "custom element 89" }, { "custom_90", "custom", "custom element 90" }, { "custom_91", "custom", "custom element 91" }, { "custom_92", "custom", "custom element 92" }, { "custom_93", "custom", "custom element 93" }, { "custom_94", "custom", "custom element 94" }, { "custom_95", "custom", "custom element 95" }, { "custom_96", "custom", "custom element 96" }, { "custom_97", "custom", "custom element 97" }, { "custom_98", "custom", "custom element 98" }, { "custom_99", "custom", "custom element 99" }, { "custom_100", "custom", "custom element 100" }, { "custom_101", "custom", "custom element 101" }, { "custom_102", "custom", "custom element 102" }, { "custom_103", "custom", "custom element 103" }, { "custom_104", "custom", "custom element 104" }, { "custom_105", "custom", "custom element 105" }, { "custom_106", "custom", "custom element 106" }, { "custom_107", "custom", "custom element 107" }, { "custom_108", "custom", "custom element 108" }, { "custom_109", "custom", "custom element 109" }, { "custom_110", "custom", "custom element 110" }, { "custom_111", "custom", "custom element 111" }, { "custom_112", "custom", "custom element 112" }, { "custom_113", "custom", "custom element 113" }, { "custom_114", "custom", "custom element 114" }, { "custom_115", "custom", "custom element 115" }, { "custom_116", "custom", "custom element 116" }, { "custom_117", "custom", "custom element 117" }, { "custom_118", "custom", "custom element 118" }, { "custom_119", "custom", "custom element 119" }, { "custom_120", "custom", "custom element 120" }, { "custom_121", "custom", "custom element 121" }, { "custom_122", "custom", "custom element 122" }, { "custom_123", "custom", "custom element 123" }, { "custom_124", "custom", "custom element 124" }, { "custom_125", "custom", "custom element 125" }, { "custom_126", "custom", "custom element 126" }, { "custom_127", "custom", "custom element 127" }, { "custom_128", "custom", "custom element 128" }, { "custom_129", "custom", "custom element 129" }, { "custom_130", "custom", "custom element 130" }, { "custom_131", "custom", "custom element 131" }, { "custom_132", "custom", "custom element 132" }, { "custom_133", "custom", "custom element 133" }, { "custom_134", "custom", "custom element 134" }, { "custom_135", "custom", "custom element 135" }, { "custom_136", "custom", "custom element 136" }, { "custom_137", "custom", "custom element 137" }, { "custom_138", "custom", "custom element 138" }, { "custom_139", "custom", "custom element 139" }, { "custom_140", "custom", "custom element 140" }, { "custom_141", "custom", "custom element 141" }, { "custom_142", "custom", "custom element 142" }, { "custom_143", "custom", "custom element 143" }, { "custom_144", "custom", "custom element 144" }, { "custom_145", "custom", "custom element 145" }, { "custom_146", "custom", "custom element 146" }, { "custom_147", "custom", "custom element 147" }, { "custom_148", "custom", "custom element 148" }, { "custom_149", "custom", "custom element 149" }, { "custom_150", "custom", "custom element 150" }, { "custom_151", "custom", "custom element 151" }, { "custom_152", "custom", "custom element 152" }, { "custom_153", "custom", "custom element 153" }, { "custom_154", "custom", "custom element 154" }, { "custom_155", "custom", "custom element 155" }, { "custom_156", "custom", "custom element 156" }, { "custom_157", "custom", "custom element 157" }, { "custom_158", "custom", "custom element 158" }, { "custom_159", "custom", "custom element 159" }, { "custom_160", "custom", "custom element 160" }, { "custom_161", "custom", "custom element 161" }, { "custom_162", "custom", "custom element 162" }, { "custom_163", "custom", "custom element 163" }, { "custom_164", "custom", "custom element 164" }, { "custom_165", "custom", "custom element 165" }, { "custom_166", "custom", "custom element 166" }, { "custom_167", "custom", "custom element 167" }, { "custom_168", "custom", "custom element 168" }, { "custom_169", "custom", "custom element 169" }, { "custom_170", "custom", "custom element 170" }, { "custom_171", "custom", "custom element 171" }, { "custom_172", "custom", "custom element 172" }, { "custom_173", "custom", "custom element 173" }, { "custom_174", "custom", "custom element 174" }, { "custom_175", "custom", "custom element 175" }, { "custom_176", "custom", "custom element 176" }, { "custom_177", "custom", "custom element 177" }, { "custom_178", "custom", "custom element 178" }, { "custom_179", "custom", "custom element 179" }, { "custom_180", "custom", "custom element 180" }, { "custom_181", "custom", "custom element 181" }, { "custom_182", "custom", "custom element 182" }, { "custom_183", "custom", "custom element 183" }, { "custom_184", "custom", "custom element 184" }, { "custom_185", "custom", "custom element 185" }, { "custom_186", "custom", "custom element 186" }, { "custom_187", "custom", "custom element 187" }, { "custom_188", "custom", "custom element 188" }, { "custom_189", "custom", "custom element 189" }, { "custom_190", "custom", "custom element 190" }, { "custom_191", "custom", "custom element 191" }, { "custom_192", "custom", "custom element 192" }, { "custom_193", "custom", "custom element 193" }, { "custom_194", "custom", "custom element 194" }, { "custom_195", "custom", "custom element 195" }, { "custom_196", "custom", "custom element 196" }, { "custom_197", "custom", "custom element 197" }, { "custom_198", "custom", "custom element 198" }, { "custom_199", "custom", "custom element 199" }, { "custom_200", "custom", "custom element 200" }, { "custom_201", "custom", "custom element 201" }, { "custom_202", "custom", "custom element 202" }, { "custom_203", "custom", "custom element 203" }, { "custom_204", "custom", "custom element 204" }, { "custom_205", "custom", "custom element 205" }, { "custom_206", "custom", "custom element 206" }, { "custom_207", "custom", "custom element 207" }, { "custom_208", "custom", "custom element 208" }, { "custom_209", "custom", "custom element 209" }, { "custom_210", "custom", "custom element 210" }, { "custom_211", "custom", "custom element 211" }, { "custom_212", "custom", "custom element 212" }, { "custom_213", "custom", "custom element 213" }, { "custom_214", "custom", "custom element 214" }, { "custom_215", "custom", "custom element 215" }, { "custom_216", "custom", "custom element 216" }, { "custom_217", "custom", "custom element 217" }, { "custom_218", "custom", "custom element 218" }, { "custom_219", "custom", "custom element 219" }, { "custom_220", "custom", "custom element 220" }, { "custom_221", "custom", "custom element 221" }, { "custom_222", "custom", "custom element 222" }, { "custom_223", "custom", "custom element 223" }, { "custom_224", "custom", "custom element 224" }, { "custom_225", "custom", "custom element 225" }, { "custom_226", "custom", "custom element 226" }, { "custom_227", "custom", "custom element 227" }, { "custom_228", "custom", "custom element 228" }, { "custom_229", "custom", "custom element 229" }, { "custom_230", "custom", "custom element 230" }, { "custom_231", "custom", "custom element 231" }, { "custom_232", "custom", "custom element 232" }, { "custom_233", "custom", "custom element 233" }, { "custom_234", "custom", "custom element 234" }, { "custom_235", "custom", "custom element 235" }, { "custom_236", "custom", "custom element 236" }, { "custom_237", "custom", "custom element 237" }, { "custom_238", "custom", "custom element 238" }, { "custom_239", "custom", "custom element 239" }, { "custom_240", "custom", "custom element 240" }, { "custom_241", "custom", "custom element 241" }, { "custom_242", "custom", "custom element 242" }, { "custom_243", "custom", "custom element 243" }, { "custom_244", "custom", "custom element 244" }, { "custom_245", "custom", "custom element 245" }, { "custom_246", "custom", "custom element 246" }, { "custom_247", "custom", "custom element 247" }, { "custom_248", "custom", "custom element 248" }, { "custom_249", "custom", "custom element 249" }, { "custom_250", "custom", "custom element 250" }, { "custom_251", "custom", "custom element 251" }, { "custom_252", "custom", "custom element 252" }, { "custom_253", "custom", "custom element 253" }, { "custom_254", "custom", "custom element 254" }, { "custom_255", "custom", "custom element 255" }, { "custom_256", "custom", "custom element 256" }, { "em_key_1", "key", "key 1 (EM style)" }, { "em_key_2", "key", "key 2 (EM style)" }, { "em_key_3", "key", "key 3 (EM style)" }, { "em_key_4", "key", "key 4 (EM style)" }, { "envelope_1", "envelope", "mail envelope 1" }, { "envelope_2", "envelope", "mail envelope 2" }, { "envelope_3", "envelope", "mail envelope 3" }, { "envelope_4", "envelope", "mail envelope 4" }, { "group_1", "group", "group element 1" }, { "group_2", "group", "group element 2" }, { "group_3", "group", "group element 3" }, { "group_4", "group", "group element 4" }, { "group_5", "group", "group element 5" }, { "group_6", "group", "group element 6" }, { "group_7", "group", "group element 7" }, { "group_8", "group", "group element 8" }, { "group_9", "group", "group element 9" }, { "group_10", "group", "group element 10" }, { "group_11", "group", "group element 11" }, { "group_12", "group", "group element 12" }, { "group_13", "group", "group element 13" }, { "group_14", "group", "group element 14" }, { "group_15", "group", "group element 15" }, { "group_16", "group", "group element 16" }, { "group_17", "group", "group element 17" }, { "group_18", "group", "group element 18" }, { "group_19", "group", "group element 19" }, { "group_20", "group", "group element 20" }, { "group_21", "group", "group element 21" }, { "group_22", "group", "group element 22" }, { "group_23", "group", "group element 23" }, { "group_24", "group", "group element 24" }, { "group_25", "group", "group element 25" }, { "group_26", "group", "group element 26" }, { "group_27", "group", "group element 27" }, { "group_28", "group", "group element 28" }, { "group_29", "group", "group element 29" }, { "group_30", "group", "group element 30" }, { "group_31", "group", "group element 31" }, { "group_32", "group", "group element 32" }, { "unknown", "unknown", "unknown element" }, { "trigger_element", "trigger", "element triggering change" }, { "trigger_player", "trigger", "player triggering change" }, { "sp_gravity_on_port_right", "sp_gravity_on_port", "gravity-on port (leading right)" }, { "sp_gravity_on_port_down", "sp_gravity_on_port", "gravity-on port (leading down)" }, { "sp_gravity_on_port_left", "sp_gravity_on_port", "gravity-on port (leading left)" }, { "sp_gravity_on_port_up", "sp_gravity_on_port", "gravity-on port (leading up)" }, { "sp_gravity_off_port_right", "sp_gravity_off_port", "gravity-off port (leading right)" }, { "sp_gravity_off_port_down", "sp_gravity_off_port", "gravity-off port (leading down)" }, { "sp_gravity_off_port_left", "sp_gravity_off_port", "gravity-off port (leading left)" }, { "sp_gravity_off_port_up", "sp_gravity_off_port", "gravity-off port (leading up)" }, { "balloon_switch_none", "balloon_switch", "wind switch (off)" }, { "emc_gate_5", "gate", "door 5 (EMC style)", }, { "emc_gate_6", "gate", "door 6 (EMC style)", }, { "emc_gate_7", "gate", "door 7 (EMC style)", }, { "emc_gate_8", "gate", "door 8 (EMC style)", }, { "emc_gate_5_gray", "gate", "gray door (EMC style, key 5)", }, { "emc_gate_6_gray", "gate", "gray door (EMC style, key 6)", }, { "emc_gate_7_gray", "gate", "gray door (EMC style, key 7)", }, { "emc_gate_8_gray", "gate", "gray door (EMC style, key 8)", }, { "emc_key_5", "key", "key 5 (EMC style)", }, { "emc_key_6", "key", "key 6 (EMC style)", }, { "emc_key_7", "key", "key 7 (EMC style)", }, { "emc_key_8", "key", "key 8 (EMC style)", }, { "emc_android", "emc_android", "android", }, { "emc_grass", "emc_grass", "grass", }, { "emc_magic_ball", "emc_magic_ball", "magic ball", }, { "emc_magic_ball.active", "emc_magic_ball", "magic ball (activated)", }, { "emc_magic_ball_switch", "emc_magic_ball_switch", "magic ball switch (off)", }, { "emc_magic_ball_switch.active", "emc_magic_ball_switch", "magic ball switch (on)", }, { "emc_spring_bumper", "emc_spring_bumper", "spring bumper", }, { "emc_plant", "emc_plant", "plant", }, { "emc_lenses", "emc_lenses", "lenses", }, { "emc_magnifier", "emc_magnifier", "magnifier", }, { "emc_wall_9", "wall", "normal wall" }, { "emc_wall_10", "wall", "normal wall" }, { "emc_wall_11", "wall", "normal wall" }, { "emc_wall_12", "wall", "normal wall" }, { "emc_wall_13", "wall", "normal wall" }, { "emc_wall_14", "wall", "normal wall" }, { "emc_wall_15", "wall", "normal wall" }, { "emc_wall_16", "wall", "normal wall" }, { "emc_wall_slippery_1", "wall", "slippery wall" }, { "emc_wall_slippery_2", "wall", "slippery wall" }, { "emc_wall_slippery_3", "wall", "slippery wall" }, { "emc_wall_slippery_4", "wall", "slippery wall" }, { "emc_fake_grass", "fake_grass", "fake grass" }, { "emc_fake_acid", "fake_acid", "fake acid" }, { "emc_dripper", "dripper", "dripper" }, { "trigger_ce_value", "trigger", "CE value of element triggering change" }, { "trigger_ce_score", "trigger", "CE score of element triggering change" }, { "current_ce_value", "current", "CE value of current element" }, { "current_ce_score", "current", "CE score of current element" }, { "yamyam.left", "yamyam", "yam yam (starts moving left)" }, { "yamyam.right", "yamyam", "yam yam (starts moving right)" }, { "yamyam.up", "yamyam", "yam yam (starts moving up)" }, { "yamyam.down", "yamyam", "yam yam (starts moving down)" }, { "bd_expandable_wall", "wall", "growing wall (horizontal, BD style)" }, { "prev_ce_8", "prev_ce", "CE 8 positions earlier in list" }, { "prev_ce_7", "prev_ce", "CE 7 positions earlier in list" }, { "prev_ce_6", "prev_ce", "CE 6 positions earlier in list" }, { "prev_ce_5", "prev_ce", "CE 5 positions earlier in list" }, { "prev_ce_4", "prev_ce", "CE 4 positions earlier in list" }, { "prev_ce_3", "prev_ce", "CE 3 positions earlier in list" }, { "prev_ce_2", "prev_ce", "CE 2 positions earlier in list" }, { "prev_ce_1", "prev_ce", "CE 1 position earlier in list" }, { "self", "self", "the current custom element" }, { "next_ce_1", "next_ce", "CE 1 position later in list" }, { "next_ce_2", "next_ce", "CE 2 positions later in list" }, { "next_ce_3", "next_ce", "CE 3 positions later in list" }, { "next_ce_4", "next_ce", "CE 4 positions later in list" }, { "next_ce_5", "next_ce", "CE 5 positions later in list" }, { "next_ce_6", "next_ce", "CE 6 positions later in list" }, { "next_ce_7", "next_ce", "CE 7 positions later in list" }, { "next_ce_8", "next_ce", "CE 8 positions later in list" }, { "any_element", "any_element", "this element matches any element" }, { "steel_char_space", "steel_char", "steel letter ' '" }, { "steel_char_exclam", "steel_char", "steel letter '!'" }, { "steel_char_quotedbl", "steel_char", "steel letter '\"'" }, { "steel_char_numbersign", "steel_char", "steel letter '#'" }, { "steel_char_dollar", "steel_char", "steel letter '$'" }, { "steel_char_percent", "steel_char", "steel letter '%'" }, { "steel_char_ampersand", "steel_char", "steel letter '&'" }, { "steel_char_apostrophe", "steel_char", "steel letter '''" }, { "steel_char_parenleft", "steel_char", "steel letter '('" }, { "steel_char_parenright", "steel_char", "steel letter ')'" }, { "steel_char_asterisk", "steel_char", "steel letter '*'" }, { "steel_char_plus", "steel_char", "steel letter '+'" }, { "steel_char_comma", "steel_char", "steel letter ','" }, { "steel_char_minus", "steel_char", "steel letter '-'" }, { "steel_char_period", "steel_char", "steel letter '.'" }, { "steel_char_slash", "steel_char", "steel letter '/'" }, { "steel_char_0", "steel_char", "steel letter '0'" }, { "steel_char_1", "steel_char", "steel letter '1'" }, { "steel_char_2", "steel_char", "steel letter '2'" }, { "steel_char_3", "steel_char", "steel letter '3'" }, { "steel_char_4", "steel_char", "steel letter '4'" }, { "steel_char_5", "steel_char", "steel letter '5'" }, { "steel_char_6", "steel_char", "steel letter '6'" }, { "steel_char_7", "steel_char", "steel letter '7'" }, { "steel_char_8", "steel_char", "steel letter '8'" }, { "steel_char_9", "steel_char", "steel letter '9'" }, { "steel_char_colon", "steel_char", "steel letter ':'" }, { "steel_char_semicolon", "steel_char", "steel letter ';'" }, { "steel_char_less", "steel_char", "steel letter '<'" }, { "steel_char_equal", "steel_char", "steel letter '='" }, { "steel_char_greater", "steel_char", "steel letter '>'" }, { "steel_char_question", "steel_char", "steel letter '?'" }, { "steel_char_at", "steel_char", "steel letter '@'" }, { "steel_char_a", "steel_char", "steel letter 'A'" }, { "steel_char_b", "steel_char", "steel letter 'B'" }, { "steel_char_c", "steel_char", "steel letter 'C'" }, { "steel_char_d", "steel_char", "steel letter 'D'" }, { "steel_char_e", "steel_char", "steel letter 'E'" }, { "steel_char_f", "steel_char", "steel letter 'F'" }, { "steel_char_g", "steel_char", "steel letter 'G'" }, { "steel_char_h", "steel_char", "steel letter 'H'" }, { "steel_char_i", "steel_char", "steel letter 'I'" }, { "steel_char_j", "steel_char", "steel letter 'J'" }, { "steel_char_k", "steel_char", "steel letter 'K'" }, { "steel_char_l", "steel_char", "steel letter 'L'" }, { "steel_char_m", "steel_char", "steel letter 'M'" }, { "steel_char_n", "steel_char", "steel letter 'N'" }, { "steel_char_o", "steel_char", "steel letter 'O'" }, { "steel_char_p", "steel_char", "steel letter 'P'" }, { "steel_char_q", "steel_char", "steel letter 'Q'" }, { "steel_char_r", "steel_char", "steel letter 'R'" }, { "steel_char_s", "steel_char", "steel letter 'S'" }, { "steel_char_t", "steel_char", "steel letter 'T'" }, { "steel_char_u", "steel_char", "steel letter 'U'" }, { "steel_char_v", "steel_char", "steel letter 'V'" }, { "steel_char_w", "steel_char", "steel letter 'W'" }, { "steel_char_x", "steel_char", "steel letter 'X'" }, { "steel_char_y", "steel_char", "steel letter 'Y'" }, { "steel_char_z", "steel_char", "steel letter 'Z'" }, { "steel_char_bracketleft", "steel_char", "steel letter '['" }, { "steel_char_backslash", "steel_char", "steel letter '\\'" }, { "steel_char_bracketright", "steel_char", "steel letter ']'" }, { "steel_char_asciicircum", "steel_char", "steel letter '^'" }, { "steel_char_underscore", "steel_char", "steel letter '_'" }, { "steel_char_copyright", "steel_char", "steel letter '©'" }, { "steel_char_aumlaut", "steel_char", "steel letter 'Ä'" }, { "steel_char_oumlaut", "steel_char", "steel letter 'Ö'" }, { "steel_char_uumlaut", "steel_char", "steel letter 'Ü'" }, { "steel_char_degree", "steel_char", "steel letter '°'" }, { "steel_char_trademark", "steel_char", "steel letter '®'" }, { "steel_char_cursor", "steel_char", "steel letter ' '" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter 'button'" }, { "steel_char_unused", "steel_char", "steel letter 'up'" }, { "steel_char_unused", "steel_char", "steel letter 'down'" }, { "sperms", "frankie", "sperms" }, { "bullet", "frankie", "bullet" }, { "heart", "frankie", "heart" }, { "cross", "frankie", "cross" }, { "frankie", "frankie", "frankie" }, { "sign_sperms", "sign", "sign (sperms)" }, { "sign_bullet", "sign", "sign (bullet)" }, { "sign_heart", "sign", "sign (heart)" }, { "sign_cross", "sign", "sign (cross)" }, { "sign_frankie", "sign", "sign (frankie)" }, { "steel_exit_closed", "steel_exit", "closed steel exit" }, { "steel_exit_open", "steel_exit", "open steel exit" }, { "dc_steelwall_1_left", "steelwall", "steel wall (left)" }, { "dc_steelwall_1_right", "steelwall", "steel wall (right)" }, { "dc_steelwall_1_top", "steelwall", "steel wall (top)" }, { "dc_steelwall_1_bottom", "steelwall", "steel wall (bottom)" }, { "dc_steelwall_1_horizontal", "steelwall", "steel wall (top/bottom)" }, { "dc_steelwall_1_vertical", "steelwall", "steel wall (left/right)" }, { "dc_steelwall_1_topleft", "steelwall", "steel wall (top/left)" }, { "dc_steelwall_1_topright", "steelwall", "steel wall (top/right)" }, { "dc_steelwall_1_bottomleft", "steelwall", "steel wall (bottom/left)" }, { "dc_steelwall_1_bottomright", "steelwall", "steel wall (bottom/right)" }, { "dc_steelwall_1_topleft_2", "steelwall", "steel wall (top/left corner)" }, { "dc_steelwall_1_topright_2", "steelwall", "steel wall (top/right corner)" }, { "dc_steelwall_1_bottomleft_2", "steelwall", "steel wall (bottom/left corner)" }, { "dc_steelwall_1_bottomright_2", "steelwall", "steel wall (bottom/right corner)" }, { "dc_steelwall_2_left", "steelwall", "steel wall (left)" }, { "dc_steelwall_2_right", "steelwall", "steel wall (right)" }, { "dc_steelwall_2_top", "steelwall", "steel wall (top)" }, { "dc_steelwall_2_bottom", "steelwall", "steel wall (bottom)" }, { "dc_steelwall_2_horizontal", "steelwall", "steel wall (horizontal)" }, { "dc_steelwall_2_vertical", "steelwall", "steel wall (vertical)" }, { "dc_steelwall_2_middle", "steelwall", "steel wall (middle)" }, { "dc_steelwall_2_single", "steelwall", "steel wall (single)" }, { "dc_switchgate_switch_up", "switchgate_switch", "switch for switch gate (steel)" }, { "dc_switchgate_switch_down", "switchgate_switch", "switch for switch gate (steel)" }, { "dc_timegate_switch", "timegate_switch", "switch for time gate (steel)" }, { "dc_timegate_switch.active", "timegate_switch", "switch for time gate (steel)" }, { "dc_landmine", "dc_landmine", "land mine (DC style, removable)" }, { "expandable_steelwall", "steelwall", "growing steel wall" }, { "expandable_steelwall_horizontal", "steelwall", "growing steel wall (horizontal)" }, { "expandable_steelwall_vertical", "steelwall", "growing steel wall (vertical)" }, { "expandable_steelwall_any", "steelwall", "growing steel wall (any direction)" }, { "em_exit_closed", "em_exit", "closed exit (EM style)" }, { "em_exit_open", "em_exit", "open exit (EM style)" }, { "em_steel_exit_closed", "em_steel_exit", "closed steel exit (EM style)" }, { "em_steel_exit_open", "em_steel_exit", "open steel exit (EM style)" }, { "dc_gate_fake_gray", "gate", "gray door (opened by no key)" }, { "dc_magic_wall", "dc_magic_wall", "magic wall (DC style)" }, { "quicksand_fast_empty", "quicksand", "fast quicksand (empty)" }, { "quicksand_fast_full", "quicksand", "fast quicksand (with rock)" }, { "from_level_template", "from_level_template", "element taken from level template" }, /* ----------------------------------------------------------------------- */ /* "real" (and therefore drawable) runtime elements */ /* ----------------------------------------------------------------------- */ { "dynabomb_player_1.active", "dynabomb", "-" }, { "dynabomb_player_2.active", "dynabomb", "-" }, { "dynabomb_player_3.active", "dynabomb", "-" }, { "dynabomb_player_4.active", "dynabomb", "-" }, { "sp_disk_red.active", "dynamite", "-" }, { "switchgate.opening", "switchgate", "-" }, { "switchgate.closing", "switchgate", "-" }, { "timegate.opening", "timegate", "-" }, { "timegate.closing", "timegate", "-" }, { "pearl.breaking", "pearl", "-" }, { "trap.active", "trap", "-" }, { "invisible_steelwall.active", "steelwall", "-" }, { "invisible_wall.active", "wall", "-" }, { "invisible_sand.active", "sand", "-" }, { "conveyor_belt_1_left.active", "conveyor_belt", "-" }, { "conveyor_belt_1_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_1_right.active", "conveyor_belt", "-" }, { "conveyor_belt_2_left.active", "conveyor_belt", "-" }, { "conveyor_belt_2_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_2_right.active", "conveyor_belt", "-" }, { "conveyor_belt_3_left.active", "conveyor_belt", "-" }, { "conveyor_belt_3_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_3_right.active", "conveyor_belt", "-" }, { "conveyor_belt_4_left.active", "conveyor_belt", "-" }, { "conveyor_belt_4_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_4_right.active", "conveyor_belt", "-" }, { "exit.opening", "exit", "-" }, { "exit.closing", "exit", "-" }, { "steel_exit.opening", "steel_exit", "-" }, { "steel_exit.closing", "steel_exit", "-" }, { "em_exit.opening", "em_exit", "-" }, { "em_exit.closing", "em_exit", "-" }, { "em_steel_exit.opening", "em_steel_exit", "-" }, { "em_steel_exit.closing", "em_steel_exit", "-" }, { "sp_exit.opening", "sp_exit", "-" }, { "sp_exit.closing", "sp_exit", "-" }, { "sp_exit_open", "sp_exit", "-" }, { "sp_terminal.active", "sp_terminal", "-" }, { "sp_buggy_base.activating", "sp_buggy_base", "-" }, { "sp_buggy_base.active", "sp_buggy_base", "-" }, { "sp_murphy_clone", "murphy_clone", "-" }, { "amoeba.dropping", "amoeba", "-" }, { "quicksand.emptying", "quicksand", "-" }, { "quicksand_fast.emptying", "quicksand", "-" }, { "magic_wall.active", "magic_wall", "-" }, { "bd_magic_wall.active", "magic_wall", "-" }, { "dc_magic_wall.active", "magic_wall", "-" }, { "magic_wall_full", "magic_wall", "-" }, { "bd_magic_wall_full", "magic_wall", "-" }, { "dc_magic_wall_full", "magic_wall", "-" }, { "magic_wall.emptying", "magic_wall", "-" }, { "bd_magic_wall.emptying", "magic_wall", "-" }, { "dc_magic_wall.emptying", "magic_wall", "-" }, { "magic_wall_dead", "magic_wall", "-" }, { "bd_magic_wall_dead", "magic_wall", "-" }, { "dc_magic_wall_dead", "magic_wall", "-" }, { "emc_fake_grass.active", "fake_grass", "-" }, { "gate_1_gray.active", "gate", "" }, { "gate_2_gray.active", "gate", "" }, { "gate_3_gray.active", "gate", "" }, { "gate_4_gray.active", "gate", "" }, { "em_gate_1_gray.active", "gate", "" }, { "em_gate_2_gray.active", "gate", "" }, { "em_gate_3_gray.active", "gate", "" }, { "em_gate_4_gray.active", "gate", "" }, { "emc_gate_5_gray.active", "gate", "", }, { "emc_gate_6_gray.active", "gate", "", }, { "emc_gate_7_gray.active", "gate", "", }, { "emc_gate_8_gray.active", "gate", "", }, { "dc_gate_white_gray.active", "gate", "", }, { "emc_dripper.active", "dripper", "dripper" }, { "emc_spring_bumper.active", "emc_spring_bumper", "spring bumper", }, /* ----------------------------------------------------------------------- */ /* "unreal" (and therefore not drawable) runtime elements */ /* ----------------------------------------------------------------------- */ { "blocked", "-", "-" }, { "explosion", "-", "-" }, { "nut.breaking", "-", "-" }, { "diamond.breaking", "-", "-" }, { "acid_splash_left", "-", "-" }, { "acid_splash_right", "-", "-" }, { "amoeba.growing", "-", "-" }, { "amoeba.shrinking", "-", "-" }, { "expandable_wall.growing", "-", "-" }, { "expandable_steelwall.growing", "-", "-" }, { "flames", "-", "-" }, { "player_is_leaving", "-", "-" }, { "player_is_exploding_1", "-", "-" }, { "player_is_exploding_2", "-", "-" }, { "player_is_exploding_3", "-", "-" }, { "player_is_exploding_4", "-", "-" }, { "quicksand.filling", "quicksand", "-" }, { "quicksand_fast.filling", "quicksand", "-" }, { "magic_wall.filling", "-", "-" }, { "bd_magic_wall.filling", "-", "-" }, { "dc_magic_wall.filling", "-", "-" }, { "element.snapping", "-", "-" }, { "diagonal.shrinking", "-", "-" }, { "diagonal.growing", "-", "-" }, /* ----------------------------------------------------------------------- */ /* dummy elements (never used as game elements, only used as graphics) */ /* ----------------------------------------------------------------------- */ { "steelwall_topleft", "-", "-" }, { "steelwall_topright", "-", "-" }, { "steelwall_bottomleft", "-", "-" }, { "steelwall_bottomright", "-", "-" }, { "steelwall_horizontal", "-", "-" }, { "steelwall_vertical", "-", "-" }, { "invisible_steelwall_topleft", "-", "-" }, { "invisible_steelwall_topright", "-", "-" }, { "invisible_steelwall_bottomleft", "-", "-" }, { "invisible_steelwall_bottomright", "-", "-" }, { "invisible_steelwall_horizontal", "-", "-" }, { "invisible_steelwall_vertical", "-", "-" }, { "dynabomb", "-", "-" }, { "dynabomb.active", "-", "-" }, { "dynabomb_player_1", "-", "-" }, { "dynabomb_player_2", "-", "-" }, { "dynabomb_player_3", "-", "-" }, { "dynabomb_player_4", "-", "-" }, { "shield_normal.active", "-", "-" }, { "shield_deadly.active", "-", "-" }, { "amoeba", "amoeba", "-" }, { "[default]", "default", "-" }, { "[bd_default]", "bd_default", "-" }, { "[sp_default]", "sp_default", "-" }, { "[sb_default]", "sb_default", "-" }, { "graphic_1", "graphic", "-" }, { "graphic_2", "graphic", "-" }, { "graphic_3", "graphic", "-" }, { "graphic_4", "graphic", "-" }, { "graphic_5", "graphic", "-" }, { "graphic_6", "graphic", "-" }, { "graphic_7", "graphic", "-" }, { "graphic_8", "graphic", "-" }, { "internal_clipboard_custom", "internal", "empty custom element" }, { "internal_clipboard_change", "internal", "empty change page" }, { "internal_clipboard_group", "internal", "empty group element" }, { "internal_dummy", "internal", "-" }, { "internal_cascade_bd", "internal", "show Boulder Dash elements" }, { "internal_cascade_bd.active", "internal", "hide Boulder Dash elements" }, { "internal_cascade_em", "internal", "show Emerald Mine elements" }, { "internal_cascade_em.active", "internal", "hide Emerald Mine elements" }, { "internal_cascade_emc", "internal", "show Emerald Mine Club elements" }, { "internal_cascade_emc.active", "internal", "hide Emerald Mine Club elements" }, { "internal_cascade_rnd", "internal", "show Rocks'n'Diamonds elements" }, { "internal_cascade_rnd.active", "internal", "hide Rocks'n'Diamonds elements" }, { "internal_cascade_sb", "internal", "show Sokoban elements" }, { "internal_cascade_sb.active", "internal", "hide Sokoban elements" }, { "internal_cascade_sp", "internal", "show Supaplex elements" }, { "internal_cascade_sp.active", "internal", "hide Supaplex elements" }, { "internal_cascade_dc", "internal", "show Diamond Caves II elements" }, { "internal_cascade_dc.active", "internal", "hide Diamond Caves II elements" }, { "internal_cascade_dx", "internal", "show DX Boulderdash elements" }, { "internal_cascade_dx.active", "internal", "hide DX Boulderdash elements" }, { "internal_cascade_chars", "internal", "show text elements" }, { "internal_cascade_chars.active", "internal", "hide text elements" }, { "internal_cascade_steel_chars", "internal", "show steel text elements" }, { "internal_cascade_steel_chars.active", "internal", "hide steel text elements" }, { "internal_cascade_ce", "internal", "show custom elements" }, { "internal_cascade_ce.active", "internal", "hide custom elements" }, { "internal_cascade_ge", "internal", "show group elements" }, { "internal_cascade_ge.active", "internal", "hide group elements" }, { "internal_cascade_ref", "internal", "show reference elements" }, { "internal_cascade_ref.active", "internal", "hide reference elements" }, { "internal_cascade_user", "internal", "show user defined elements" }, { "internal_cascade_user.active", "internal", "hide user defined elements" }, { "internal_cascade_dynamic", "internal", "show elements used in this level" }, { "internal_cascade_dynamic.active", "internal", "hide elements used in this level" }, /* keyword to stop parser: "ELEMENT_INFO_END" <-- do not change! */ { NULL, NULL, NULL } }; /* ------------------------------------------------------------------------- */ /* element action and direction definitions */ /* ------------------------------------------------------------------------- */ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] = { { ".[DEFAULT]", ACTION_DEFAULT, TRUE }, { ".waiting", ACTION_WAITING, TRUE }, { ".falling", ACTION_FALLING, TRUE }, { ".moving", ACTION_MOVING, TRUE }, { ".digging", ACTION_DIGGING, FALSE }, { ".snapping", ACTION_SNAPPING, FALSE }, { ".collecting", ACTION_COLLECTING, FALSE }, { ".dropping", ACTION_DROPPING, FALSE }, { ".pushing", ACTION_PUSHING, FALSE }, { ".walking", ACTION_WALKING, FALSE }, { ".passing", ACTION_PASSING, FALSE }, { ".impact", ACTION_IMPACT, FALSE }, { ".breaking", ACTION_BREAKING, FALSE }, { ".activating", ACTION_ACTIVATING, FALSE }, { ".deactivating", ACTION_DEACTIVATING, FALSE }, { ".opening", ACTION_OPENING, FALSE }, { ".closing", ACTION_CLOSING, FALSE }, { ".attacking", ACTION_ATTACKING, TRUE }, { ".growing", ACTION_GROWING, TRUE }, { ".shrinking", ACTION_SHRINKING, FALSE }, { ".active", ACTION_ACTIVE, TRUE }, { ".filling", ACTION_FILLING, FALSE }, { ".emptying", ACTION_EMPTYING, FALSE }, { ".changing", ACTION_CHANGING, FALSE }, { ".exploding", ACTION_EXPLODING, FALSE }, { ".boring", ACTION_BORING, FALSE }, { ".boring[1]", ACTION_BORING_1, FALSE }, { ".boring[2]", ACTION_BORING_2, FALSE }, { ".boring[3]", ACTION_BORING_3, FALSE }, { ".boring[4]", ACTION_BORING_4, FALSE }, { ".boring[5]", ACTION_BORING_5, FALSE }, { ".boring[6]", ACTION_BORING_6, FALSE }, { ".boring[7]", ACTION_BORING_7, FALSE }, { ".boring[8]", ACTION_BORING_8, FALSE }, { ".boring[9]", ACTION_BORING_9, FALSE }, { ".boring[10]", ACTION_BORING_10, FALSE }, { ".sleeping", ACTION_SLEEPING, FALSE }, { ".sleeping[1]", ACTION_SLEEPING_1, FALSE }, { ".sleeping[2]", ACTION_SLEEPING_2, FALSE }, { ".sleeping[3]", ACTION_SLEEPING_3, FALSE }, { ".awakening", ACTION_AWAKENING, FALSE }, { ".dying", ACTION_DYING, FALSE }, { ".turning", ACTION_TURNING, FALSE }, { ".turning_from_left", ACTION_TURNING_FROM_LEFT, FALSE }, { ".turning_from_right", ACTION_TURNING_FROM_RIGHT, FALSE }, { ".turning_from_up", ACTION_TURNING_FROM_UP, FALSE }, { ".turning_from_down", ACTION_TURNING_FROM_DOWN, FALSE }, { ".smashed_by_rock", ACTION_SMASHED_BY_ROCK, FALSE }, { ".smashed_by_spring", ACTION_SMASHED_BY_SPRING, FALSE }, { ".eating", ACTION_EATING, FALSE }, { ".twinkling", ACTION_TWINKLING, FALSE }, { ".splashing", ACTION_SPLASHING, FALSE }, { ".page[1]", ACTION_PAGE_1, FALSE }, { ".page[2]", ACTION_PAGE_2, FALSE }, { ".page[3]", ACTION_PAGE_3, FALSE }, { ".page[4]", ACTION_PAGE_4, FALSE }, { ".page[5]", ACTION_PAGE_5, FALSE }, { ".page[6]", ACTION_PAGE_6, FALSE }, { ".page[7]", ACTION_PAGE_7, FALSE }, { ".page[8]", ACTION_PAGE_8, FALSE }, { ".page[9]", ACTION_PAGE_9, FALSE }, { ".page[10]", ACTION_PAGE_10, FALSE }, { ".page[11]", ACTION_PAGE_11, FALSE }, { ".page[12]", ACTION_PAGE_12, FALSE }, { ".page[13]", ACTION_PAGE_13, FALSE }, { ".page[14]", ACTION_PAGE_14, FALSE }, { ".page[15]", ACTION_PAGE_15, FALSE }, { ".page[16]", ACTION_PAGE_16, FALSE }, { ".page[17]", ACTION_PAGE_17, FALSE }, { ".page[18]", ACTION_PAGE_18, FALSE }, { ".page[19]", ACTION_PAGE_19, FALSE }, { ".page[20]", ACTION_PAGE_20, FALSE }, { ".page[21]", ACTION_PAGE_21, FALSE }, { ".page[22]", ACTION_PAGE_22, FALSE }, { ".page[23]", ACTION_PAGE_23, FALSE }, { ".page[24]", ACTION_PAGE_24, FALSE }, { ".page[25]", ACTION_PAGE_25, FALSE }, { ".page[26]", ACTION_PAGE_26, FALSE }, { ".page[27]", ACTION_PAGE_27, FALSE }, { ".page[28]", ACTION_PAGE_28, FALSE }, { ".page[29]", ACTION_PAGE_29, FALSE }, { ".page[30]", ACTION_PAGE_30, FALSE }, { ".page[31]", ACTION_PAGE_31, FALSE }, { ".page[32]", ACTION_PAGE_32, FALSE }, { ".other", ACTION_OTHER, FALSE }, /* empty suffix always matches -- check as last entry in InitSoundInfo() */ { "", ACTION_DEFAULT, TRUE }, { NULL, 0, 0 } }; struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS_FULL + 1] = { { ".left", MV_BIT_LEFT }, { ".right", MV_BIT_RIGHT }, { ".up", MV_BIT_UP }, { ".down", MV_BIT_DOWN }, { ".upleft", MV_BIT_UP }, { ".upright", MV_BIT_RIGHT }, { ".downleft", MV_BIT_LEFT }, { ".downright", MV_BIT_DOWN }, { NULL, 0 } }; struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] = { { ".[DEFAULT]", GFX_SPECIAL_ARG_DEFAULT, }, { ".LOADING", GFX_SPECIAL_ARG_LOADING, }, { ".TITLE_INITIAL", GFX_SPECIAL_ARG_TITLE_INITIAL, }, { ".TITLE", GFX_SPECIAL_ARG_TITLE, }, { ".MAIN", GFX_SPECIAL_ARG_MAIN, }, { ".LEVELS", GFX_SPECIAL_ARG_LEVELS }, { ".SCORES", GFX_SPECIAL_ARG_SCORES, }, { ".EDITOR", GFX_SPECIAL_ARG_EDITOR, }, { ".INFO", GFX_SPECIAL_ARG_INFO, }, { ".SETUP", GFX_SPECIAL_ARG_SETUP, }, { ".PLAYING", GFX_SPECIAL_ARG_PLAYING, }, { ".DOOR", GFX_SPECIAL_ARG_DOOR, }, { ".PANEL", GFX_SPECIAL_ARG_PANEL, }, { ".PREVIEW", GFX_SPECIAL_ARG_PREVIEW, }, { ".CRUMBLED", GFX_SPECIAL_ARG_CRUMBLED, }, /* empty suffix always matches -- check as last entry in InitMusicInfo() */ { "", GFX_SPECIAL_ARG_DEFAULT, }, { NULL, 0, } }; #include "conf_var.c" /* include auto-generated data structure definitions */ /* ------------------------------------------------------------------------- */ /* font definitions */ /* ------------------------------------------------------------------------- */ /* Important: When one entry is a prefix of another entry, the longer entry must come first, because the dynamic configuration does prefix matching! (These definitions must match the corresponding definitions in "main.h"!) */ struct FontInfo font_info[NUM_FONTS + 1] = { { "font.initial_1" }, { "font.initial_2" }, { "font.initial_3" }, { "font.initial_4" }, { "font.title_1" }, { "font.title_2" }, { "font.menu_1.active" }, { "font.menu_2.active" }, { "font.menu_1" }, { "font.menu_2" }, { "font.text_1.active" }, { "font.text_2.active" }, { "font.text_3.active" }, { "font.text_4.active" }, { "font.text_1" }, { "font.text_2" }, { "font.text_3" }, { "font.text_4" }, { "font.envelope_1" }, { "font.envelope_2" }, { "font.envelope_3" }, { "font.envelope_4" }, { "font.input_1.active" }, { "font.input_2.active" }, { "font.input_1" }, { "font.input_2" }, { "font.option_off" }, { "font.option_on" }, { "font.value_1" }, { "font.value_2" }, { "font.value_old" }, { "font.level_number.active" }, { "font.level_number" }, { "font.tape_recorder" }, { "font.game_info" }, { "font.info.elements" }, { "font.info.levelset" }, { NULL } }; /* ------------------------------------------------------------------------- */ /* music token prefix definitions */ /* ------------------------------------------------------------------------- */ struct MusicPrefixInfo music_prefix_info[NUM_MUSIC_PREFIXES + 1] = { { "background", TRUE }, { NULL, 0 } }; /* ========================================================================= */ /* main() */ /* ========================================================================= */ static void print_usage() { printf("\n" "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n" "\n" "Options:\n" " -d, --display HOSTNAME[:SCREEN] specify X server display\n" " -b, --basepath DIRECTORY alternative base DIRECTORY\n" " -l, --level DIRECTORY alternative level DIRECTORY\n" " -g, --graphics DIRECTORY alternative graphics DIRECTORY\n" " -s, --sounds DIRECTORY alternative sounds DIRECTORY\n" " -m, --music DIRECTORY alternative music DIRECTORY\n" " -n, --network network multiplayer game\n" " --serveronly only start network server\n" " -v, --verbose verbose mode\n" " --debug display debugging information\n" " --debug-x11-sync enable X11 synchronous mode\n" " -e, --execute COMMAND execute batch COMMAND\n" "\n" "Valid commands for '--execute' option:\n" " \"print graphicsinfo.conf\" print default graphics config\n" " \"print soundsinfo.conf\" print default sounds config\n" " \"print musicinfo.conf\" print default music config\n" " \"print editorsetup.conf\" print default editor config\n" " \"print helpanim.conf\" print default helpanim config\n" " \"print helptext.conf\" print default helptext config\n" " \"dump level FILE\" dump level data from FILE\n" " \"dump tape FILE\" dump tape data from FILE\n" " \"autoplay LEVELDIR [NR ...]\" play level tapes for LEVELDIR\n" " \"convert LEVELDIR [NR]\" convert levels in LEVELDIR\n" " \"create images DIRECTORY\" write BMP images to DIRECTORY\n" "\n", program.command_basename); } int main(int argc, char *argv[]) { char * window_title_string = getWindowTitleString(); InitProgramInfo(argv[0], USERDATA_DIRECTORY, USERDATA_DIRECTORY_UNIX, PROGRAM_TITLE_STRING, window_title_string, ICON_TITLE_STRING, X11_ICON_FILENAME, X11_ICONMASK_FILENAME, SDL_ICON_FILENAME, MSDOS_POINTER_FILENAME, COOKIE_PREFIX, FILENAME_PREFIX, GAME_VERSION_ACTUAL); InitExitFunction(CloseAllAndExit); InitPlatformDependentStuff(); GetOptions(argv, print_usage); OpenAll(); EventLoop(); CloseAllAndExit(0); return 0; /* to keep compilers happy */ } rocksndiamonds-3.3.0.1+dfsg1/src/conf_mus.h0000644000175000017500000000417711375255512017416 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_mus.h * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_MUS_H #define CONF_MUS_H /* values for music configuration */ #define MUS_BACKGROUND 0 #define MUS_BACKGROUND_TITLE_INITIAL 1 #define MUS_BACKGROUND_TITLE 2 #define MUS_BACKGROUND_MAIN 3 #define MUS_BACKGROUND_LEVELS 4 #define MUS_BACKGROUND_SCORES 5 #define MUS_BACKGROUND_EDITOR 6 #define MUS_BACKGROUND_INFO 7 #define MUS_BACKGROUND_SETUP 8 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_1 9 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_2 10 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_3 11 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_4 12 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_5 13 #define MUS_BACKGROUND_TITLESCREEN_1 14 #define MUS_BACKGROUND_TITLESCREEN_2 15 #define MUS_BACKGROUND_TITLESCREEN_3 16 #define MUS_BACKGROUND_TITLESCREEN_4 17 #define MUS_BACKGROUND_TITLESCREEN_5 18 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 19 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_2 20 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_3 21 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_4 22 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_5 23 #define MUS_BACKGROUND_TITLEMESSAGE_1 24 #define MUS_BACKGROUND_TITLEMESSAGE_2 25 #define MUS_BACKGROUND_TITLEMESSAGE_3 26 #define MUS_BACKGROUND_TITLEMESSAGE_4 27 #define MUS_BACKGROUND_TITLEMESSAGE_5 28 #define NUM_MUSIC_FILES 29 #endif /* CONF_MUS_H */ rocksndiamonds-3.3.0.1+dfsg1/src/conf_g2m.c0000644000175000017500000000304511375255512017263 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_g2m.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_G2M_C #define CONF_G2M_C /* values for gamemode/music mapping configuration */ static struct { int gamemode; int music; } gamemode_to_music[] = { { -1, MUS_BACKGROUND }, { GFX_SPECIAL_ARG_TITLE_INITIAL, MUS_BACKGROUND_TITLE_INITIAL }, { GFX_SPECIAL_ARG_TITLE, MUS_BACKGROUND_TITLE }, { GFX_SPECIAL_ARG_MAIN, MUS_BACKGROUND_MAIN }, { GFX_SPECIAL_ARG_LEVELS, MUS_BACKGROUND_LEVELS }, { GFX_SPECIAL_ARG_SCORES, MUS_BACKGROUND_SCORES }, { GFX_SPECIAL_ARG_EDITOR, MUS_BACKGROUND_EDITOR }, { GFX_SPECIAL_ARG_INFO, MUS_BACKGROUND_INFO }, { GFX_SPECIAL_ARG_SETUP, MUS_BACKGROUND_SETUP }, { -1, -1 }, }; #endif /* CONF_G2M_C */ rocksndiamonds-3.3.0.1+dfsg1/src/screens.c0000644000175000017500000047262211403456010017232 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * screens.c * ***********************************************************/ #include "libgame/libgame.h" #include "screens.h" #include "events.h" #include "game.h" #include "tools.h" #include "editor.h" #include "files.h" #include "tape.h" #include "cartoons.h" #include "network.h" #include "init.h" #include "config.h" /* screens on the info screen */ #define INFO_MODE_MAIN 0 #define INFO_MODE_TITLE 1 #define INFO_MODE_ELEMENTS 2 #define INFO_MODE_MUSIC 3 #define INFO_MODE_CREDITS 4 #define INFO_MODE_PROGRAM 5 #define INFO_MODE_VERSION 6 #define INFO_MODE_LEVELSET 7 #define MAX_INFO_MODES 8 /* screens on the setup screen */ #define SETUP_MODE_MAIN 0 #define SETUP_MODE_GAME 1 #define SETUP_MODE_EDITOR 2 #define SETUP_MODE_GRAPHICS 3 #define SETUP_MODE_SOUND 4 #define SETUP_MODE_ARTWORK 5 #define SETUP_MODE_INPUT 6 #define SETUP_MODE_SHORTCUTS 7 #define SETUP_MODE_SHORTCUTS_1 8 #define SETUP_MODE_SHORTCUTS_2 9 #define SETUP_MODE_SHORTCUTS_3 10 #define SETUP_MODE_SHORTCUTS_4 11 #define SETUP_MODE_SHORTCUTS_5 12 /* sub-screens on the setup screen (generic) */ #define SETUP_MODE_CHOOSE_ARTWORK 13 #define SETUP_MODE_CHOOSE_OTHER 14 /* sub-screens on the setup screen (specific) */ #define SETUP_MODE_CHOOSE_GAME_SPEED 15 #define SETUP_MODE_CHOOSE_SCREEN_MODE 16 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17 #define SETUP_MODE_CHOOSE_GRAPHICS 18 #define SETUP_MODE_CHOOSE_SOUNDS 19 #define SETUP_MODE_CHOOSE_MUSIC 20 #define MAX_SETUP_MODES 21 /* for input setup functions */ #define SETUPINPUT_SCREEN_POS_START 0 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4) #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3) #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1) /* for various menu stuff */ #define MENU_SCREEN_START_XPOS 1 #define MENU_SCREEN_START_YPOS 2 #define MENU_SCREEN_VALUE_XPOS 14 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1) #define MENU_TITLE1_YPOS 8 #define MENU_TITLE2_YPOS 46 #define MAX_INFO_ELEMENTS_ON_SCREEN 10 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS) #define MAX_MENU_TEXT_LENGTH_BIG (MENU_SCREEN_VALUE_XPOS - \ MENU_SCREEN_START_XPOS) #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2) /* buttons and scrollbars identifiers */ #define SCREEN_CTRL_ID_PREV_LEVEL 0 #define SCREEN_CTRL_ID_NEXT_LEVEL 1 #define SCREEN_CTRL_ID_PREV_PLAYER 2 #define SCREEN_CTRL_ID_NEXT_PLAYER 3 #define SCREEN_CTRL_ID_SCROLL_UP 4 #define SCREEN_CTRL_ID_SCROLL_DOWN 5 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6 #define NUM_SCREEN_GADGETS 7 #define NUM_SCREEN_MENUBUTTONS 4 #define NUM_SCREEN_SCROLLBUTTONS 2 #define NUM_SCREEN_SCROLLBARS 1 #define SCREEN_MASK_MAIN (1 << 0) #define SCREEN_MASK_INPUT (1 << 1) /* graphic position and size values for buttons and scrollbars */ #define SC_MENUBUTTON_XSIZE TILEX #define SC_MENUBUTTON_YSIZE TILEY #define SC_SCROLLBUTTON_XSIZE TILEX #define SC_SCROLLBUTTON_YSIZE TILEY #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE) #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \ SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \ SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \ SC_SCROLL_VERTICAL_YSIZE) #define SC_BORDER_SIZE 14 /* forward declarations of internal functions */ static void HandleScreenGadgets(struct GadgetInfo *); static void HandleSetupScreen_Generic(int, int, int, int, int); static void HandleSetupScreen_Input(int, int, int, int, int); static void CustomizeKeyboard(int); static void CalibrateJoystick(int); static void execSetupGame(void); static void execSetupGraphics(void); static void execSetupArtwork(void); static void HandleChooseTree(int, int, int, int, int, TreeInfo **); static void DrawChooseLevel(void); static void DrawInfoScreen(void); static void DrawAndFadeInInfoScreen(int); static void DrawSetupScreen(void); static void DrawInfoScreenExt(int, int); static void DrawInfoScreen_NotAvailable(char *, char *); static void DrawInfoScreen_HelpAnim(int, int, boolean); static void DrawInfoScreen_HelpText(int, int, int, int); static void HandleInfoScreen_Main(int, int, int, int, int); static void HandleInfoScreen_TitleScreen(int); static void HandleInfoScreen_Elements(int); static void HandleInfoScreen_Music(int); static void HandleInfoScreen_Credits(int); static void HandleInfoScreen_Program(int); static void HandleInfoScreen_Version(int); static void MapScreenMenuGadgets(int); static void MapScreenTreeGadgets(TreeInfo *); static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS]; static int info_mode = INFO_MODE_MAIN; static int setup_mode = SETUP_MODE_MAIN; static TreeInfo *screen_modes = NULL; static TreeInfo *screen_mode_current = NULL; static TreeInfo *scroll_delays = NULL; static TreeInfo *scroll_delay_current = NULL; static TreeInfo *game_speeds = NULL; static TreeInfo *game_speed_current = NULL; static struct { int value; char *text; } game_speeds_list[] = { #if 1 { 30, "Very Slow" }, { 25, "Slow" }, { 20, "Normal" }, { 15, "Fast" }, { 10, "Very Fast" }, #else { 1000, "1/1s (Extremely Slow)" }, { 500, "1/2s" }, { 200, "1/5s" }, { 100, "1/10s" }, { 50, "1/20s" }, { 29, "1/35s (Original Supaplex)" }, { 25, "1/40s" }, { 20, "1/50s (Normal Speed)" }, { 14, "1/70s (Maximum Supaplex)" }, { 10, "1/100s" }, { 5, "1/200s" }, { 2, "1/500s" }, { 1, "1/1000s (Extremely Fast)" }, #endif { -1, NULL }, }; static struct { int value; char *text; } scroll_delays_list[] = { { 0, "0 Tiles (No Scroll Delay)" }, { 1, "1 Tile" }, { 2, "2 Tiles" }, { 3, "3 Tiles (Default)" }, { 4, "4 Tiles" }, { 5, "5 Tiles" }, { 6, "6 Tiles" }, { 7, "7 Tiles" }, { 8, "8 Tiles (Maximum Scroll Delay)"}, { -1, NULL }, }; #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \ (s) <= GAME_MODE_SETUP ? (s) : \ (s) == GAME_MODE_PSEUDO_TYPENAME ? \ GAME_MODE_MAIN : GAME_MODE_DEFAULT) /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */ #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \ (i) <= INFO_MODE_LEVELSET ? (i) : \ INFO_MODE_MAIN) #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \ (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \ (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \ (i) <= SETUP_MODE_CHOOSE_MUSIC ? \ SETUP_MODE_CHOOSE_ARTWORK : \ SETUP_MODE_CHOOSE_OTHER) #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.draw_xoffset[GAME_MODE_INFO] : \ menu.draw_xoffset_info[DRAW_MODE_INFO(i)]) #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_INFO] : \ menu.draw_yoffset_info[DRAW_MODE_INFO(i)]) #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_xoffset[GAME_MODE_SETUP] : \ menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)]) #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_SETUP] : \ menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)]) #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \ DRAW_XOFFSET_INFO(info_mode) : \ (s) == GAME_MODE_SETUP ? \ DRAW_XOFFSET_SETUP(setup_mode) : \ menu.draw_xoffset[DRAW_MODE(s)]) #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \ DRAW_YOFFSET_INFO(info_mode) : \ (s) == GAME_MODE_SETUP ? \ DRAW_YOFFSET_SETUP(setup_mode) : \ menu.draw_yoffset[DRAW_MODE(s)]) #define mSX (SX + DRAW_XOFFSET(game_status)) #define mSY (SY + DRAW_YOFFSET(game_status)) #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \ menu.list_size[game_status] : \ MAX_MENU_ENTRIES_ON_SCREEN) #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) #define NUM_SCROLLBAR_BITMAPS 2 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS]; #endif /* title display and control definitions */ #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \ 2 * MAX_NUM_TITLE_MESSAGES) static int num_title_screens = 0; struct TitleControlInfo { boolean is_image; boolean initial; int local_nr; int sort_priority; }; struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS]; /* main menu display and control definitions */ #define MAIN_CONTROL_NAME 0 #define MAIN_CONTROL_LEVELS 1 #define MAIN_CONTROL_SCORES 2 #define MAIN_CONTROL_EDITOR 3 #define MAIN_CONTROL_INFO 4 #define MAIN_CONTROL_GAME 5 #define MAIN_CONTROL_SETUP 6 #define MAIN_CONTROL_QUIT 7 #define MAIN_CONTROL_PREV_LEVEL 8 #define MAIN_CONTROL_NEXT_LEVEL 9 #define MAIN_CONTROL_FIRST_LEVEL 10 #define MAIN_CONTROL_LAST_LEVEL 11 #define MAIN_CONTROL_LEVEL_NUMBER 12 #define MAIN_CONTROL_LEVEL_INFO_1 13 #define MAIN_CONTROL_LEVEL_INFO_2 14 #define MAIN_CONTROL_LEVEL_NAME 15 #define MAIN_CONTROL_LEVEL_AUTHOR 16 #define MAIN_CONTROL_LEVEL_YEAR 17 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19 #define MAIN_CONTROL_LEVEL_TESTED_BY 20 #define MAIN_CONTROL_TITLE_1 21 #define MAIN_CONTROL_TITLE_2 22 #define MAIN_CONTROL_TITLE_3 23 static char str_main_text_name[10]; static char str_main_text_first_level[10]; static char str_main_text_last_level[10]; static char str_main_text_level_number[10]; static char *main_text_name = str_main_text_name; static char *main_text_first_level = str_main_text_first_level; static char *main_text_last_level = str_main_text_last_level; static char *main_text_level_number = str_main_text_level_number; static char *main_text_levels = "Levelset"; static char *main_text_scores = "Hall Of Fame"; static char *main_text_editor = "Level Creator"; static char *main_text_info = "Info Screen"; static char *main_text_game = "Start Game"; static char *main_text_setup = "Setup"; static char *main_text_quit = "Quit"; static char *main_text_level_name = level.name; static char *main_text_level_author = level.author; static char *main_text_level_year = NULL; static char *main_text_level_imported_from = NULL; static char *main_text_level_imported_by = NULL; static char *main_text_level_tested_by = NULL; static char *main_text_title_1 = PROGRAM_TITLE_STRING; static char *main_text_title_2 = PROGRAM_COPYRIGHT_STRING; static char *main_text_title_3 = PROGRAM_GAME_BY_STRING; struct MainControlInfo { int nr; struct MenuPosInfo *pos_button; int button_graphic; struct TextPosInfo *pos_text; char **text; struct TextPosInfo *pos_input; char **input; }; static struct MainControlInfo main_controls[] = { { MAIN_CONTROL_NAME, &menu.main.button.name, IMG_MENU_BUTTON_NAME, &menu.main.text.name, &main_text_name, &menu.main.input.name, &setup.player_name, }, { MAIN_CONTROL_LEVELS, &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS, &menu.main.text.levels, &main_text_levels, NULL, NULL, }, { MAIN_CONTROL_SCORES, &menu.main.button.scores, IMG_MENU_BUTTON_SCORES, &menu.main.text.scores, &main_text_scores, NULL, NULL, }, { MAIN_CONTROL_EDITOR, &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR, &menu.main.text.editor, &main_text_editor, NULL, NULL, }, { MAIN_CONTROL_INFO, &menu.main.button.info, IMG_MENU_BUTTON_INFO, &menu.main.text.info, &main_text_info, NULL, NULL, }, { MAIN_CONTROL_GAME, &menu.main.button.game, IMG_MENU_BUTTON_GAME, &menu.main.text.game, &main_text_game, NULL, NULL, }, { MAIN_CONTROL_SETUP, &menu.main.button.setup, IMG_MENU_BUTTON_SETUP, &menu.main.text.setup, &main_text_setup, NULL, NULL, }, { MAIN_CONTROL_QUIT, &menu.main.button.quit, IMG_MENU_BUTTON_QUIT, &menu.main.text.quit, &main_text_quit, NULL, NULL, }, #if 0 /* (these two buttons are real gadgets) */ { MAIN_CONTROL_PREV_LEVEL, &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL, NULL, NULL, NULL, NULL, }, { MAIN_CONTROL_NEXT_LEVEL, &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL, NULL, NULL, NULL, NULL, }, #endif { MAIN_CONTROL_FIRST_LEVEL, NULL, -1, &menu.main.text.first_level, &main_text_first_level, NULL, NULL, }, { MAIN_CONTROL_LAST_LEVEL, NULL, -1, &menu.main.text.last_level, &main_text_last_level, NULL, NULL, }, { MAIN_CONTROL_LEVEL_NUMBER, NULL, -1, &menu.main.text.level_number, &main_text_level_number, NULL, NULL, }, { MAIN_CONTROL_LEVEL_INFO_1, NULL, -1, &menu.main.text.level_info_1, NULL, NULL, NULL, }, { MAIN_CONTROL_LEVEL_INFO_2, NULL, -1, &menu.main.text.level_info_2, NULL, NULL, NULL, }, { MAIN_CONTROL_LEVEL_NAME, NULL, -1, &menu.main.text.level_name, &main_text_level_name, NULL, NULL, }, { MAIN_CONTROL_LEVEL_AUTHOR, NULL, -1, &menu.main.text.level_author, &main_text_level_author, NULL, NULL, }, { MAIN_CONTROL_LEVEL_YEAR, NULL, -1, &menu.main.text.level_year, &main_text_level_year, NULL, NULL, }, { MAIN_CONTROL_LEVEL_IMPORTED_FROM, NULL, -1, &menu.main.text.level_imported_from, &main_text_level_imported_from, NULL, NULL, }, { MAIN_CONTROL_LEVEL_IMPORTED_BY, NULL, -1, &menu.main.text.level_imported_by, &main_text_level_imported_by, NULL, NULL, }, { MAIN_CONTROL_LEVEL_TESTED_BY, NULL, -1, &menu.main.text.level_tested_by, &main_text_level_tested_by, NULL, NULL, }, { MAIN_CONTROL_TITLE_1, NULL, -1, &menu.main.text.title_1, &main_text_title_1, NULL, NULL, }, { MAIN_CONTROL_TITLE_2, NULL, -1, &menu.main.text.title_2, &main_text_title_2, NULL, NULL, }, { MAIN_CONTROL_TITLE_3, NULL, -1, &menu.main.text.title_3, &main_text_title_3, NULL, NULL, }, { -1, NULL, -1, NULL, NULL, NULL, NULL, } }; static int getTitleScreenGraphic(int nr, boolean initial) { return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr; } static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial) { return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]); } #if 0 static int getTitleScreenGameMode(boolean initial) { return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); } #endif static int getTitleMessageGameMode(boolean initial) { return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); } #if 0 static int getTitleScreenBackground(boolean initial) { return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); } #endif #if 0 static int getTitleMessageBackground(int nr, boolean initial) { return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); } #endif static int getTitleBackground(int nr, boolean initial, boolean is_image) { int base = (is_image ? (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 : IMG_BACKGROUND_TITLESCREEN_1) : (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 : IMG_BACKGROUND_TITLEMESSAGE_1)); int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); int graphic_local = base + nr; if (graphic_info[graphic_local].bitmap != NULL) return graphic_local; if (graphic_info[graphic_global].bitmap != NULL) return graphic_global; return IMG_UNDEFINED; } static int getTitleSound(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; int initial = tci->initial; int nr = tci->local_nr; int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); int base = (is_image ? (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 : SND_BACKGROUND_TITLESCREEN_1) : (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 : SND_BACKGROUND_TITLEMESSAGE_1)); int sound_global = menu.sound[mode]; int sound_local = base + nr; #if 0 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n", nr, initial, is_image, sound_global, getSoundListEntry(sound_global)->filename, sound_local, getSoundListEntry(sound_local)->filename); #endif if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME)) return sound_local; if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME)) return sound_global; return SND_UNDEFINED; } static int getTitleMusic(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; int initial = tci->initial; int nr = tci->local_nr; int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); int base = (is_image ? (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 : MUS_BACKGROUND_TITLESCREEN_1) : (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 : MUS_BACKGROUND_TITLEMESSAGE_1)); int music_global = menu.music[mode]; int music_local = base + nr; #if 0 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n", nr, initial, is_image, music_global, getMusicListEntry(music_global)->filename, music_local, getMusicListEntry(music_local)->filename); #endif if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME)) return music_local; if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME)) return music_global; return MUS_UNDEFINED; } static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; int initial = tci->initial; int nr = tci->local_nr; struct TitleFadingInfo ti; if (is_image) { int graphic = getTitleScreenGraphic(nr, initial); /* initialize fading control values to default title config settings */ ti = (initial ? title_initial_default : title_default); /* override default settings with image config settings, if defined */ if (graphic_info[graphic].fade_mode != FADE_MODE_DEFAULT) ti.fade_mode = graphic_info[graphic].fade_mode; if (graphic_info[graphic].fade_delay > -1) ti.fade_delay = graphic_info[graphic].fade_delay; if (graphic_info[graphic].post_delay > -1) ti.post_delay = graphic_info[graphic].post_delay; if (graphic_info[graphic].auto_delay > -1) ti.auto_delay = graphic_info[graphic].auto_delay; } else { if (initial) { ti.fade_mode = titlemessage_initial[nr].fade_mode; ti.fade_delay = titlemessage_initial[nr].fade_delay; ti.post_delay = titlemessage_initial[nr].post_delay; ti.auto_delay = titlemessage_initial[nr].auto_delay; } else { ti.fade_mode = titlemessage[nr].fade_mode; ti.fade_delay = titlemessage[nr].fade_delay; ti.post_delay = titlemessage[nr].post_delay; ti.auto_delay = titlemessage[nr].auto_delay; } } #if 0 if (ti.anim_mode == ANIM_NONE) ti.fade_delay = ti.post_delay = 0; #endif return ti; } static int compareTitleControlInfo(const void *object1, const void *object2) { const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1; const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2; int compare_result; if (tci1->initial != tci2->initial) compare_result = (tci1->initial ? -1 : +1); else if (tci1->sort_priority != tci2->sort_priority) compare_result = tci1->sort_priority - tci2->sort_priority; else if (tci1->is_image != tci2->is_image) compare_result = (tci1->is_image ? -1 : +1); else compare_result = tci1->local_nr - tci2->local_nr; return compare_result; } static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image, boolean initial, int nr, int sort_priority) { title_controls[num_title_screens].is_image = is_image; title_controls[num_title_screens].initial = initial; title_controls[num_title_screens].local_nr = nr; title_controls[num_title_screens].sort_priority = sort_priority; num_title_screens++; } static void InitializeTitleControls_CheckTitleInfo(boolean initial) { int i; for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++) { int graphic = getTitleScreenGraphic(i, initial); Bitmap *bitmap = graphic_info[graphic].bitmap; int sort_priority = graphic_info[graphic].sort_priority; #if 0 /* skip images and messages (fonts!) when using forced custom graphics */ if (setup.override_level_graphics && !initial) continue; #endif if (bitmap != NULL) InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority); } for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++) { struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial); char *filename = getLevelSetTitleMessageFilename(i, initial); int sort_priority = tmi->sort_priority; #if 0 /* skip images and messages (fonts!) when using forced custom graphics */ if (setup.override_level_graphics) continue; #endif if (filename != NULL) InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority); } } static void InitializeTitleControls(boolean show_title_initial) { num_title_screens = 0; #if 1 /* 1st step: initialize title screens for game start (only when starting) */ if (show_title_initial) InitializeTitleControls_CheckTitleInfo(TRUE); #endif /* 2nd step: initialize title screens for current level set */ InitializeTitleControls_CheckTitleInfo(FALSE); /* sort title screens according to sort_priority and title number */ qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo), compareTitleControlInfo); } static boolean visibleMenuPos(struct MenuPosInfo *pos) { return (pos != NULL && pos->x != -1 && pos->y != -1); } static boolean visibleTextPos(struct TextPosInfo *pos) { return (pos != NULL && pos->x != -1 && pos->y != -1); } static void InitializeMainControls() { boolean local_team_mode = (!options.network && setup.team_mode); int i; /* set main control text values to dynamically determined values */ sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:"); strcpy(main_text_first_level, int2str(leveldir_current->first_level, menu.main.text.first_level.size)); strcpy(main_text_last_level, int2str(leveldir_current->last_level, menu.main.text.last_level.size)); strcpy(main_text_level_number, int2str(level_nr, menu.main.text.level_number.size)); main_text_level_year = leveldir_current->year; main_text_level_imported_from = leveldir_current->imported_from; main_text_level_imported_by = leveldir_current->imported_by; main_text_level_tested_by = leveldir_current->tested_by; /* set main control screen positions to dynamically determined values */ for (i = 0; main_controls[i].nr != -1; i++) { struct MainControlInfo *mci = &main_controls[i]; int nr = mci->nr; struct MenuPosInfo *pos_button = mci->pos_button; struct TextPosInfo *pos_text = mci->pos_text; struct TextPosInfo *pos_input = mci->pos_input; char *text = (mci->text ? *mci->text : NULL); char *input = (mci->input ? *mci->input : NULL); int button_graphic = mci->button_graphic; #if 1 int font_text = (pos_text ? pos_text->font : -1); int font_input = (pos_input ? pos_input->font : -1); #else int font_text = mci->font_text; int font_input = mci->font_input; #endif int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0); int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0); int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0); int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0); int text_chars = (text != NULL ? strlen(text) : 0); int input_chars = (input != NULL ? strlen(input) : 0); int button_width = (button_graphic != -1 ? graphic_info[button_graphic].width : 0); int button_height = (button_graphic != -1 ? graphic_info[button_graphic].height : 0); int text_width = font_text_width * text_chars; int text_height = font_text_height; int input_width = font_input_width * input_chars; int input_height = font_input_height; if (nr == MAIN_CONTROL_NAME) { #if 0 if (menu.main.input.name.x == -1) menu.main.input.name.x = menu.main.text.name.x + text_width; if (menu.main.input.name.y == -1) menu.main.input.name.y = menu.main.text.name.y; #endif #if 1 menu.main.input.name.width = input_width; menu.main.input.name.height = input_height; #else menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN; menu.main.input.name.height = font_input_height; #endif } if (pos_button != NULL) /* (x/y may be -1/-1 here) */ { if (pos_button->width == 0) pos_button->width = button_width; if (pos_button->height == 0) pos_button->height = button_height; } if (pos_text != NULL) /* (x/y may be -1/-1 here) */ { /* calculate width for non-clickable text -- needed for text alignment */ boolean calculate_text_width = (pos_button == NULL && text != NULL); if (visibleMenuPos(pos_button)) { if (pos_text->x == -1) pos_text->x = pos_button->x + pos_button->width; if (pos_text->y == -1) pos_text->y = pos_button->y; } if (pos_text->width == -1 || calculate_text_width) pos_text->width = text_width; if (pos_text->height == -1) pos_text->height = text_height; } if (pos_input != NULL) /* (x/y may be -1/-1 here) */ { if (visibleTextPos(pos_text)) { if (pos_input->x == -1) pos_input->x = pos_text->x + pos_text->width; if (pos_input->y == -1) pos_input->y = pos_text->y; } if (pos_input->width == -1) pos_input->width = input_width; if (pos_input->height == -1) pos_input->height = input_height; } } } static void DrawCursorAndText_Main_Ext(int nr, boolean active_text, boolean active_input) { int i; for (i = 0; main_controls[i].nr != -1; i++) { struct MainControlInfo *mci = &main_controls[i]; if (mci->nr == nr || nr == -1) { struct MenuPosInfo *pos_button = mci->pos_button; struct TextPosInfo *pos_text = mci->pos_text; struct TextPosInfo *pos_input = mci->pos_input; char *text = (mci->text ? *mci->text : NULL); char *input = (mci->input ? *mci->input : NULL); int button_graphic = mci->button_graphic; #if 1 int font_text = (pos_text ? pos_text->font : -1); int font_input = (pos_input ? pos_input->font : -1); #else int font_text = mci->font_text; int font_input = mci->font_input; #endif if (active_text) { button_graphic = BUTTON_ACTIVE(button_graphic); font_text = FONT_ACTIVE(font_text); } if (active_input) { font_input = FONT_ACTIVE(font_input); } if (visibleMenuPos(pos_button)) { struct MenuPosInfo *pos = pos_button; int x = mSX + pos->x; int y = mSY + pos->y; DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic); DrawGraphicThruMaskExt(drawto, x, y, button_graphic, 0); } if (visibleTextPos(pos_text) && text != NULL) { struct TextPosInfo *pos = pos_text; int x = mSX + ALIGNED_TEXT_XPOS(pos); int y = mSY + ALIGNED_TEXT_YPOS(pos); #if 1 /* (check why/if this is needed) */ DrawBackgroundForFont(x, y, pos->width, pos->height, font_text); #endif DrawText(x, y, text, font_text); } if (visibleTextPos(pos_input) && input != NULL) { struct TextPosInfo *pos = pos_input; int x = mSX + ALIGNED_TEXT_XPOS(pos); int y = mSY + ALIGNED_TEXT_YPOS(pos); #if 1 /* (check why/if this is needed) */ DrawBackgroundForFont(x, y, pos->width, pos->height, font_input); #endif DrawText(x, y, input, font_input); } } } } static void DrawCursorAndText_Main(int nr, boolean active_text) { DrawCursorAndText_Main_Ext(nr, active_text, FALSE); } #if 0 static void DrawCursorAndText_Main_Input(int nr, boolean active_text) { DrawCursorAndText_Main_Ext(nr, active_text, TRUE); } #endif static struct MainControlInfo *getMainControlInfo(int nr) { int i; for (i = 0; main_controls[i].nr != -1; i++) if (main_controls[i].nr == nr) return &main_controls[i]; return NULL; } static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y) { if (rect == NULL) return FALSE; int rect_x = ALIGNED_TEXT_XPOS(rect); int rect_y = ALIGNED_TEXT_YPOS(rect); return (x >= rect_x && x < rect_x + rect->width && y >= rect_y && y < rect_y + rect->height); } static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y) { if (rect == NULL) return FALSE; int rect_x = ALIGNED_TEXT_XPOS(rect); int rect_y = ALIGNED_TEXT_YPOS(rect); return (x >= rect_x && x < rect_x + rect->width && y >= rect_y && y < rect_y + rect->height); } static void drawCursorExt(int xpos, int ypos, boolean active, int graphic) { #if 1 static int cursor_array[MAX_LEV_FIELDY]; #else static int cursor_array[SCR_FIELDY]; #endif int x = mSX + TILEX * xpos; int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos); if (xpos == 0) { if (graphic != -1) cursor_array[ypos] = graphic; else graphic = cursor_array[ypos]; } if (active) graphic = BUTTON_ACTIVE(graphic); DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic); DrawGraphicThruMaskExt(drawto, x, y, graphic, 0); } static void initCursor(int ypos, int graphic) { drawCursorExt(0, ypos, FALSE, graphic); } static void drawCursor(int ypos, boolean active) { drawCursorExt(0, ypos, active, -1); } static void drawCursorXY(int xpos, int ypos, int graphic) { drawCursorExt(xpos, ypos, FALSE, graphic); } static void drawChooseTreeCursor(int ypos, boolean active) { int last_game_status = game_status; /* save current game status */ #if 0 /* force LEVELS draw offset on artwork setup screen */ game_status = GAME_MODE_LEVELS; #endif drawCursorExt(0, ypos, active, -1); game_status = last_game_status; /* restore current game status */ } void DrawHeadline() { DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING); DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING); } #if 0 static int getPrevlevelButtonPos() { return 10; } static int getCurrentLevelTextPos() { return (getPrevlevelButtonPos() + 1); } static int getNextLevelButtonPos() { return getPrevlevelButtonPos() + 3 + 1; } static int getLevelRangeTextPos() { return getNextLevelButtonPos() + 1; } #endif int effectiveGameStatus() { if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE) return GAME_MODE_TITLE; return game_status; } void DrawTitleScreenImage(int nr, boolean initial) { int graphic = getTitleScreenGraphic(nr, initial); Bitmap *bitmap = graphic_info[graphic].bitmap; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int src_x = graphic_info[graphic].src_x; int src_y = graphic_info[graphic].src_y; int dst_x, dst_y; if (bitmap == NULL) return; if (width > WIN_XSIZE) { /* image width too large for window => center image horizontally */ src_x = (width - WIN_XSIZE) / 2; width = WIN_XSIZE; } if (height > WIN_YSIZE) { /* image height too large for window => center image vertically */ src_y = (height - WIN_YSIZE) / 2; height = WIN_YSIZE; } /* always display title screens centered */ dst_x = (WIN_XSIZE - width) / 2; dst_y = (WIN_YSIZE - height) / 2; SetDrawBackgroundMask(REDRAW_ALL); SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE)); ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); if (DrawingOnBackground(dst_x, dst_y)) { SetClipOrigin(bitmap, bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); redraw_mask = REDRAW_ALL; } void DrawTitleScreenMessage(int nr, boolean initial) { char *filename = getLevelSetTitleMessageFilename(nr, initial); struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial); int last_game_status = game_status; /* save current game status */ if (filename == NULL) return; /* force TITLE font on title message screen */ game_status = getTitleMessageGameMode(initial); /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) tmi->chars = tmi->width / getFontWidth(tmi->font); else tmi->width = tmi->chars * getFontWidth(tmi->font); /* if lines set to "-1", automatically determine by text and font height */ if (tmi->lines == -1) tmi->lines = tmi->height / getFontHeight(tmi->font); else tmi->height = tmi->lines * getFontHeight(tmi->font); SetDrawBackgroundMask(REDRAW_ALL); SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE)); ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi), filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1, tmi->autowrap, tmi->centered, tmi->parse_comments); game_status = last_game_status; /* restore current game status */ } void DrawTitleScreen() { KeyboardAutoRepeatOff(); #if 0 SetMainBackgroundImage(IMG_BACKGROUND_TITLE); #endif HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE); StopAnimation(); } boolean CheckTitleScreen(boolean levelset_has_changed) { static boolean show_title_initial = TRUE; boolean show_titlescreen = FALSE; /* needed to be able to skip title screen, if no image or message defined */ InitializeTitleControls(show_title_initial); if (setup.show_titlescreen && (show_title_initial || levelset_has_changed)) show_titlescreen = TRUE; /* show initial title images and messages only once at program start */ show_title_initial = FALSE; return (show_titlescreen && num_title_screens > 0); } void DrawMainMenuExt(int fade_mask, boolean do_fading) { static LevelDirTree *leveldir_last_valid = NULL; boolean levelset_has_changed = FALSE; FadeSetLeaveScreen(); /* do not fade out here -- function may continue and fade on editor screen */ UnmapAllGadgets(); FadeSoundsAndMusic(); KeyboardAutoRepeatOn(); ActivateJoystick(); SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); audio.sound_deactivated = FALSE; GetPlayerConfig(); /* needed if last screen was the playing screen, invoked from level editor */ if (level_editor_test_game) { game_status = GAME_MODE_EDITOR; DrawLevelEd(); return; } /* needed if last screen was the setup screen and fullscreen state changed */ ToggleFullscreenIfNeeded(); /* leveldir_current may be invalid (level group, parent link) */ if (!validLevelSeries(leveldir_current)) leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid); if (leveldir_current != leveldir_last_valid) levelset_has_changed = TRUE; /* store valid level series information */ leveldir_last_valid = leveldir_current; init_last = init; /* switch to new busy animation */ /* needed if last screen (level choice) changed graphics, sounds or music */ ReloadCustomArtwork(0); if (redraw_mask & REDRAW_ALL) fade_mask = REDRAW_ALL; #if 1 FadeOut(fade_mask); /* needed if last screen was the editor screen */ UndrawSpecialEditorDoor(); #if 0 if (fade_mask == REDRAW_FIELD) BackToFront(); #endif #endif #if 1 /* needed if different viewport properties defined for menues */ ChangeViewportPropertiesIfNeeded(); #endif #if defined(TARGET_SDL) SetDrawtoField(DRAW_BACKBUFFER); #endif if (CheckTitleScreen(levelset_has_changed)) { game_status = GAME_MODE_TITLE; DrawTitleScreen(); return; } /* level_nr may have been set to value over handicap with level editor */ if (setup.handicap && level_nr > leveldir_current->handicap_level) level_nr = leveldir_current->handicap_level; LoadLevel(level_nr); LoadScore(level_nr); SetMainBackgroundImage(IMG_BACKGROUND_MAIN); #if 1 if (fade_mask == REDRAW_ALL) { // int door_state = GetDoorState(); RedrawBackground(); // OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); } #endif ClearField(); InitializeMainControls(); DrawCursorAndText_Main(-1, FALSE); DrawPreviewLevel(TRUE); HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE); TapeStop(); if (TAPE_IS_EMPTY(tape)) LoadTape(level_nr); DrawCompleteVideoDisplay(); PlayMenuSound(); PlayMenuMusic(); /* create gadgets for main menu screen */ FreeScreenGadgets(); CreateScreenGadgets(); /* map gadgets for main menu screen */ MapTapeButtons(); MapScreenMenuGadgets(SCREEN_MASK_MAIN); #if 1 if (fade_mask == REDRAW_ALL) { int door_state = GetDoorState(); // RedrawBackground(); OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); } #endif DrawMaskedBorder(REDRAW_ALL); FadeIn(fade_mask); FadeSetEnterMenu(); #if 1 /* update screen area with special editor door */ redraw_mask |= REDRAW_ALL; BackToFront(); #endif SetMouseCursor(CURSOR_DEFAULT); InitAnimation(); OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2); } void DrawAndFadeInMainMenu(int fade_mask) { DrawMainMenuExt(fade_mask, TRUE); } void DrawMainMenu() { DrawMainMenuExt(REDRAW_ALL, FALSE); } #if defined(CREATE_SPECIAL_EDITION_RND_JUE) static void gotoTopLevelDir() { /* move upwards to top level directory */ while (leveldir_current->node_parent) { /* write a "path" into level tree for easy navigation to last level */ if (leveldir_current->node_parent->node_group->cl_first == -1) { int num_leveldirs = numTreeInfoInGroup(leveldir_current); int leveldir_pos = posTreeInfo(leveldir_current); int num_page_entries; int cl_first, cl_cursor; if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN) num_page_entries = num_leveldirs; else num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; cl_first = MAX(0, leveldir_pos - num_page_entries + 1); cl_cursor = leveldir_pos - cl_first; leveldir_current->node_parent->node_group->cl_first = cl_first; leveldir_current->node_parent->node_group->cl_cursor = cl_cursor; } leveldir_current = leveldir_current->node_parent; } } #endif void HandleTitleScreen(int mx, int my, int dx, int dy, int button) { static unsigned long title_delay = 0; static int title_screen_nr = 0; static int last_sound = -1, last_music = -1; boolean return_to_main_menu = FALSE; boolean use_fading_main_menu = TRUE; struct TitleControlInfo *tci; struct TitleFadingInfo fading_default; struct TitleFadingInfo fading_last = fading; struct TitleFadingInfo fading_next; int sound, music; if (button == MB_MENU_INITIALIZE) { title_delay = 0; title_screen_nr = 0; tci = &title_controls[title_screen_nr]; last_sound = SND_UNDEFINED; last_music = MUS_UNDEFINED; if (game_status == GAME_MODE_INFO) { if (num_title_screens == 0) { DrawInfoScreen_NotAvailable("Title screen information:", "No title screen for this level set."); return; } FadeSoundsAndMusic(); #if 1 FadeOut(REDRAW_ALL); #endif } if (tci->is_image) DrawTitleScreenImage(tci->local_nr, tci->initial); else DrawTitleScreenMessage(tci->local_nr, tci->initial); fading_default = (tci->initial ? title_initial_default : title_default); fading = fading_next = getTitleFading(tci); #if 1 #if 1 if (!(fading_last.fade_mode & FADE_TYPE_TRANSFORM) && fading_next.fade_mode & FADE_TYPE_TRANSFORM) { fading.fade_mode = FADE_MODE_FADE; fading.fade_delay = fading_default.fade_delay; } #else if (fading_last.fade_mode != FADE_MODE_CROSSFADE && fading_next.fade_mode == FADE_MODE_CROSSFADE) fading.fade_mode = FADE_MODE_FADE; #endif #endif #if 1 sound = getTitleSound(tci); music = getTitleMusic(tci); if (sound != last_sound) PlayMenuSoundExt(sound); if (music != last_music) PlayMenuMusicExt(music); last_sound = sound; last_music = music; #endif SetMouseCursor(CURSOR_NONE); #if 1 FadeIn(REDRAW_ALL); #endif fading = fading_next; DelayReached(&title_delay, 0); /* reset delay counter */ return; } #if 1 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay)) button = MB_MENU_CHOICE; #else if (fading.auto_delay > -1 && DelayReached(&title_delay, fading.auto_delay)) button = MB_MENU_CHOICE; #endif if (button == MB_MENU_LEAVE) { return_to_main_menu = TRUE; use_fading_main_menu = FALSE; } else if (button == MB_MENU_CHOICE) { if (game_status == GAME_MODE_INFO && num_title_screens == 0) { #if 0 FadeOut(REDRAW_FIELD); #endif FadeSetEnterScreen(); info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); return; } title_screen_nr++; tci = &title_controls[title_screen_nr]; if (title_screen_nr < num_title_screens) { sound = getTitleSound(tci); music = getTitleMusic(tci); if (sound == SND_UNDEFINED || sound != last_sound) FadeSounds(); if (music == MUS_UNDEFINED || music != last_music) FadeMusic(); #if 1 FadeOut(REDRAW_ALL); #endif if (tci->is_image) DrawTitleScreenImage(tci->local_nr, tci->initial); else DrawTitleScreenMessage(tci->local_nr, tci->initial); fading_next = getTitleFading(tci); #if 1 sound = getTitleSound(tci); music = getTitleMusic(tci); if (sound != last_sound) PlayMenuSoundExt(sound); if (music != last_music) PlayMenuMusicExt(music); last_sound = sound; last_music = music; #endif #if 1 /* last screen already faded out, next screen has no animation */ if (!(fading.fade_mode & FADE_TYPE_TRANSFORM) && fading_next.fade_mode == FADE_MODE_NONE) fading = fading_next; #else /* last screen already faded out, next screen has no animation */ if (fading.fade_mode != FADE_MODE_CROSSFADE && fading_next.fade_mode == FADE_MODE_NONE) fading = fading_next; #endif #if 1 FadeIn(REDRAW_ALL); #endif fading = fading_next; DelayReached(&title_delay, 0); /* reset delay counter */ } else { FadeSoundsAndMusic(); return_to_main_menu = TRUE; } } if (return_to_main_menu) { #if 0 RedrawBackground(); #endif SetMouseCursor(CURSOR_DEFAULT); if (game_status == GAME_MODE_INFO) { #if 0 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); #endif info_mode = INFO_MODE_MAIN; DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu); } else /* default: return to main menu */ { #if 0 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); #endif game_status = GAME_MODE_MAIN; DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu); } } } void HandleMainMenu_SelectLevel(int step, int direction) { int old_level_nr = level_nr; int new_level_nr; new_level_nr = old_level_nr + step * direction; if (new_level_nr < leveldir_current->first_level) new_level_nr = leveldir_current->first_level; if (new_level_nr > leveldir_current->last_level) new_level_nr = leveldir_current->last_level; if (setup.handicap && new_level_nr > leveldir_current->handicap_level) { /* skipping levels is only allowed when trying to skip single level */ if (setup.skip_levels && step == 1 && Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK)) { leveldir_current->handicap_level++; SaveLevelSetup_SeriesInfo(); } new_level_nr = leveldir_current->handicap_level; } if (new_level_nr != old_level_nr) { struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER); PlaySound(SND_MENU_ITEM_SELECTING); level_nr = new_level_nr; DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y, int2str(level_nr, menu.main.text.level_number.size), mci->pos_text->font); LoadLevel(level_nr); DrawPreviewLevel(TRUE); TapeErase(); LoadTape(level_nr); DrawCompleteVideoDisplay(); /* needed because DrawPreviewLevel() takes some time */ BackToFront(); SyncDisplay(); } } void HandleMainMenu(int mx, int my, int dx, int dy, int button) { static int choice = MAIN_CONTROL_GAME; int pos = choice; int i; if (button == MB_MENU_INITIALIZE) { DrawCursorAndText_Main(choice, TRUE); return; } if (mx || my) /* mouse input */ { pos = -1; for (i = 0; main_controls[i].nr != -1; i++) { if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) || insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) || insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY)) { pos = main_controls[i].nr; break; } } } else if (dx || dy) /* keyboard input */ { if (dx > 0 && (choice == MAIN_CONTROL_INFO || choice == MAIN_CONTROL_SETUP)) button = MB_MENU_CHOICE; else if (dy) pos = choice + dy; } if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button) { HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1); } else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT) { if (button) { if (pos != choice) { PlaySound(SND_MENU_ITEM_ACTIVATING); DrawCursorAndText_Main(choice, FALSE); DrawCursorAndText_Main(pos, TRUE); choice = pos; } } else { PlaySound(SND_MENU_ITEM_SELECTING); if (pos == MAIN_CONTROL_NAME) { game_status = GAME_MODE_PSEUDO_TYPENAME; HandleTypeName(strlen(setup.player_name), 0); } else if (pos == MAIN_CONTROL_LEVELS) { if (leveldir_first) { game_status = GAME_MODE_LEVELS; SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); #if defined(CREATE_SPECIAL_EDITION_RND_JUE) gotoTopLevelDir(); #endif DrawChooseLevel(); } } else if (pos == MAIN_CONTROL_SCORES) { game_status = GAME_MODE_SCORES; DrawHallOfFame(-1); } else if (pos == MAIN_CONTROL_EDITOR) { if (leveldir_current->readonly && !strEqual(setup.player_name, "Artsoft")) Request("This level is read only !", REQ_CONFIRM); game_status = GAME_MODE_EDITOR; FadeSetEnterScreen(); #if 0 /* needed if different viewport properties defined for editor */ ChangeViewportPropertiesIfNeeded(); #endif DrawLevelEd(); } else if (pos == MAIN_CONTROL_INFO) { game_status = GAME_MODE_INFO; info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else if (pos == MAIN_CONTROL_GAME) { StartGameActions(options.network, setup.autorecord, level.random_seed); } else if (pos == MAIN_CONTROL_SETUP) { game_status = GAME_MODE_SETUP; setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } else if (pos == MAIN_CONTROL_QUIT) { SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED)) game_status = GAME_MODE_QUIT; } } } if (game_status == GAME_MODE_MAIN) { DrawPreviewLevel(FALSE); DoAnimation(); } } /* ========================================================================= */ /* info screen functions */ /* ========================================================================= */ static struct TokenInfo *info_info; static int num_info_info; static void execInfoTitleScreen() { info_mode = INFO_MODE_TITLE; DrawInfoScreen(); } static void execInfoElements() { info_mode = INFO_MODE_ELEMENTS; DrawInfoScreen(); } static void execInfoMusic() { info_mode = INFO_MODE_MUSIC; DrawInfoScreen(); } static void execInfoCredits() { info_mode = INFO_MODE_CREDITS; DrawInfoScreen(); } static void execInfoProgram() { info_mode = INFO_MODE_PROGRAM; DrawInfoScreen(); } static void execInfoVersion() { info_mode = INFO_MODE_VERSION; DrawInfoScreen(); } static void execInfoLevelSet() { info_mode = INFO_MODE_LEVELSET; DrawInfoScreen(); } static void execExitInfo() { game_status = GAME_MODE_MAIN; DrawMainMenuExt(REDRAW_FIELD, FALSE); } static struct TokenInfo info_info_main[] = { { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" }, { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" }, { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" }, { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" }, { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" }, { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" }, { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execExitInfo, "Exit" }, { 0, NULL, NULL } }; static void DrawCursorAndText_Info(int pos, boolean active) { int xpos = MENU_SCREEN_START_XPOS; int ypos = MENU_SCREEN_START_YPOS + pos; int font_nr = FONT_MENU_1; if (active) font_nr = FONT_ACTIVE(font_nr); DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr); if (info_info[pos].type & ~TYPE_SKIP_ENTRY) drawCursor(pos, active); } static void DrawInfoScreen_Main(int fade_mask, boolean do_fading) { int i; UnmapAllGadgets(); CloseDoor(DOOR_CLOSE_2); /* (needed after displaying title screens which disable auto repeat) */ KeyboardAutoRepeatOn(); FadeSetLeaveScreen(); #if 1 FadeOut(fade_mask); #endif #if 1 if (fade_mask == REDRAW_ALL) { RedrawBackground(); OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); } #endif ClearField(); DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen"); info_info = info_info_main; num_info_info = 0; #if 1 for (i = 0; info_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) #else for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) #endif { if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (info_info[i].type & ~TYPE_SKIP_ENTRY) initCursor(i, IMG_MENU_BUTTON); DrawCursorAndText_Info(i, FALSE); num_info_info++; } HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE); PlayMenuSound(); PlayMenuMusic(); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); InitAnimation(); } void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) { static int choice_store[MAX_INFO_MODES]; int choice = choice_store[info_mode]; /* always starts with 0 */ int x = 0; int y = choice; if (button == MB_MENU_INITIALIZE) { /* advance to first valid menu entry */ while (choice < num_info_info && info_info[choice].type & TYPE_SKIP_ENTRY) choice++; choice_store[info_mode] = choice; DrawCursorAndText_Info(choice, TRUE); return; } else if (button == MB_MENU_LEAVE) { for (y = 0; y < num_info_info; y++) { if (info_info[y].type & TYPE_LEAVE_MENU) { void (*menu_callback_function)(void) = info_info[y].value; FadeSetLeaveMenu(); menu_callback_function(); break; /* absolutely needed because function changes 'info_info'! */ } } return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard input */ { if (dx) { int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER); if (info_info[choice].type & menu_navigation_type || info_info[choice].type & TYPE_ENTER_SCREEN || info_info[choice].type & TYPE_BOOLEAN_STYLE || info_info[choice].type & TYPE_YES_NO_AUTO) button = MB_MENU_CHOICE; } else if (dy) y = choice + dy; /* jump to next non-empty menu entry (up or down) */ while (y > 0 && y < num_info_info - 1 && info_info[y].type & TYPE_SKIP_ENTRY) y += dy; } if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY) { if (button) { if (y != choice) { PlaySound(SND_MENU_ITEM_ACTIVATING); DrawCursorAndText_Info(choice, FALSE); DrawCursorAndText_Info(y, TRUE); choice = choice_store[info_mode] = y; } } else if (!(info_info[y].type & TYPE_GHOSTED)) { PlaySound(SND_MENU_ITEM_SELECTING); if (info_info[y].type & TYPE_ENTER_OR_LEAVE) { void (*menu_callback_function)(void) = info_info[choice].value; FadeSetFromType(info_info[y].type); menu_callback_function(); } } } } void DrawInfoScreen_NotAvailable(char *text_title, char *text_error) { int ystart1 = mSY - SY + 100; int ystart2 = mSY - SY + 150; int ybottom = mSY - SY + SYSIZE - 20; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, text_title); DrawTextSCentered(ystart2, FONT_TEXT_2, text_error); DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); } void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init) { static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN]; static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN]; int xstart = mSX + 16; int ystart1 = mSY - SY + 100; int ystart2 = mSY + 64 + 2 * 32; int ybottom = mSY - SY + SYSIZE - 20; int ystep = TILEY + 4; int element, action, direction; int graphic; int delay; int sync_frame; int i, j; if (init) { for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++) infoscreen_step[i] = infoscreen_frame[i] = 0; ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Elements:"); DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for next page"); FrameCounter = 0; } i = j = 0; while (helpanim_info[j].element != HELPANIM_LIST_END) { if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN || i >= max_anims) break; else if (i < start) { while (helpanim_info[j].element != HELPANIM_LIST_NEXT) j++; j++; i++; continue; } j += infoscreen_step[i - start]; element = helpanim_info[j].element; action = helpanim_info[j].action; direction = helpanim_info[j].direction; if (element < 0) element = EL_UNKNOWN; if (action != -1 && direction != -1) graphic = el_act_dir2img(element, action, direction); else if (action != -1) graphic = el_act2img(element, action); else if (direction != -1) graphic = el_dir2img(element, direction); else graphic = el2img(element); delay = helpanim_info[j++].delay; if (delay == -1) delay = 1000000; if (infoscreen_frame[i - start] == 0) { sync_frame = 0; infoscreen_frame[i - start] = delay - 1; } else { sync_frame = delay - infoscreen_frame[i - start]; infoscreen_frame[i - start]--; } if (helpanim_info[j].element == HELPANIM_LIST_NEXT) { if (!infoscreen_frame[i - start]) infoscreen_step[i - start] = 0; } else { if (!infoscreen_frame[i - start]) infoscreen_step[i - start]++; while (helpanim_info[j].element != HELPANIM_LIST_NEXT) j++; } j++; ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep, TILEX, TILEY); DrawGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep, graphic, sync_frame, USE_MASKING); if (init) DrawInfoScreen_HelpText(element, action, direction, i - start); i++; } redraw_mask |= REDRAW_FIELD; FrameCounter++; } static char *getHelpText(int element, int action, int direction) { char token[MAX_LINE_LEN]; strcpy(token, element_info[element].token_name); if (action != -1) strcat(token, element_action_info[action].suffix); if (direction != -1) strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix); return getHashEntry(helptext_info, token); } void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos) { int font_nr = FONT_INFO_ELEMENTS; int font_width = getFontWidth(font_nr); int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX; int sy = mSY + 65 + 2 * 32 + 1; int ystep = TILEY + 4; int pad_x = sx - SX; int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width; int max_lines_per_text = 2; char *text = NULL; if (action != -1 && direction != -1) /* element.action.direction */ text = getHelpText(element, action, direction); if (text == NULL && action != -1) /* element.action */ text = getHelpText(element, action, -1); if (text == NULL && direction != -1) /* element.direction */ text = getHelpText(element, -1, direction); if (text == NULL) /* base element */ text = getHelpText(element, -1, -1); if (text == NULL) /* not found */ text = "No description available"; if (strlen(text) <= max_chars_per_line) /* only one line of text */ sy += getFontHeight(font_nr) / 2; DrawTextBuffer(sx, sy + ypos * ystep, text, font_nr, max_chars_per_line, -1, max_lines_per_text, 0, -1, TRUE, FALSE, FALSE); } void DrawInfoScreen_TitleScreen() { DrawTitleScreen(); } void HandleInfoScreen_TitleScreen(int button) { HandleTitleScreen(0, 0, 0, 0, button); } void DrawInfoScreen_Elements() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS); FadeOut(REDRAW_FIELD); LoadHelpAnimInfo(); LoadHelpTextInfo(); HandleInfoScreen_Elements(MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); InitAnimation(); } void HandleInfoScreen_Elements(int button) { static unsigned long info_delay = 0; static int num_anims; static int num_pages; static int page; int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN; int i; if (button == MB_MENU_INITIALIZE) { boolean new_element = TRUE; num_anims = 0; for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++) { if (helpanim_info[i].element == HELPANIM_LIST_NEXT) new_element = TRUE; else if (new_element) { num_anims++; new_element = FALSE; } } num_pages = (num_anims + anims_per_page - 1) / anims_per_page; page = 0; } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); page++; } if (page >= num_pages) { FadeSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); return; } #if 1 if (page > 0) FadeSetNextScreen(); #endif if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } else { if (DelayReached(&info_delay, GameFrameDelay)) if (page < num_pages) DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE); PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Music() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC); #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); DrawHeadline(); LoadMusicInfo(); HandleInfoScreen_Music(MB_MENU_INITIALIZE); #if 1 FadeIn(REDRAW_FIELD); #endif } void HandleInfoScreen_Music(int button) { static struct MusicFileInfo *list = NULL; int ystart1 = mSY - SY + 100; int ystart2 = mSY - SY + 150; int ybottom = mSY - SY + SYSIZE - 20; int dy = 30; if (button == MB_MENU_INITIALIZE) { list = music_file_info; if (list == NULL) { FadeSoundsAndMusic(); ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, "No music info for this level set."); DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for info menu"); return; } } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { int y = 0; if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); if (list != NULL) list = list->next; } if (list == NULL) { FadeSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); return; } FadeSoundsAndMusic(); #if 1 if (list != music_file_info) FadeSetNextScreen(); #endif if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); if (list->is_sound) { int sound = list->music; if (sound_info[sound].loop) PlaySoundLoop(sound); else PlaySound(sound); DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Sounds:"); } else { PlayMusic(list->music); DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Music:"); } if (!strEqual(list->title, UNKNOWN_NAME)) { if (!strEqual(list->title_header, UNKNOWN_NAME)) DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->title_header); DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title); } if (!strEqual(list->artist, UNKNOWN_NAME)) { if (!strEqual(list->artist_header, UNKNOWN_NAME)) DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->artist_header); else DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "by"); DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->artist); } if (!strEqual(list->album, UNKNOWN_NAME)) { if (!strEqual(list->album_header, UNKNOWN_NAME)) DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->album_header); else DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the album"); DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album); } if (!strEqual(list->year, UNKNOWN_NAME)) { if (!strEqual(list->year_header, UNKNOWN_NAME)) DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->year_header); else DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the year"); DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->year); } DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for next page"); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } if (list != NULL && list->is_sound && sound_info[list->music].loop) PlaySoundLoop(list->music); } static void DrawInfoScreen_CreditsScreen(int screen_nr) { int ystart1 = mSY - SY + 100; int ystart2 = mSY - SY + 150; int ybottom = mSY - SY + SYSIZE - 20; int ystep = 30; ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, "Credits:"); if (screen_nr == 0) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Special thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Peter Liepa"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for creating"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "\"Boulder Dash\""); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "in the year"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, "1984"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, "published by"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, "First Star Software"); } else if (screen_nr == 1) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Special thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Klaus Heinz & Volker Wertich"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for creating"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "\"Emerald Mine\""); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "in the year"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, "1987"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, "published by"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, "Kingsoft"); } else if (screen_nr == 2) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Special thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Michael Stopp & Philip Jespersen"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for creating"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "\"Supaplex\""); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "in the year"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, "1991"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, "published by"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, "Digital Integration"); } else if (screen_nr == 3) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Special thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Hiroyuki Imabayashi"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for creating"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "\"Sokoban\""); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "in the year"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, "1982"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, "published by"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, "Thinking Rabbit"); } else if (screen_nr == 4) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Special thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Alan Bond"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "and"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "Jürgen Bonhagen"); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "for the continuous creation"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2, "of outstanding level sets"); } else if (screen_nr == 5) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Peter Elzner"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for ideas and inspiration by"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "Diamond Caves"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2, "Thanks to"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_3, "Steffest"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2, "for ideas and inspiration by"); DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3, "DX-Boulderdash"); } else if (screen_nr == 6) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "David Tritscher"); #if 1 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for the code base used for the"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2, "native Emerald Mine engine"); #else DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for the new Emerald Mine engine"); #endif } else if (screen_nr == 7) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "Thanks to"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, "Guido Schulz"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, "for the initial DOS port"); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, "Thanks to"); DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, "Karl Hörnell"); DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, "for some additional toons"); } else if (screen_nr == 8) { DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "And not to forget:"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2, "Many thanks to"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3, "All those who contributed"); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, "levels to this game"); DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_3, "since 1995"); } DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for next page"); } void DrawInfoScreen_Credits() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS); FadeSoundsAndMusic(); #if 1 FadeOut(REDRAW_FIELD); #endif HandleInfoScreen_Credits(MB_MENU_INITIALIZE); #if 1 FadeIn(REDRAW_FIELD); #endif } void HandleInfoScreen_Credits(int button) { static int screen_nr = 0; int num_screens = 9; if (button == MB_MENU_INITIALIZE) { screen_nr = 0; // DrawInfoScreen_CreditsScreen(screen_nr); } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); screen_nr++; } if (screen_nr >= num_screens) { FadeSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); return; } #if 1 if (screen_nr > 0) FadeSetNextScreen(); #endif if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); DrawInfoScreen_CreditsScreen(screen_nr); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Program() { int ystart1 = mSY - SY + 100; int ystart2 = mSY - SY + 150; int ybottom = mSY - SY + SYSIZE - 20; int ystep = 30; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM); #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, "Program Information:"); DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, "This game is Freeware!"); DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2, "If you like it, send e-mail to:"); DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3, PROGRAM_EMAIL_STRING); DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2, "or SnailMail to:"); DrawTextSCentered(ystart2 + 4 * ystep + 0, FONT_TEXT_3, "Holger Schemel"); DrawTextSCentered(ystart2 + 4 * ystep + 20, FONT_TEXT_3, "Detmolder Strasse 189"); DrawTextSCentered(ystart2 + 4 * ystep + 40, FONT_TEXT_3, "33604 Bielefeld"); DrawTextSCentered(ystart2 + 4 * ystep + 60, FONT_TEXT_3, "Germany"); DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2, "More information and levels:"); DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3, PROGRAM_WEBSITE_STRING); DrawTextSCentered(ystart2 + 9 * ystep, FONT_TEXT_2, "If you have created new levels,"); DrawTextSCentered(ystart2 + 10 * ystep, FONT_TEXT_2, "send them to me to include them!"); DrawTextSCentered(ystart2 + 11 * ystep, FONT_TEXT_2, ":-)"); DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for info menu"); #if 1 FadeIn(REDRAW_FIELD); #endif } void HandleInfoScreen_Program(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSoundsAndMusic(); #if 0 FadeOut(REDRAW_FIELD); #endif info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Version() { int font_header = FONT_TEXT_3; int font_text = FONT_TEXT_2; int xstep = getFontWidth(font_text); int ystep = getFontHeight(font_text); int ystart1 = mSY - SY + 100; int ystart2 = mSY - SY + 150; int ybottom = mSY - SY + SYSIZE - 20; int xstart1 = mSX + 2 * xstep; int xstart2 = mSX + 19 * xstep; #if defined(TARGET_SDL) int xstart3 = mSX + 29 * xstep; SDL_version sdl_version_compiled; const SDL_version *sdl_version_linked; int driver_name_len = 8; char driver_name[driver_name_len]; #endif SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION); #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, FONT_TEXT_1, "Version Information:"); DrawTextF(xstart1, ystart2, font_header, "Name"); DrawTextF(xstart2, ystart2, font_text, PROGRAM_TITLE_STRING); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_header, "Version"); DrawTextF(xstart2, ystart2, font_text, getProgramFullVersionString()); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_header, "Platform"); DrawTextF(xstart2, ystart2, font_text, PLATFORM_STRING); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_header, "Target"); DrawTextF(xstart2, ystart2, font_text, TARGET_STRING); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_header, "Compile time"); DrawTextF(xstart2, ystart2, font_text, getCompileDateString()); #if defined(TARGET_SDL) ystart2 += 3 * ystep; DrawTextF(xstart1, ystart2, font_header, "Library"); DrawTextF(xstart2, ystart2, font_header, "compiled"); DrawTextF(xstart3, ystart2, font_header, "linked"); SDL_VERSION(&sdl_version_compiled); sdl_version_linked = SDL_Linked_Version(); ystart2 += 2 * ystep; DrawTextF(xstart1, ystart2, font_text, "SDL"); DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); SDL_IMAGE_VERSION(&sdl_version_compiled); sdl_version_linked = IMG_Linked_Version(); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_text, "SDL_image"); DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); SDL_MIXER_VERSION(&sdl_version_compiled); sdl_version_linked = Mix_Linked_Version(); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_text, "SDL_mixer"); DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); SDL_NET_VERSION(&sdl_version_compiled); sdl_version_linked = SDLNet_Linked_Version(); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_text, "SDL_net"); DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); ystart2 += 3 * ystep; DrawTextF(xstart1, ystart2, font_header, "Driver"); DrawTextF(xstart2, ystart2, font_header, "Requested"); DrawTextF(xstart3, ystart2, font_header, "Used"); SDL_VideoDriverName(driver_name, driver_name_len); ystart2 += 2 * ystep; DrawTextF(xstart1, ystart2, font_text, "SDL_VideoDriver"); DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_videodriver); DrawTextF(xstart3, ystart2, font_text, "%s", driver_name); SDL_AudioDriverName(driver_name, driver_name_len); ystart2 += ystep; DrawTextF(xstart1, ystart2, font_text, "SDL_AudioDriver"); DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_audiodriver); DrawTextF(xstart3, ystart2, font_text, "%s", driver_name); #endif DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for info menu"); #if 1 FadeIn(REDRAW_FIELD); #endif } void HandleInfoScreen_Version(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSoundsAndMusic(); #if 0 FadeOut(REDRAW_FIELD); #endif info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_LevelSet() { struct TitleMessageInfo *tmi = &readme; char *filename = getLevelSetInfoFilename(); /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) tmi->chars = tmi->width / getFontWidth(tmi->font); else tmi->width = tmi->chars * getFontWidth(tmi->font); /* if lines set to "-1", automatically determine by text and font height */ if (tmi->lines == -1) tmi->lines = tmi->height / getFontHeight(tmi->font); else tmi->height = tmi->lines * getFontHeight(tmi->font); SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET); #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); DrawHeadline(); DrawTextCentered(mSY + 100, FONT_TEXT_1, "Level Set Information:"); if (filename != NULL) DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi), filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1, tmi->autowrap, tmi->centered, tmi->parse_comments); else DrawTextCentered(mSY + ALIGNED_TEXT_YPOS(tmi), FONT_TEXT_2, "No information for this level set."); DrawTextCentered(mSY + SYSIZE - 20, FONT_TEXT_4, "Press any key or button for info menu"); #if 1 FadeIn(REDRAW_FIELD); #endif } void HandleInfoScreen_LevelSet(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSoundsAndMusic(); #if 0 FadeOut(REDRAW_FIELD); #endif info_mode = INFO_MODE_MAIN; DrawAndFadeInInfoScreen(REDRAW_FIELD); } else { PlayMenuSoundIfLoop(); } } static void DrawInfoScreenExt(int fade_mask, boolean do_fading) { SetMainBackgroundImage(IMG_BACKGROUND_INFO); if (info_mode == INFO_MODE_TITLE) DrawInfoScreen_TitleScreen(); else if (info_mode == INFO_MODE_ELEMENTS) DrawInfoScreen_Elements(); else if (info_mode == INFO_MODE_MUSIC) DrawInfoScreen_Music(); else if (info_mode == INFO_MODE_CREDITS) DrawInfoScreen_Credits(); else if (info_mode == INFO_MODE_PROGRAM) DrawInfoScreen_Program(); else if (info_mode == INFO_MODE_VERSION) DrawInfoScreen_Version(); else if (info_mode == INFO_MODE_LEVELSET) DrawInfoScreen_LevelSet(); else DrawInfoScreen_Main(fade_mask, do_fading); if (info_mode != INFO_MODE_MAIN && info_mode != INFO_MODE_TITLE && info_mode != INFO_MODE_MUSIC) { PlayMenuSound(); PlayMenuMusic(); } } void DrawAndFadeInInfoScreen(int fade_mask) { DrawInfoScreenExt(fade_mask, TRUE); } void DrawInfoScreen() { DrawInfoScreenExt(REDRAW_FIELD, FALSE); } void HandleInfoScreen(int mx, int my, int dx, int dy, int button) { if (info_mode == INFO_MODE_TITLE) HandleInfoScreen_TitleScreen(button); else if (info_mode == INFO_MODE_ELEMENTS) HandleInfoScreen_Elements(button); else if (info_mode == INFO_MODE_MUSIC) HandleInfoScreen_Music(button); else if (info_mode == INFO_MODE_CREDITS) HandleInfoScreen_Credits(button); else if (info_mode == INFO_MODE_PROGRAM) HandleInfoScreen_Program(button); else if (info_mode == INFO_MODE_VERSION) HandleInfoScreen_Version(button); else if (info_mode == INFO_MODE_LEVELSET) HandleInfoScreen_LevelSet(button); else HandleInfoScreen_Main(mx, my, dx, dy, button); DoAnimation(); } /* ========================================================================= */ /* type name functions */ /* ========================================================================= */ void HandleTypeName(int newxpos, Key key) { static char last_player_name[MAX_PLAYER_NAME_LEN + 1]; struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME); struct TextPosInfo *pos = mci->pos_input; int startx = mSX + ALIGNED_TEXT_XPOS(pos); int starty = mSY + ALIGNED_TEXT_YPOS(pos); static int xpos = 0; int font_nr = pos->font; int font_active_nr = FONT_ACTIVE(font_nr); int font_width = getFontWidth(font_active_nr); char key_char = getValidConfigValueChar(getCharFromKey(key)); boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0)); boolean is_active = TRUE; DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr); if (newxpos) { strcpy(last_player_name, setup.player_name); xpos = newxpos; } else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN) { setup.player_name[xpos] = key_char; setup.player_name[xpos + 1] = 0; xpos++; } else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0) { xpos--; setup.player_name[xpos] = 0; } else if (key == KSYM_Return && xpos > 0) { SaveSetup(); is_active = FALSE; game_status = GAME_MODE_MAIN; } else if (key == KSYM_Escape) { strcpy(setup.player_name, last_player_name); is_active = FALSE; game_status = GAME_MODE_MAIN; } if (is_active) { pos->width = (strlen(setup.player_name) + 1) * font_width; startx = mSX + ALIGNED_TEXT_XPOS(pos); DrawText(startx, starty, setup.player_name, font_active_nr); DrawText(startx + xpos * font_width, starty, "_", font_active_nr); } else { pos->width = strlen(setup.player_name) * font_width; startx = mSX + ALIGNED_TEXT_XPOS(pos); DrawText(startx, starty, setup.player_name, font_nr); } } /* ========================================================================= */ /* tree menu functions */ /* ========================================================================= */ static void DrawChooseTree(TreeInfo **ti_ptr) { UnmapAllGadgets(); FreeScreenGadgets(); CreateScreenGadgets(); CloseDoor(DOOR_CLOSE_2); #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr); MapScreenTreeGadgets(*ti_ptr); #if 1 FadeIn(REDRAW_FIELD); #endif InitAnimation(); } static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti) { struct GadgetInfo *gi = screen_gadget[id]; int items_max, items_visible, item_position; items_max = numTreeInfoInGroup(ti); items_visible = NUM_MENU_ENTRIES_ON_SCREEN; item_position = first_entry; if (item_position > items_max - items_visible) item_position = items_max - items_visible; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void drawChooseTreeList(int first_entry, int num_page_entries, TreeInfo *ti) { int i; char *title_string = NULL; int yoffset_sets = MENU_TITLE1_YPOS; int yoffset_setup = 16; int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets : yoffset_setup); int last_game_status = game_status; /* save current game status */ title_string = ti->infotext; DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string); #if 0 /* force LEVELS font on artwork setup screen */ game_status = GAME_MODE_LEVELS; #endif #if 1 /* clear tree list area, but not title or scrollbar */ DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32, SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset, NUM_MENU_ENTRIES_ON_SCREEN * 32); #else /* clear tree list area, but not title or scrollbar */ DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32, SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset, MAX_MENU_ENTRIES_ON_SCREEN * 32); #endif for (i = 0; i < num_page_entries; i++) { TreeInfo *node, *node_first; int entry_pos = first_entry + i; int xpos = MENU_SCREEN_START_XPOS; int ypos = MENU_SCREEN_START_YPOS + i; int startx = mSX + xpos * 32; int starty = mSY + ypos * 32; int font_nr = FONT_TEXT_1; int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int startx_text = startx + font_xoffset; int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; int text_size = startx_scrollbar - startx_text; int max_buffer_len = text_size / getFontWidth(font_nr); char buffer[max_buffer_len + 1]; node_first = getTreeInfoFirstGroupEntry(ti); node = getTreeInfoFromPos(node_first, entry_pos); strncpy(buffer, node->name, max_buffer_len); buffer[max_buffer_len] = '\0'; DrawText(startx, starty, buffer, font_nr + node->color); if (node->parent_link) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (node->level_group) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else initCursor(i, IMG_MENU_BUTTON); } game_status = last_game_status; /* restore current game status */ redraw_mask |= REDRAW_FIELD; } static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti) { TreeInfo *node, *node_first; int x, last_redraw_mask = redraw_mask; int ypos = MENU_TITLE2_YPOS; int font_nr = FONT_TITLE_2; if (ti->type != TREE_TYPE_LEVEL_DIR) return; node_first = getTreeInfoFirstGroupEntry(ti); node = getTreeInfoFromPos(node_first, entry_pos); DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr); if (node->parent_link) DrawTextFCentered(ypos, font_nr, "leave group \"%s\"", node->class_desc); else if (node->level_group) DrawTextFCentered(ypos, font_nr, "enter group \"%s\"", node->class_desc); else if (ti->type == TREE_TYPE_LEVEL_DIR) DrawTextFCentered(ypos, font_nr, "%3d levels (%s)", node->levels, node->class_desc); /* let BackToFront() redraw only what is needed */ redraw_mask = last_redraw_mask | REDRAW_TILES; for (x = 0; x < SCR_FIELDX; x++) MarkTileDirty(x, 1); } static void HandleChooseTree(int mx, int my, int dx, int dy, int button, TreeInfo **ti_ptr) { TreeInfo *ti = *ti_ptr; int x = 0; int y = ti->cl_cursor; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); int num_entries = numTreeInfoInGroup(ti); int num_page_entries; int last_game_status = game_status; /* save current game status */ boolean position_set_by_scrollbar = (dx == 999); #if 0 /* force LEVELS draw offset on choose level and artwork setup screen */ game_status = GAME_MODE_LEVELS; #endif if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN) num_page_entries = num_entries; else num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; game_status = last_game_status; /* restore current game status */ if (button == MB_MENU_INITIALIZE) { int num_entries = numTreeInfoInGroup(ti); int entry_pos = posTreeInfo(ti); if (ti->cl_first == -1) { /* only on initialization */ ti->cl_first = MAX(0, entry_pos - num_page_entries + 1); ti->cl_cursor = entry_pos - ti->cl_first; } else if (ti->cl_cursor >= num_page_entries || (num_entries > num_page_entries && num_entries - ti->cl_first < num_page_entries)) { /* only after change of list size (by custom graphic configuration) */ ti->cl_first = MAX(0, entry_pos - num_page_entries + 1); ti->cl_cursor = entry_pos - ti->cl_first; } if (position_set_by_scrollbar) ti->cl_first = dy; else AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); drawChooseTreeCursor(ti->cl_cursor, TRUE); return; } else if (button == MB_MENU_LEAVE) { FadeSetLeaveMenu(); PlaySound(SND_MENU_ITEM_SELECTING); if (ti->node_parent) { *ti_ptr = ti->node_parent; DrawChooseTree(ti_ptr); } else if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) execSetupGame(); else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE || setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) execSetupGraphics(); else execSetupArtwork(); } else { game_status = GAME_MODE_MAIN; DrawMainMenuExt(REDRAW_FIELD, FALSE); } return; } if (mx || my) /* mouse input */ { int last_game_status = game_status; /* save current game status */ #if 0 /* force LEVELS draw offset on artwork setup screen */ game_status = GAME_MODE_LEVELS; #endif x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; game_status = last_game_status; /* restore current game status */ } else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ { /* move cursor instead of scrolling when already at start/end of list */ if (dy == -1 * SCROLL_LINE && ti->cl_first == 0) dy = -1; else if (dy == +1 * SCROLL_LINE && ti->cl_first + num_page_entries == num_entries) dy = 1; /* handle scrolling screen one line or page */ if (ti->cl_cursor + dy < 0 || ti->cl_cursor + dy > num_page_entries - 1) { if (ABS(dy) == SCROLL_PAGE) step = num_page_entries - 1; if (dy < 0 && ti->cl_first > 0) { /* scroll page/line up */ ti->cl_first -= step; if (ti->cl_first < 0) ti->cl_first = 0; drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); drawChooseTreeCursor(ti->cl_cursor, TRUE); AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); } else if (dy > 0 && ti->cl_first + num_page_entries < num_entries) { /* scroll page/line down */ ti->cl_first += step; if (ti->cl_first + num_page_entries > num_entries) ti->cl_first = MAX(0, num_entries - num_page_entries); drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); drawChooseTreeCursor(ti->cl_cursor, TRUE); AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); } return; } /* handle moving cursor one line */ y = ti->cl_cursor + dy; } if (dx == 1) { TreeInfo *node_first, *node_cursor; int entry_pos = ti->cl_first + y; node_first = getTreeInfoFirstGroupEntry(ti); node_cursor = getTreeInfoFromPos(node_first, entry_pos); if (node_cursor->node_group) { FadeSetEnterMenu(); PlaySound(SND_MENU_ITEM_SELECTING); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor->node_group; DrawChooseTree(ti_ptr); return; } } else if (dx == -1 && ti->node_parent) { FadeSetLeaveMenu(); PlaySound(SND_MENU_ITEM_SELECTING); *ti_ptr = ti->node_parent; DrawChooseTree(ti_ptr); return; } if (!anyScrollbarGadgetActive() && IN_VIS_FIELD(x, y) && mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && y >= 0 && y < num_page_entries) { if (button) { if (y != ti->cl_cursor) { PlaySound(SND_MENU_ITEM_ACTIVATING); drawChooseTreeCursor(ti->cl_cursor, FALSE); drawChooseTreeCursor(y, TRUE); drawChooseTreeInfo(ti->cl_first + y, ti); ti->cl_cursor = y; } } else { TreeInfo *node_first, *node_cursor; int entry_pos = ti->cl_first + y; PlaySound(SND_MENU_ITEM_SELECTING); node_first = getTreeInfoFirstGroupEntry(ti); node_cursor = getTreeInfoFromPos(node_first, entry_pos); if (node_cursor->node_group) { FadeSetEnterMenu(); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor->node_group; DrawChooseTree(ti_ptr); } else if (node_cursor->parent_link) { FadeSetLeaveMenu(); *ti_ptr = node_cursor->node_parent; DrawChooseTree(ti_ptr); } else { FadeSetEnterScreen(); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor; if (ti->type == TREE_TYPE_LEVEL_DIR) { LoadLevelSetup_SeriesInfo(); SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); TapeErase(); } if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) execSetupGame(); else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE || setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) execSetupGraphics(); else execSetupArtwork(); } else { game_status = GAME_MODE_MAIN; DrawMainMenu(); } } } } } void DrawChooseLevel() { SetMainBackgroundImage(IMG_BACKGROUND_LEVELS); DrawChooseTree(&leveldir_current); PlayMenuSound(); PlayMenuMusic(); } void HandleChooseLevel(int mx, int my, int dx, int dy, int button) { HandleChooseTree(mx, my, dx, dy, button, &leveldir_current); DoAnimation(); } void DrawHallOfFame(int highlight_position) { UnmapAllGadgets(); FadeSoundsAndMusic(); /* (this is needed when called from GameEnd() after winning a game) */ KeyboardAutoRepeatOn(); ActivateJoystick(); /* (this is needed when called from GameEnd() after winning a game) */ SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); CloseDoor(DOOR_CLOSE_2); if (highlight_position < 0) LoadScore(level_nr); FadeSetEnterScreen(); // printf("::: %d: %d\n", game_status, menu.enter_screen[game_status]); #if 1 FadeOut(REDRAW_FIELD); #endif InitAnimation(); PlayMenuSound(); PlayMenuMusic(); HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE); #if 1 FadeIn(REDRAW_FIELD); #endif } static void drawHallOfFameList(int first_entry, int highlight_position) { int i; SetMainBackgroundImage(IMG_BACKGROUND_SCORES); ClearField(); DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame"); DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, "HighScores of Level %d", level_nr); for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++) { int entry = first_entry + i; boolean active = (entry == highlight_position); int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1); int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2); int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3); int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4); int dx1 = 3 * getFontWidth(font_nr1); int dx2 = dx1 + getFontWidth(font_nr1); int dx3 = dx2 + 25 * getFontWidth(font_nr3); int sy = mSY + 64 + i * 32; DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1); DrawText(mSX + dx1, sy, ".", font_nr1); DrawText(mSX + dx2, sy, ".........................", font_nr3); if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME)) DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2); DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4); } redraw_mask |= REDRAW_FIELD; } void HandleHallOfFame(int mx, int my, int dx, int dy, int button) { static int first_entry = 0; static int highlight_position = 0; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); if (button == MB_MENU_INITIALIZE) { first_entry = 0; highlight_position = mx; drawHallOfFameList(first_entry, highlight_position); return; } if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */ step = NUM_MENU_ENTRIES_ON_SCREEN - 1; if (dy < 0) { if (first_entry > 0) { first_entry -= step; if (first_entry < 0) first_entry = 0; drawHallOfFameList(first_entry, highlight_position); } } else if (dy > 0) { if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES) { first_entry += step; if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES) first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); drawHallOfFameList(first_entry, highlight_position); } } else if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSound(SND_BACKGROUND_SCORES); game_status = GAME_MODE_MAIN; DrawMainMenu(); } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSound(SND_BACKGROUND_SCORES); #if 0 FadeOut(REDRAW_FIELD); #endif game_status = GAME_MODE_MAIN; DrawAndFadeInMainMenu(REDRAW_FIELD); } if (game_status == GAME_MODE_SCORES) PlayMenuSoundIfLoop(); DoAnimation(); } /* ========================================================================= */ /* setup screen functions */ /* ========================================================================= */ static struct TokenInfo *setup_info; static int num_setup_info; static char *screen_mode_text; static char *scroll_delay_text; static char *game_speed_text; static char *graphics_set_name; static char *sounds_set_name; static char *music_set_name; static void execSetupMain() { setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } static void execSetupGame() { if (game_speeds == NULL) { int i; for (i = 0; game_speeds_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = game_speeds_list[i].value; char *text = game_speeds_list[i].text; ti->node_top = &game_speeds; ti->sort_priority = 10000 - value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, "Game Speed"); pushTreeInfo(&game_speeds, ti); } /* sort game speed values to start with slowest game speed */ sortTreeInfo(&game_speeds); /* set current game speed to configured game speed value */ game_speed_current = getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay)); /* if that fails, set current game speed to reliable default value */ if (game_speed_current == NULL) game_speed_current = getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY)); /* if that also fails, set current game speed to first available speed */ if (game_speed_current == NULL) game_speed_current = game_speeds; } setup.game_frame_delay = atoi(game_speed_current->identifier); /* needed for displaying game speed text instead of identifier */ game_speed_text = game_speed_current->name; setup_mode = SETUP_MODE_GAME; DrawSetupScreen(); } static void execSetupChooseGameSpeed() { setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED; DrawSetupScreen(); } static void execSetupEditor() { setup_mode = SETUP_MODE_EDITOR; DrawSetupScreen(); } static void execSetupGraphics() { if (video.fullscreen_available && screen_modes == NULL) { int i; for (i = 0; video.fullscreen_modes[i].width != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int x = video.fullscreen_modes[i].width; int y = video.fullscreen_modes[i].height; int xx, yy; get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy); ti->node_top = &screen_modes; ti->sort_priority = x * 10000 + y; sprintf(identifier, "%dx%d", x, y); sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, "Fullscreen Mode"); pushTreeInfo(&screen_modes, ti); } /* sort fullscreen modes to start with lowest available screen resolution */ sortTreeInfo(&screen_modes); /* set current screen mode for fullscreen mode to configured setup value */ screen_mode_current = getTreeInfoFromIdentifier(screen_modes, setup.fullscreen_mode); /* if that fails, set current screen mode to reliable default value */ if (screen_mode_current == NULL) screen_mode_current = getTreeInfoFromIdentifier(screen_modes, DEFAULT_FULLSCREEN_MODE); /* if that also fails, set current screen mode to first available mode */ if (screen_mode_current == NULL) screen_mode_current = screen_modes; if (screen_mode_current == NULL) video.fullscreen_available = FALSE; } if (video.fullscreen_available) { setup.fullscreen_mode = screen_mode_current->identifier; /* needed for displaying screen mode name instead of identifier */ screen_mode_text = screen_mode_current->name; } #if 1 if (scroll_delays == NULL) { int i; for (i = 0; scroll_delays_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = scroll_delays_list[i].value; char *text = scroll_delays_list[i].text; ti->node_top = &scroll_delays; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, "Scroll Delay"); pushTreeInfo(&scroll_delays, ti); } /* sort scroll delay values to start with lowest scroll delay value */ sortTreeInfo(&scroll_delays); /* set current scroll delay value to configured scroll delay value */ scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value)); /* if that fails, set current scroll delay to reliable default value */ if (scroll_delay_current == NULL) scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY)); /* if that also fails, set current scroll delay to first available value */ if (scroll_delay_current == NULL) scroll_delay_current = scroll_delays; } setup.scroll_delay_value = atoi(scroll_delay_current->identifier); /* needed for displaying scroll delay text instead of identifier */ scroll_delay_text = scroll_delay_current->name; #endif setup_mode = SETUP_MODE_GRAPHICS; DrawSetupScreen(); } static void execSetupChooseScreenMode() { if (!video.fullscreen_available) return; setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE; DrawSetupScreen(); } static void execSetupChooseScrollDelay() { setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY; DrawSetupScreen(); } static void execSetupSound() { setup_mode = SETUP_MODE_SOUND; DrawSetupScreen(); } static void execSetupArtwork() { #if 0 printf("::: '%s', '%s', '%s'\n", artwork.gfx_current->subdir, artwork.gfx_current->fullpath, artwork.gfx_current->basepath); #endif setup.graphics_set = artwork.gfx_current->identifier; setup.sounds_set = artwork.snd_current->identifier; setup.music_set = artwork.mus_current->identifier; /* needed if last screen (setup choice) changed graphics, sounds or music */ ReloadCustomArtwork(0); /* needed for displaying artwork name instead of artwork identifier */ graphics_set_name = artwork.gfx_current->name; sounds_set_name = artwork.snd_current->name; music_set_name = artwork.mus_current->name; setup_mode = SETUP_MODE_ARTWORK; DrawSetupScreen(); } static void execSetupChooseGraphics() { setup_mode = SETUP_MODE_CHOOSE_GRAPHICS; DrawSetupScreen(); } static void execSetupChooseSounds() { setup_mode = SETUP_MODE_CHOOSE_SOUNDS; DrawSetupScreen(); } static void execSetupChooseMusic() { setup_mode = SETUP_MODE_CHOOSE_MUSIC; DrawSetupScreen(); } static void execSetupInput() { setup_mode = SETUP_MODE_INPUT; DrawSetupScreen(); } static void execSetupShortcuts() { setup_mode = SETUP_MODE_SHORTCUTS; DrawSetupScreen(); } static void execSetupShortcuts1() { setup_mode = SETUP_MODE_SHORTCUTS_1; DrawSetupScreen(); } static void execSetupShortcuts2() { setup_mode = SETUP_MODE_SHORTCUTS_2; DrawSetupScreen(); } static void execSetupShortcuts3() { setup_mode = SETUP_MODE_SHORTCUTS_3; DrawSetupScreen(); } static void execSetupShortcuts4() { setup_mode = SETUP_MODE_SHORTCUTS_4; DrawSetupScreen(); } static void execSetupShortcuts5() { setup_mode = SETUP_MODE_SHORTCUTS_5; DrawSetupScreen(); } static void execExitSetup() { game_status = GAME_MODE_MAIN; DrawMainMenuExt(REDRAW_FIELD, FALSE); } static void execSaveAndExitSetup() { SaveSetup(); execExitSetup(); } static struct TokenInfo setup_info_main[] = { { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" }, { TYPE_ENTER_MENU, execSetupEditor, "Editor" }, { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" }, { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" }, { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" }, { TYPE_ENTER_MENU, execSetupInput, "Input Devices" }, { TYPE_ENTER_MENU, execSetupShortcuts, "Key Shortcuts" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execExitSetup, "Exit" }, { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_game[] = { { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" }, { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" }, { TYPE_SWITCH, &setup.handicap, "Handicap:" }, { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" }, { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" }, { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" }, { TYPE_STRING, &game_speed_text, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_editor[] = { #if 0 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" }, { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" }, { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" }, { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" }, { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" }, { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" }, { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" }, { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" }, #endif { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" }, { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" }, { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" }, #if 0 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" }, #endif { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" }, { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" }, { TYPE_EMPTY, NULL, "" }, #if 0 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" }, { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" }, { TYPE_EMPTY, NULL, "" }, #endif { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_graphics[] = { { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" }, { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" }, { TYPE_STRING, &screen_mode_text, "" }, #if 0 { TYPE_SWITCH, &setup.scroll_delay, "Scroll Delay:" }, #endif { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay Value:" }, { TYPE_STRING, &scroll_delay_text, "" }, #if 0 { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scrolling:" }, #endif { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" }, { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" }, { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" }, { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" }, { TYPE_SWITCH, &setup.toons, "Show Toons:" }, { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" }, { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_sound[] = { { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" }, { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" }, { TYPE_SWITCH, &setup.sound_music, "Music:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_artwork[] = { { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" }, { TYPE_STRING, &graphics_set_name, "" }, { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" }, { TYPE_STRING, &sounds_set_name, "" }, { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" }, { TYPE_STRING, &music_set_name, "" }, { TYPE_EMPTY, NULL, "" }, #if 1 #if 1 { TYPE_YES_NO_AUTO,&setup.override_level_graphics,"Override Level Graphics:"}, { TYPE_YES_NO_AUTO,&setup.override_level_sounds, "Override Level Sounds:" }, { TYPE_YES_NO_AUTO,&setup.override_level_music, "Override Level Music:" }, #else { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" }, { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:" }, { TYPE_YES_NO, &setup.override_level_music, "Override Level Music:" }, { TYPE_YES_NO, &setup.auto_override_artwork, "Auto-Override Non-CE Sets:" }, #endif #else { TYPE_STRING, NULL, "Override Level Artwork:"}, { TYPE_YES_NO, &setup.override_level_graphics, "Graphics:" }, { TYPE_YES_NO, &setup.override_level_sounds, "Sounds:" }, { TYPE_YES_NO, &setup.override_level_music, "Music:" }, #endif { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_input[] = { { TYPE_SWITCH, NULL, "Player:" }, { TYPE_SWITCH, NULL, "Device:" }, { TYPE_ENTER_MENU, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts[] = { { TYPE_ENTER_MENU, execSetupShortcuts1, "Various Keys" }, { TYPE_ENTER_MENU, execSetupShortcuts2, "Player Focus" }, { TYPE_ENTER_MENU, execSetupShortcuts3, "Tape Buttons" }, { TYPE_ENTER_MENU, execSetupShortcuts4, "Sound & Music" }, { TYPE_ENTER_MENU, execSetupShortcuts5, "TAS Snap Keys" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_1[] = { { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", }, { TYPE_KEY, &setup.shortcut.save_game, "" }, { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", }, { TYPE_KEY, &setup.shortcut.load_game, "" }, { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", }, { TYPE_KEY, &setup.shortcut.toggle_pause, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" }, { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_2[] = { { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", }, { TYPE_KEY, &setup.shortcut.focus_player[0], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", }, { TYPE_KEY, &setup.shortcut.focus_player[1], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", }, { TYPE_KEY, &setup.shortcut.focus_player[2], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", }, { TYPE_KEY, &setup.shortcut.focus_player[3], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", }, { TYPE_KEY, &setup.shortcut.focus_player_all, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_3[] = { { TYPE_KEYTEXT, NULL, "Tape Eject:", }, { TYPE_KEY, &setup.shortcut.tape_eject, "" }, { TYPE_KEYTEXT, NULL, "Tape Stop:", }, { TYPE_KEY, &setup.shortcut.tape_stop, "" }, { TYPE_KEYTEXT, NULL, "Tape Pause:", }, { TYPE_KEY, &setup.shortcut.tape_pause, "" }, { TYPE_KEYTEXT, NULL, "Tape Record:", }, { TYPE_KEY, &setup.shortcut.tape_record, "" }, { TYPE_KEYTEXT, NULL, "Tape Play:", }, { TYPE_KEY, &setup.shortcut.tape_play, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_4[] = { { TYPE_KEYTEXT, NULL, "Sound Effects (Normal):", }, { TYPE_KEY, &setup.shortcut.sound_simple, "" }, { TYPE_KEYTEXT, NULL, "Sound Effects (Looping):", }, { TYPE_KEY, &setup.shortcut.sound_loops, "" }, { TYPE_KEYTEXT, NULL, "Music:", }, { TYPE_KEY, &setup.shortcut.sound_music, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_5[] = { { TYPE_KEYTEXT, NULL, "Snap Left:", }, { TYPE_KEY, &setup.shortcut.snap_left, "" }, { TYPE_KEYTEXT, NULL, "Snap Right:", }, { TYPE_KEY, &setup.shortcut.snap_right, "" }, { TYPE_KEYTEXT, NULL, "Snap Up:", }, { TYPE_KEY, &setup.shortcut.snap_up, "" }, { TYPE_KEYTEXT, NULL, "Snap Down:", }, { TYPE_KEY, &setup.shortcut.snap_down, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static Key getSetupKey() { Key key = KSYM_UNDEFINED; boolean got_key_event = FALSE; while (!got_key_event) { if (PendingEvent()) /* got event */ { Event event; NextEvent(&event); switch (event.type) { case EVENT_KEYPRESS: { key = GetEventKey((KeyEvent *)&event, TRUE); /* press 'Escape' or 'Enter' to keep the existing key binding */ if (key == KSYM_Escape || key == KSYM_Return) key = KSYM_UNDEFINED; /* keep old value */ got_key_event = TRUE; } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } DoAnimation(); BackToFront(); /* don't eat all CPU time */ Delay(10); } return key; } static int getSetupTextFont(int type) { if (type & (TYPE_SWITCH | TYPE_YES_NO | TYPE_YES_NO_AUTO | TYPE_STRING | TYPE_ECS_AGA | TYPE_KEYTEXT | TYPE_ENTER_LIST)) return FONT_MENU_2; else return FONT_MENU_1; } static int getSetupValueFont(int type, void *value) { if (type & TYPE_KEY) return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1); else if (type & TYPE_STRING) return FONT_VALUE_2; else if (type & TYPE_ECS_AGA) return FONT_VALUE_1; else if (type & TYPE_BOOLEAN_STYLE) return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF); else if (type & TYPE_YES_NO_AUTO) return (*(int *)value == AUTO ? FONT_OPTION_ON : *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON); else return FONT_VALUE_1; } static void drawSetupValue(int pos) { boolean font_draw_xoffset_modified = FALSE; int font_draw_xoffset_old = -1; int xpos = MENU_SCREEN_VALUE_XPOS; int ypos = MENU_SCREEN_START_YPOS + pos; int startx = mSX + xpos * 32; int starty = mSY + ypos * 32; int font_nr, font_width, font_height; int type = setup_info[pos].type; void *value = setup_info[pos].value; char *value_string = getSetupValue(type, value); #if 1 int i; #endif if (value_string == NULL) return; if (type & TYPE_KEY) { xpos = MENU_SCREEN_START_XPOS; if (type & TYPE_QUERY) value_string = ""; } else if (type & TYPE_STRING) { int max_value_len = (SCR_FIELDX - 2) * 2; xpos = MENU_SCREEN_START_XPOS; if (strlen(value_string) > max_value_len) value_string[max_value_len] = '\0'; } else if (type & TYPE_YES_NO_AUTO) { xpos = MENU_SCREEN_VALUE_XPOS - 1; } startx = mSX + xpos * 32; starty = mSY + ypos * 32; font_nr = getSetupValueFont(type, value); font_width = getFontWidth(font_nr); font_height = getFontHeight(font_nr); /* downward compatibility correction for Juergen Bonhagen's menu settings */ if (setup_mode != SETUP_MODE_INPUT) { int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */ int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset; int text_startx = mSX + MENU_SCREEN_START_XPOS * 32; int text_font_nr = getSetupTextFont(FONT_MENU_2); int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset; int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr); boolean correct_font_draw_xoffset = FALSE; if (xpos == MENU_SCREEN_START_XPOS && startx + font1_xoffset < text_startx + text_font_xoffset) correct_font_draw_xoffset = TRUE; if (xpos == MENU_SCREEN_VALUE_XPOS && startx + font2_xoffset < text_startx + text_width + text_font_xoffset) correct_font_draw_xoffset = TRUE; /* check if setup value would overlap with setup text when printed */ /* (this can happen for extreme/wrong values for font draw offset) */ if (correct_font_draw_xoffset) { font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset; font_draw_xoffset_modified = TRUE; if (type & TYPE_KEY) getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr); else if (!(type & TYPE_STRING)) getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 - MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr)); } } #if 0 DrawBackground(startx, starty, SX + SXSIZE - startx, font_height); #else for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++) DrawText(startx + i * font_width, starty, " ", font_nr); #endif DrawText(startx, starty, value_string, font_nr); if (font_draw_xoffset_modified) getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old; } static void changeSetupValue(int pos, int dx) { if (setup_info[pos].type & TYPE_BOOLEAN_STYLE) { *(boolean *)setup_info[pos].value ^= TRUE; } else if (setup_info[pos].type & TYPE_YES_NO_AUTO) { *(int *)setup_info[pos].value = (dx == -1 ? (*(int *)setup_info[pos].value == AUTO ? TRUE : *(int *)setup_info[pos].value == TRUE ? FALSE : AUTO) : (*(int *)setup_info[pos].value == TRUE ? AUTO : *(int *)setup_info[pos].value == AUTO ? FALSE : TRUE)); } else if (setup_info[pos].type & TYPE_KEY) { Key key; setup_info[pos].type |= TYPE_QUERY; drawSetupValue(pos); setup_info[pos].type &= ~TYPE_QUERY; key = getSetupKey(); if (key != KSYM_UNDEFINED) *(Key *)setup_info[pos].value = key; } drawSetupValue(pos); } static void DrawCursorAndText_Setup(int pos, boolean active) { int xpos = MENU_SCREEN_START_XPOS; int ypos = MENU_SCREEN_START_YPOS + pos; int font_nr = getSetupTextFont(setup_info[pos].type); if (setup_info == setup_info_input) font_nr = FONT_MENU_1; if (active) font_nr = FONT_ACTIVE(font_nr); DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr); if (setup_info[pos].type & ~TYPE_SKIP_ENTRY) drawCursor(pos, active); } static void DrawSetupScreen_Generic() { boolean redraw_all = FALSE; char *title_string = NULL; int i; UnmapAllGadgets(); CloseDoor(DOOR_CLOSE_2); if (redraw_mask & REDRAW_ALL) redraw_all = TRUE; #if 0 printf("::: %s\n", (redraw_mask & REDRAW_FIELD ? "REDRAW_FIELD" : redraw_mask & REDRAW_ALL ? "REDRAW_ALL" : int2str(0, redraw_mask))); #endif #if 0 /* !!! usually REDRAW_NONE => DOES NOT WORK (with fade) => CHECK THIS !!! */ FadeOut(redraw_mask); #else FadeOut(REDRAW_FIELD); #endif ClearField(); if (setup_mode == SETUP_MODE_MAIN) { setup_info = setup_info_main; title_string = "Setup"; } else if (setup_mode == SETUP_MODE_GAME) { setup_info = setup_info_game; title_string = "Setup Game"; } else if (setup_mode == SETUP_MODE_EDITOR) { setup_info = setup_info_editor; title_string = "Setup Editor"; } else if (setup_mode == SETUP_MODE_GRAPHICS) { setup_info = setup_info_graphics; title_string = "Setup Graphics"; } else if (setup_mode == SETUP_MODE_SOUND) { setup_info = setup_info_sound; title_string = "Setup Sound"; } else if (setup_mode == SETUP_MODE_ARTWORK) { setup_info = setup_info_artwork; title_string = "Custom Artwork"; } else if (setup_mode == SETUP_MODE_SHORTCUTS) { setup_info = setup_info_shortcuts; title_string = "Setup Shortcuts"; } else if (setup_mode == SETUP_MODE_SHORTCUTS_1) { setup_info = setup_info_shortcuts_1; title_string = "Setup Shortcuts"; } else if (setup_mode == SETUP_MODE_SHORTCUTS_2) { setup_info = setup_info_shortcuts_2; title_string = "Setup Shortcuts"; } else if (setup_mode == SETUP_MODE_SHORTCUTS_3) { setup_info = setup_info_shortcuts_3; title_string = "Setup Shortcuts"; } else if (setup_mode == SETUP_MODE_SHORTCUTS_4) { setup_info = setup_info_shortcuts_4; title_string = "Setup Shortcuts"; } else if (setup_mode == SETUP_MODE_SHORTCUTS_5) { setup_info = setup_info_shortcuts_5; title_string = "Setup Shortcuts"; } DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string); num_setup_info = 0; #if 1 for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) #else for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) #endif { void *value_ptr = setup_info[i].value; /* set some entries to "unchangeable" according to other variables */ if ((value_ptr == &setup.sound_simple && !audio.sound_available) || (value_ptr == &setup.sound_loops && !audio.loops_available) || (value_ptr == &setup.sound_music && !audio.music_available) || (value_ptr == &setup.fullscreen && !video.fullscreen_available) || (value_ptr == &screen_mode_text && !video.fullscreen_available)) setup_info[i].type |= TYPE_GHOSTED; if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (setup_info[i].type & ~TYPE_SKIP_ENTRY) initCursor(i, IMG_MENU_BUTTON); DrawCursorAndText_Setup(i, FALSE); if (setup_info[i].type & TYPE_VALUE) drawSetupValue(i); num_setup_info++; } #if 0 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4, "Joysticks deactivated in setup menu"); #endif #if 1 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE); #endif if (redraw_all) redraw_mask = REDRAW_ALL; #if 1 FadeIn(redraw_mask); #else FadeIn(REDRAW_FIELD); #endif InitAnimation(); #if 0 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE); #endif } void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) { static int choice_store[MAX_SETUP_MODES]; int choice = choice_store[setup_mode]; /* always starts with 0 */ int x = 0; int y = choice; if (button == MB_MENU_INITIALIZE) { /* advance to first valid menu entry */ while (choice < num_setup_info && setup_info[choice].type & TYPE_SKIP_ENTRY) choice++; choice_store[setup_mode] = choice; DrawCursorAndText_Setup(choice, TRUE); return; } else if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); for (y = 0; y < num_setup_info; y++) { if (setup_info[y].type & TYPE_LEAVE_MENU) { void (*menu_callback_function)(void) = setup_info[y].value; FadeSetLeaveMenu(); menu_callback_function(); break; /* absolutely needed because function changes 'setup_info'! */ } } return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard input */ { if (dx) { int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER); if (setup_info[choice].type & menu_navigation_type || setup_info[choice].type & TYPE_BOOLEAN_STYLE || setup_info[choice].type & TYPE_YES_NO_AUTO) button = MB_MENU_CHOICE; } else if (dy) y = choice + dy; /* jump to next non-empty menu entry (up or down) */ while (y > 0 && y < num_setup_info - 1 && setup_info[y].type & TYPE_SKIP_ENTRY) y += dy; } if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info) { if (button) { if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY) { PlaySound(SND_MENU_ITEM_ACTIVATING); DrawCursorAndText_Setup(choice, FALSE); DrawCursorAndText_Setup(y, TRUE); choice = choice_store[setup_mode] = y; } } else if (!(setup_info[y].type & TYPE_GHOSTED)) { PlaySound(SND_MENU_ITEM_SELECTING); /* when selecting key headline, execute function for key value change */ if (setup_info[y].type & TYPE_KEYTEXT && setup_info[y + 1].type & TYPE_KEY) y++; /* when selecting string value, execute function for list selection */ if (setup_info[y].type & TYPE_STRING && y > 0 && setup_info[y - 1].type & TYPE_ENTER_LIST) y--; if (setup_info[y].type & TYPE_ENTER_OR_LEAVE) { void (*menu_callback_function)(void) = setup_info[y].value; FadeSetFromType(setup_info[y].type); menu_callback_function(); } else { if (setup_info[y].type & TYPE_VALUE) changeSetupValue(y, dx); } } } } void DrawSetupScreen_Input() { int i; #if 1 FadeOut(REDRAW_FIELD); #endif ClearField(); #if 1 setup_info = setup_info_input; #endif DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input"); #if 1 #if 1 DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2, "Joysticks deactivated on this screen"); #else DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4, "Joysticks deactivated on this screen"); #endif #endif #if 1 for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) #else for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) #endif { if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (setup_info[i].type & ~TYPE_SKIP_ENTRY) initCursor(i, IMG_MENU_BUTTON); DrawCursorAndText_Setup(i, FALSE); } #if 0 DeactivateJoystickForCalibration(); #endif #if 0 #if 1 DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2, "Joysticks deactivated on this screen"); #else DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4, "Joysticks deactivated on this screen"); #endif #endif /* create gadgets for setup input menu screen */ FreeScreenGadgets(); CreateScreenGadgets(); /* map gadgets for setup input menu screen */ MapScreenMenuGadgets(SCREEN_MASK_INPUT); HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE); #if 1 FadeIn(REDRAW_FIELD); #endif InitAnimation(); } static void setJoystickDeviceToNr(char *device_name, int device_nr) { if (device_name == NULL) return; if (device_nr < 0 || device_nr >= MAX_PLAYERS) device_nr = 0; if (strlen(device_name) > 1) { char c1 = device_name[strlen(device_name) - 1]; char c2 = device_name[strlen(device_name) - 2]; if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9')) device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10); } else strncpy(device_name, getDeviceNameFromJoystickNr(device_nr), strlen(device_name)); } static void drawPlayerSetupInputInfo(int player_nr, boolean active) { int i; static struct SetupKeyboardInfo custom_key; static struct { Key *key; char *text; } custom[] = { { &custom_key.left, "Joystick Left" }, { &custom_key.right, "Joystick Right" }, { &custom_key.up, "Joystick Up" }, { &custom_key.down, "Joystick Down" }, { &custom_key.snap, "Button 1" }, { &custom_key.drop, "Button 2" } }; static char *joystick_name[MAX_PLAYERS] = { "Joystick1", "Joystick2", "Joystick3", "Joystick4" }; int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1); InitJoysticks(); custom_key = setup.input[player_nr].key; DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1), FONT_INPUT_1_ACTIVE); ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY, TILEX, TILEY); DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY, PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0); if (setup.input[player_nr].use_joystick) { char *device_name = setup.input[player_nr].joy.device_name; char *text = joystick_name[getJoystickNrFromDeviceName(device_name)]; int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1); DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr); DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr); } else { DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1); DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr); } DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1); drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT); drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT); drawCursorXY(1, 6, IMG_MENU_BUTTON_UP); drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN); DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD); DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD); for (i = 0; i < 6; i++) { int ypos = 6 + i + (i > 3 ? i-3 : 0); DrawText(mSX + 3 * 32, mSY + ypos * 32, " ", FONT_VALUE_1); DrawText(mSX + 3 * 32, mSY + ypos * 32, (setup.input[player_nr].use_joystick ? custom[i].text : getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1); } } static int input_player_nr = 0; void HandleSetupScreen_Input_Player(int step, int direction) { int old_player_nr = input_player_nr; int new_player_nr; new_player_nr = old_player_nr + step * direction; if (new_player_nr < 0) new_player_nr = 0; if (new_player_nr > MAX_PLAYERS - 1) new_player_nr = MAX_PLAYERS - 1; if (new_player_nr != old_player_nr) { input_player_nr = new_player_nr; drawPlayerSetupInputInfo(input_player_nr, FALSE); } } void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) { static int choice = 0; int x = 0; int y = choice; int pos_start = SETUPINPUT_SCREEN_POS_START; int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1; int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2; int pos_end = SETUPINPUT_SCREEN_POS_END; if (button == MB_MENU_INITIALIZE) { drawPlayerSetupInputInfo(input_player_nr, (choice == 2)); DrawCursorAndText_Setup(choice, TRUE); return; } else if (button == MB_MENU_LEAVE) { setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); InitJoysticks(); return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard input */ { if (dx && choice == 0) x = (dx < 0 ? 10 : 12); else if ((dx && choice == 1) || (dx == +1 && choice == 2) || (dx == -1 && choice == pos_end)) button = MB_MENU_CHOICE; else if (dy) y = choice + dy; if (y >= pos_empty1 && y <= pos_empty2) y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1); } if (y == 0 && dx != 0 && button) { HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1); } else if (IN_VIS_FIELD(x, y) && y >= pos_start && y <= pos_end && !(y >= pos_empty1 && y <= pos_empty2)) { if (button) { if (y != choice) { DrawCursorAndText_Setup(choice, FALSE); DrawCursorAndText_Setup(y, TRUE); drawPlayerSetupInputInfo(input_player_nr, (y == 2)); choice = y; } } else { if (y == 1) { char *device_name = setup.input[input_player_nr].joy.device_name; if (!setup.input[input_player_nr].use_joystick) { int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1); setJoystickDeviceToNr(device_name, new_device_nr); setup.input[input_player_nr].use_joystick = TRUE; } else { int device_nr = getJoystickNrFromDeviceName(device_name); int new_device_nr = device_nr + (dx >= 0 ? +1 : -1); if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS) setup.input[input_player_nr].use_joystick = FALSE; else setJoystickDeviceToNr(device_name, new_device_nr); } drawPlayerSetupInputInfo(input_player_nr, FALSE); } else if (y == 2) { if (setup.input[input_player_nr].use_joystick) { InitJoysticks(); CalibrateJoystick(input_player_nr); } else CustomizeKeyboard(input_player_nr); } else if (y == pos_end) { InitJoysticks(); FadeSetLeaveMenu(); setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } } } } void CustomizeKeyboard(int player_nr) { int i; int step_nr; boolean finished = FALSE; static struct SetupKeyboardInfo custom_key; static struct { Key *key; char *text; } customize_step[] = { { &custom_key.left, "Move Left" }, { &custom_key.right, "Move Right" }, { &custom_key.up, "Move Up" }, { &custom_key.down, "Move Down" }, { &custom_key.snap, "Snap Field" }, { &custom_key.drop, "Drop Element" } }; /* read existing key bindings from player setup */ custom_key = setup.input[player_nr].key; FadeSetEnterMenu(); FadeOut(REDRAW_FIELD); ClearField(); DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input"); #if 0 BackToFront(); InitAnimation(); #endif step_nr = 0; DrawText(mSX, mSY + (2 + 2 * step_nr) * 32, customize_step[step_nr].text, FONT_INPUT_1_ACTIVE); DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32, "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); #if 1 FadeIn(REDRAW_FIELD); InitAnimation(); #endif while (!finished) { if (PendingEvent()) /* got event */ { Event event; NextEvent(&event); switch (event.type) { case EVENT_KEYPRESS: { Key key = GetEventKey((KeyEvent *)&event, FALSE); if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6)) { if (key == KSYM_Escape) FadeSkipNextFadeIn(); finished = TRUE; break; } /* all keys configured -- wait for "Escape" or "Return" key */ if (step_nr == 6) break; /* press 'Enter' to keep the existing key binding */ if (key == KSYM_Return) key = *customize_step[step_nr].key; /* check if key already used */ for (i = 0; i < step_nr; i++) if (*customize_step[i].key == key) break; if (i < step_nr) break; /* got new key binding */ *customize_step[step_nr].key = key; DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, " ", FONT_VALUE_1); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(key), FONT_VALUE_1); step_nr++; /* un-highlight last query */ DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32, customize_step[step_nr - 1].text, FONT_MENU_1); DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32, "Key:", FONT_MENU_1); /* press 'Enter' to leave */ if (step_nr == 6) { DrawText(mSX + 16, mSY + 15 * 32 + 16, "Press Enter", FONT_TITLE_1); break; } /* query next key binding */ DrawText(mSX, mSY + (2 + 2 * step_nr) * 32, customize_step[step_nr].text, FONT_INPUT_1_ACTIVE); DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32, "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } DoAnimation(); BackToFront(); /* don't eat all CPU time */ Delay(10); } /* write new key bindings back to player setup */ setup.input[player_nr].key = custom_key; StopAnimation(); DrawSetupScreen_Input(); } static boolean CalibrateJoystickMain(int player_nr) { int new_joystick_xleft = JOYSTICK_XMIDDLE; int new_joystick_xright = JOYSTICK_XMIDDLE; int new_joystick_yupper = JOYSTICK_YMIDDLE; int new_joystick_ylower = JOYSTICK_YMIDDLE; int new_joystick_xmiddle, new_joystick_ymiddle; int joystick_fd = joystick.fd[player_nr]; int x, y, last_x, last_y, xpos = 8, ypos = 3; boolean check[3][3]; int check_remaining = 3 * 3; int joy_x, joy_y; int joy_value; int result = -1; if (joystick.status == JOYSTICK_NOT_AVAILABLE) return FALSE; if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) return FALSE; FadeSetEnterMenu(); FadeOut(REDRAW_FIELD); ClearField(); for (y = 0; y < 3; y++) { for (x = 0; x < 3; x++) { DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0); check[x][y] = FALSE; } } DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick"); DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions"); DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls"); DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,"); DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick"); DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and"); DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!"); joy_value = Joystick(player_nr); last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0); last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0); /* eventually uncalibrated center position (joystick could be uncentered) */ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) return FALSE; new_joystick_xmiddle = joy_x; new_joystick_ymiddle = joy_y; DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0); FadeIn(REDRAW_FIELD); while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */ InitAnimation(); while (result < 0) { if (PendingEvent()) /* got event */ { Event event; NextEvent(&event); switch (event.type) { case EVENT_KEYPRESS: switch (GetEventKey((KeyEvent *)&event, TRUE)) { case KSYM_Return: if (check_remaining == 0) result = 1; break; case KSYM_Escape: FadeSkipNextFadeIn(); result = 0; break; default: break; } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) return FALSE; new_joystick_xleft = MIN(new_joystick_xleft, joy_x); new_joystick_xright = MAX(new_joystick_xright, joy_x); new_joystick_yupper = MIN(new_joystick_yupper, joy_y); new_joystick_ylower = MAX(new_joystick_ylower, joy_y); setup.input[player_nr].joy.xleft = new_joystick_xleft; setup.input[player_nr].joy.yupper = new_joystick_yupper; setup.input[player_nr].joy.xright = new_joystick_xright; setup.input[player_nr].joy.ylower = new_joystick_ylower; setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle; setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle; CheckJoystickData(); joy_value = Joystick(player_nr); if (joy_value & JOY_BUTTON && check_remaining == 0) result = 1; x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0); y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0); if (x != last_x || y != last_y) { DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0); DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0); last_x = x; last_y = y; if (check_remaining > 0 && !check[x+1][y+1]) { check[x+1][y+1] = TRUE; check_remaining--; } #if 0 #ifdef DEBUG printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n", setup.input[player_nr].joy.xleft, setup.input[player_nr].joy.xmiddle, setup.input[player_nr].joy.xright); printf("UP / MIDDLE / DOWN == %d / %d / %d\n", setup.input[player_nr].joy.yupper, setup.input[player_nr].joy.ymiddle, setup.input[player_nr].joy.ylower); #endif #endif } DoAnimation(); BackToFront(); /* don't eat all CPU time */ Delay(10); } /* calibrated center position (joystick should now be centered) */ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) return FALSE; new_joystick_xmiddle = joy_x; new_joystick_ymiddle = joy_y; StopAnimation(); #if 0 DrawSetupScreen_Input(); #endif /* wait until the last pressed button was released */ while (Joystick(player_nr) & JOY_BUTTON) { if (PendingEvent()) /* got event */ { Event event; NextEvent(&event); HandleOtherEvents(&event); Delay(10); } } return TRUE; } void CalibrateJoystick(int player_nr) { if (!CalibrateJoystickMain(player_nr)) { char *device_name = setup.input[player_nr].joy.device_name; int nr = getJoystickNrFromDeviceName(device_name) + 1; int xpos = mSX - SX; int ypos = mSY - SY; ClearField(); DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr); DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! "); BackToFront(); Delay(2000); /* show error message for a short time */ ClearEventQueue(); } #if 1 DrawSetupScreen_Input(); #endif } void DrawSetupScreen() { DeactivateJoystick(); SetMainBackgroundImage(IMG_BACKGROUND_SETUP); if (setup_mode == SETUP_MODE_INPUT) DrawSetupScreen_Input(); else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) DrawChooseTree(&game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE) DrawChooseTree(&screen_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) DrawChooseTree(&scroll_delay_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) DrawChooseTree(&artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) DrawChooseTree(&artwork.snd_current); else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC) DrawChooseTree(&artwork.mus_current); else DrawSetupScreen_Generic(); PlayMenuSound(); PlayMenuMusic(); } void RedrawSetupScreenAfterFullscreenToggle() { if (setup_mode == SETUP_MODE_GRAPHICS) DrawSetupScreen(); } void HandleSetupScreen(int mx, int my, int dx, int dy, int button) { if (setup_mode == SETUP_MODE_INPUT) HandleSetupScreen_Input(mx, my, dx, dy, button); else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) HandleChooseTree(mx, my, dx, dy, button, &game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE) HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current); else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC) HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current); else HandleSetupScreen_Generic(mx, my, dx, dy, button); DoAnimation(); } void HandleGameActions() { if (game_status != GAME_MODE_PLAYING) return; GameActions(); /* main game loop */ if (tape.auto_play && !tape.playing) AutoPlayTape(); /* continue automatically playing next tape */ } /* ---------- new screen button stuff -------------------------------------- */ static void getScreenMenuButtonPos(int *x, int *y, int gadget_id) { switch (gadget_id) { #if 1 case SCREEN_CTRL_ID_PREV_LEVEL: *x = mSX + menu.main.button.prev_level.x; *y = mSY + menu.main.button.prev_level.y; break; case SCREEN_CTRL_ID_NEXT_LEVEL: *x = mSX + menu.main.button.next_level.x; *y = mSY + menu.main.button.next_level.y; break; #else case SCREEN_CTRL_ID_PREV_LEVEL: *x = mSX + TILEX * getPrevlevelButtonPos(); *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1); break; case SCREEN_CTRL_ID_NEXT_LEVEL: *x = mSX + TILEX * getNextLevelButtonPos(); *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1); break; #endif case SCREEN_CTRL_ID_PREV_PLAYER: *x = mSX + TILEX * 10; *y = mSY + TILEY * MENU_SCREEN_START_YPOS; break; case SCREEN_CTRL_ID_NEXT_PLAYER: *x = mSX + TILEX * 12; *y = mSY + TILEY * MENU_SCREEN_START_YPOS; break; default: Error(ERR_EXIT, "unknown gadget ID %d", gadget_id); } } static struct { int gfx_unpressed, gfx_pressed; void (*get_gadget_position)(int *, int *, int); int gadget_id; int screen_mask; char *infotext; } menubutton_info[NUM_SCREEN_MENUBUTTONS] = { { IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_PREV_LEVEL, SCREEN_MASK_MAIN, "last level" }, { IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_NEXT_LEVEL, SCREEN_MASK_MAIN, "next level" }, { IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_PREV_PLAYER, SCREEN_MASK_INPUT, "last player" }, { IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_NEXT_PLAYER, SCREEN_MASK_INPUT, "next player" }, }; static struct { int gfx_unpressed, gfx_pressed; int x, y; int gadget_id; char *infotext; } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] = { { IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS, #endif SCREEN_CTRL_ID_SCROLL_UP, "scroll up" }, { IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE, #if 1 -1, -1, /* these values are not constant, but can change at runtime */ #else SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS, #endif SCREEN_CTRL_ID_SCROLL_DOWN, "scroll down" } }; static struct { #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) Bitmap **gfx_unpressed, **gfx_pressed; #else int gfx_unpressed, gfx_pressed; #endif int x, y; int width, height; int type; int gadget_id; char *infotext; } scrollbar_info[NUM_SCREEN_SCROLLBARS] = { { #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) &scrollbar_bitmap[0], &scrollbar_bitmap[1], #else IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE, #endif #if 1 -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ #else SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS, SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE, #endif GD_TYPE_SCROLLBAR_VERTICAL, SCREEN_CTRL_ID_SCROLL_VERTICAL, "scroll level series vertically" } }; static void CreateScreenMenubuttons() { struct GadgetInfo *gi; unsigned long event_mask; int i; for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; int gfx_unpressed, gfx_pressed; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; int id = menubutton_info[i].gadget_id; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; menubutton_info[i].get_gadget_position(&x, &y, id); width = SC_MENUBUTTON_XSIZE; height = SC_MENUBUTTON_YSIZE; gfx_unpressed = menubutton_info[i].gfx_unpressed; gfx_pressed = menubutton_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, menubutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } static void CreateScreenScrollbuttons() { struct GadgetInfo *gi; unsigned long event_mask; int i; /* these values are not constant, but can change at runtime */ scrollbutton_info[0].x = SC_SCROLL_UP_XPOS; scrollbutton_info[0].y = SC_SCROLL_UP_YPOS; scrollbutton_info[1].x = SC_SCROLL_DOWN_XPOS; scrollbutton_info[1].y = SC_SCROLL_DOWN_YPOS; for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; int gfx_unpressed, gfx_pressed; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; int id = scrollbutton_info[i].gadget_id; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset; y = mSY + scrollbutton_info[i].y; width = SC_SCROLLBUTTON_XSIZE; height = SC_SCROLLBUTTON_YSIZE; if (id == SCREEN_CTRL_ID_SCROLL_DOWN) y = mSY + (SC_SCROLL_VERTICAL_YPOS + (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE); gfx_unpressed = scrollbutton_info[i].gfx_unpressed; gfx_pressed = scrollbutton_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } static void CreateScreenScrollbars() { int i; /* these values are not constant, but can change at runtime */ scrollbar_info[0].x = SC_SCROLL_VERTICAL_XPOS; scrollbar_info[0].y = SC_SCROLL_VERTICAL_YPOS; scrollbar_info[0].width = SC_SCROLL_VERTICAL_XSIZE; scrollbar_info[0].height = SC_SCROLL_VERTICAL_YSIZE; for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) int gfx_unpressed, gfx_pressed; #endif int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; struct GadgetInfo *gi; int items_max, items_visible, item_position; unsigned long event_mask; int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; int id = scrollbar_info[i].gadget_id; event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset; y = mSY + scrollbar_info[i].y; width = scrollbar_info[i].width; height = scrollbar_info[i].height; if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL) height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE; items_max = num_page_entries; items_visible = num_page_entries; item_position = 0; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed; gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed; gd_x1 = 0; gd_y1 = 0; gd_x2 = 0; gd_y2 = 0; #else gfx_unpressed = scrollbar_info[i].gfx_unpressed; gfx_pressed = scrollbar_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; #endif gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbar_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, scrollbar_info[i].type, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, #if 1 GDI_WHEEL_AREA_X, SX, GDI_WHEEL_AREA_Y, SY, GDI_WHEEL_AREA_WIDTH, SXSIZE, GDI_WHEEL_AREA_HEIGHT, SYSIZE, #else GDI_WHEEL_AREA_X, 0, GDI_WHEEL_AREA_Y, 0, GDI_WHEEL_AREA_WIDTH, WIN_XSIZE, GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE, #endif GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } void CreateScreenGadgets() { int last_game_status = game_status; /* save current game status */ #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) int i; for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++) { scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH); /* copy pointers to clip mask and GC */ scrollbar_bitmap[i]->clip_mask = graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask; scrollbar_bitmap[i]->stored_clip_gc = graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc; BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap, scrollbar_bitmap[i], graphic_info[IMG_MENU_SCROLLBAR + i].src_x, graphic_info[IMG_MENU_SCROLLBAR + i].src_y, TILEX, TILEY, 0, 0); } #endif CreateScreenMenubuttons(); #if 0 /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */ game_status = GAME_MODE_LEVELS; #endif CreateScreenScrollbuttons(); CreateScreenScrollbars(); game_status = last_game_status; /* restore current game status */ } void FreeScreenGadgets() { int i; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++) { /* prevent freeing clip mask and GC twice */ scrollbar_bitmap[i]->clip_mask = None; scrollbar_bitmap[i]->stored_clip_gc = None; FreeBitmap(scrollbar_bitmap[i]); } #endif for (i = 0; i < NUM_SCREEN_GADGETS; i++) FreeGadget(screen_gadget[i]); } void MapScreenMenuGadgets(int screen_mask) { int i; for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++) if (screen_mask & menubutton_info[i].screen_mask) MapGadget(screen_gadget[menubutton_info[i].gadget_id]); } void MapScreenTreeGadgets(TreeInfo *ti) { int num_entries = numTreeInfoInGroup(ti); int i; if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN) return; for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++) MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]); for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++) MapGadget(screen_gadget[scrollbar_info[i].gadget_id]); } static void HandleScreenGadgets(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 SCREEN_CTRL_ID_PREV_LEVEL: HandleMainMenu_SelectLevel(step, -1); break; case SCREEN_CTRL_ID_NEXT_LEVEL: HandleMainMenu_SelectLevel(step, +1); break; case SCREEN_CTRL_ID_PREV_PLAYER: HandleSetupScreen_Input_Player(step, -1); break; case SCREEN_CTRL_ID_NEXT_PLAYER: HandleSetupScreen_Input_Player(step, +1); break; case SCREEN_CTRL_ID_SCROLL_UP: if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_DOWN: if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_VERTICAL: if (game_status == GAME_MODE_LEVELS) HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); break; default: break; } } rocksndiamonds-3.3.0.1+dfsg1/src/init.c0000644000175000017500000054515011363674530016546 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * init.c * ***********************************************************/ #include "libgame/libgame.h" #include "init.h" #include "events.h" #include "screens.h" #include "editor.h" #include "game.h" #include "tape.h" #include "tools.h" #include "files.h" #include "network.h" #include "netserv.h" #include "cartoons.h" #include "config.h" #include "conf_e2g.c" /* include auto-generated data structure definitions */ #include "conf_esg.c" /* include auto-generated data structure definitions */ #include "conf_e2s.c" /* include auto-generated data structure definitions */ #include "conf_fnt.c" /* include auto-generated data structure definitions */ #include "conf_g2s.c" /* include auto-generated data structure definitions */ #include "conf_g2m.c" /* include auto-generated data structure definitions */ #include "conf_act.c" /* include auto-generated data structure definitions */ #define CONFIG_TOKEN_FONT_INITIAL "font.initial" #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy" #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS]; static struct GraphicInfo anim_initial; static int copy_properties[][5] = { { EL_BUG, EL_BUG_LEFT, EL_BUG_RIGHT, EL_BUG_UP, EL_BUG_DOWN }, { EL_SPACESHIP, EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT, EL_SPACESHIP_UP, EL_SPACESHIP_DOWN }, { EL_BD_BUTTERFLY, EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT, EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN }, { EL_BD_FIREFLY, EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT, EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN }, { EL_PACMAN, EL_PACMAN_LEFT, EL_PACMAN_RIGHT, EL_PACMAN_UP, EL_PACMAN_DOWN }, { EL_YAMYAM, EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT, EL_YAMYAM_UP, EL_YAMYAM_DOWN }, { EL_MOLE, EL_MOLE_LEFT, EL_MOLE_RIGHT, EL_MOLE_UP, EL_MOLE_DOWN }, { -1, -1, -1, -1, -1 } }; static void print_timestamp_ext(char *message, char *mode) { #if DEBUG #if DEBUG_PRINT_INIT_TIMESTAMPS static char *debug_message = NULL; static char *last_message = NULL; static int counter_nr = 0; int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH; checked_free(debug_message); debug_message = getStringCat3(mode, " ", message); if (strEqual(mode, "INIT")) { debug_print_timestamp(counter_nr, NULL); if (counter_nr + 1 < max_depth) debug_print_timestamp(counter_nr, debug_message); counter_nr++; debug_print_timestamp(counter_nr, NULL); } else if (strEqual(mode, "DONE")) { counter_nr--; if (counter_nr + 1 < max_depth || (counter_nr == 0 && max_depth == 1)) { last_message = message; if (counter_nr == 0 && max_depth == 1) { checked_free(debug_message); debug_message = getStringCat3("TIME", " ", message); } debug_print_timestamp(counter_nr, debug_message); } } else if (!strEqual(mode, "TIME") || !strEqual(message, last_message)) { if (counter_nr < max_depth) debug_print_timestamp(counter_nr, debug_message); } #endif #endif } static void print_timestamp_init(char *message) { print_timestamp_ext(message, "INIT"); } static void print_timestamp_time(char *message) { print_timestamp_ext(message, "TIME"); } static void print_timestamp_done(char *message) { print_timestamp_ext(message, "DONE"); } void DrawInitAnim() { struct GraphicInfo *graphic_info_last = graphic_info; int graphic = 0; static unsigned long action_delay = 0; unsigned long action_delay_value = GameFrameDelay; int sync_frame = FrameCounter; int x, y; if (game_status != GAME_MODE_LOADING) return; if (anim_initial.bitmap == NULL || window == NULL) return; if (!DelayReached(&action_delay, action_delay_value)) return; #if 0 { static unsigned long last_counter = -1; unsigned long current_counter = Counter(); unsigned long delay = current_counter - last_counter; if (last_counter != -1 && delay > action_delay_value + 5) printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay); last_counter = current_counter; } #endif x = ALIGNED_TEXT_XPOS(&init_last.busy); y = ALIGNED_TEXT_YPOS(&init_last.busy); graphic_info = &anim_initial; /* graphic == 0 => anim_initial */ #if 0 { static boolean done = FALSE; // if (!done) printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n", init.busy.x, init.busy.y, init.busy.align, init.busy.valign, x, y, graphic_info[graphic].width, graphic_info[graphic].height, sync_frame, anim_initial.anim_delay); done = TRUE; } #endif if (sync_frame % anim_initial.anim_delay == 0) { #if 1 Bitmap *src_bitmap; int src_x, src_y; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int frame = getGraphicAnimationFrame(graphic, sync_frame); getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y); #else /* !!! this can only draw TILEX/TILEY size animations !!! */ DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING); #endif } graphic_info = graphic_info_last; FrameCounter++; } void FreeGadgets() { FreeLevelEditorGadgets(); FreeGameButtons(); FreeTapeButtons(); FreeToolButtons(); FreeScreenGadgets(); } void InitGadgets() { static boolean gadgets_initialized = FALSE; if (gadgets_initialized) FreeGadgets(); CreateLevelEditorGadgets(); CreateGameButtons(); CreateTapeButtons(); CreateToolButtons(); CreateScreenGadgets(); InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting); gadgets_initialized = TRUE; } inline void InitElementSmallImagesScaledUp(int graphic) { #if 0 struct FileInfo *fi = getImageListEntryFromImageID(graphic); printf("::: '%s' -> '%s'\n", fi->token, fi->filename); #endif CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor); } void InitElementSmallImages() { static int special_graphics[] = { IMG_EDITOR_ELEMENT_BORDER, IMG_EDITOR_ELEMENT_BORDER_INPUT, IMG_EDITOR_CASCADE_LIST, IMG_EDITOR_CASCADE_LIST_ACTIVE, -1 }; struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i; /* initialize normal images from static configuration */ for (i = 0; element_to_graphic[i].element > -1; i++) InitElementSmallImagesScaledUp(element_to_graphic[i].graphic); /* initialize special images from static configuration */ for (i = 0; element_to_special_graphic[i].element > -1; i++) InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic); /* initialize images from dynamic configuration (may be elements or other) */ for (i = 0; i < num_property_mappings; i++) InitElementSmallImagesScaledUp(property_mapping[i].artwork_index); /* initialize special images from above list (non-element images) */ for (i = 0; special_graphics[i] > -1; i++) InitElementSmallImagesScaledUp(special_graphics[i]); } void InitScaledImages() { int i; /* scale normal images from static configuration, if not already scaled */ for (i = 0; i < NUM_IMAGE_FILES; i++) ScaleImage(i, graphic_info[i].scale_up_factor); } #if 1 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */ void SetBitmaps_EM(Bitmap **em_bitmap) { em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap; em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap; } #endif #if 0 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */ void SetBitmaps_SP(Bitmap **sp_bitmap) { *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap; } #endif static int getFontBitmapID(int font_nr) { int special = -1; /* (special case: do not use special font for GAME_MODE_LOADING) */ if (game_status >= GAME_MODE_TITLE_INITIAL && game_status <= GAME_MODE_PSEUDO_PREVIEW) special = game_status; else if (game_status == GAME_MODE_PSEUDO_TYPENAME) special = GFX_SPECIAL_ARG_MAIN; #if 0 else if (game_status == GAME_MODE_PLAYING) special = GFX_SPECIAL_ARG_DOOR; #endif #if 0 if (special != -1) { printf("%s%s\n", font_info[font_nr].token_name, special_suffix_info[special].suffix); } #endif if (special != -1) return font_info[font_nr].special_bitmap_id[special]; else return font_nr; } static int getFontFromToken(char *token) { #if 1 char *value = getHashEntry(font_token_hash, token); if (value != NULL) return atoi(value); #else int i; /* !!! OPTIMIZE THIS BY USING HASH !!! */ for (i = 0; i < NUM_FONTS; i++) if (strEqual(token, font_info[i].token_name)) return i; #endif /* if font not found, use reliable default value */ return FONT_INITIAL_1; } void InitFontGraphicInfo() { static struct FontBitmapInfo *font_bitmap_info = NULL; struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int num_font_bitmaps = NUM_FONTS; int i, j; if (graphic_info == NULL) /* still at startup phase */ { InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID, getFontFromToken); return; } /* ---------- initialize font graphic definitions ---------- */ /* always start with reliable default values (normal font graphics) */ for (i = 0; i < NUM_FONTS; i++) font_info[i].graphic = IMG_FONT_INITIAL_1; /* initialize normal font/graphic mapping from static configuration */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; if (special != -1) continue; font_info[font_nr].graphic = graphic; } /* always start with reliable default values (special font graphics) */ for (i = 0; i < NUM_FONTS; i++) { for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { font_info[i].special_graphic[j] = font_info[i].graphic; font_info[i].special_bitmap_id[j] = i; } } /* initialize special font/graphic mapping from static configuration */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; int base_graphic = font2baseimg(font_nr); if (IS_SPECIAL_GFX_ARG(special)) { boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; boolean special_cloned = (graphic_info[graphic].clone_from != -1); /* if the base font ("font.title_1", for example) has been redefined, but not the special font ("font.title_1.LEVELS", for example), do not use an existing (in this case considered obsolete) special font anymore, but use the automatically determined default font */ /* special case: cloned special fonts must be explicitly redefined, but are not automatically redefined by redefining base font */ if (base_redefined && !special_redefined && !special_cloned) continue; font_info[font_nr].special_graphic[special] = graphic; font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps; num_font_bitmaps++; } } /* initialize special font/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; if (font_nr < 0) continue; if (IS_SPECIAL_GFX_ARG(special)) { font_info[font_nr].special_graphic[special] = graphic; font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps; num_font_bitmaps++; } } /* correct special font/graphic mapping for cloned fonts for downwards compatibility of PREVIEW fonts -- this is only needed for implicit redefinition of special font by redefined base font, and only if other fonts are cloned from this special font (like in the "Zelda" level set) */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; if (IS_SPECIAL_GFX_ARG(special)) { boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; boolean special_cloned = (graphic_info[graphic].clone_from != -1); if (special_cloned && !special_redefined) { int j; for (j = 0; font_to_graphic[j].font_nr > -1; j++) { int font_nr2 = font_to_graphic[j].font_nr; int special2 = font_to_graphic[j].special; int graphic2 = font_to_graphic[j].graphic; if (IS_SPECIAL_GFX_ARG(special2) && graphic2 == graphic_info[graphic].clone_from) { font_info[font_nr].special_graphic[special] = font_info[font_nr2].special_graphic[special2]; font_info[font_nr].special_bitmap_id[special] = font_info[font_nr2].special_bitmap_id[special2]; } } } } } /* reset non-redefined ".active" font graphics if normal font is redefined */ /* (this different treatment is needed because normal and active fonts are independently defined ("active" is not a property of font definitions!) */ for (i = 0; i < NUM_FONTS; i++) { int font_nr_base = i; int font_nr_active = FONT_ACTIVE(font_nr_base); /* check only those fonts with exist as normal and ".active" variant */ if (font_nr_base != font_nr_active) { int base_graphic = font_info[font_nr_base].graphic; int active_graphic = font_info[font_nr_active].graphic; boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean active_redefined = getImageListEntryFromImageID(active_graphic)->redefined; /* if the base font ("font.menu_1", for example) has been redefined, but not the active font ("font.menu_1.active", for example), do not use an existing (in this case considered obsolete) active font anymore, but use the automatically determined default font */ if (base_redefined && !active_redefined) font_info[font_nr_active].graphic = base_graphic; /* now also check each "special" font (which may be the same as above) */ for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { int base_graphic = font_info[font_nr_base].special_graphic[j]; int active_graphic = font_info[font_nr_active].special_graphic[j]; boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean active_redefined = getImageListEntryFromImageID(active_graphic)->redefined; /* same as above, but check special graphic definitions, for example: redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */ if (base_redefined && !active_redefined) { font_info[font_nr_active].special_graphic[j] = font_info[font_nr_base].special_graphic[j]; font_info[font_nr_active].special_bitmap_id[j] = font_info[font_nr_base].special_bitmap_id[j]; } } } } /* ---------- initialize font bitmap array ---------- */ if (font_bitmap_info != NULL) FreeFontInfo(font_bitmap_info); font_bitmap_info = checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo)); /* ---------- initialize font bitmap definitions ---------- */ for (i = 0; i < NUM_FONTS; i++) { if (i < NUM_INITIAL_FONTS) { font_bitmap_info[i] = font_initial[i]; continue; } for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { int font_bitmap_id = font_info[i].special_bitmap_id[j]; int graphic = font_info[i].special_graphic[j]; /* set 'graphic_info' for font entries, if uninitialized (guessed) */ if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT) { graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT; graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE; } /* copy font relevant information from graphics information */ font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap; font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x; font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y; font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width; font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height; font_bitmap_info[font_bitmap_id].draw_xoffset = graphic_info[graphic].draw_xoffset; font_bitmap_info[font_bitmap_id].draw_yoffset = graphic_info[graphic].draw_yoffset; font_bitmap_info[font_bitmap_id].num_chars = graphic_info[graphic].anim_frames; font_bitmap_info[font_bitmap_id].num_chars_per_line = graphic_info[graphic].anim_frames_per_line; } } InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID, getFontFromToken); } void InitElementGraphicInfo() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i, act, dir; if (graphic_info == NULL) /* still at startup phase */ return; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { element_info[i].graphic[act] = -1; element_info[i].crumbled[act] = -1; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { element_info[i].direction_graphic[act][dir] = -1; element_info[i].direction_crumbled[act][dir] = -1; } } } UPDATE_BUSY_STATE(); /* initialize normal element/graphic mapping from static configuration */ for (i = 0; element_to_graphic[i].element > -1; i++) { int element = element_to_graphic[i].element; int action = element_to_graphic[i].action; int direction = element_to_graphic[i].direction; boolean crumbled = element_to_graphic[i].crumbled; int graphic = element_to_graphic[i].graphic; int base_graphic = el2baseimg(element); if (graphic_info[graphic].bitmap == NULL) continue; if ((action > -1 || direction > -1 || crumbled == TRUE) && base_graphic != -1) { boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean act_dir_redefined = getImageListEntryFromImageID(graphic)->redefined; /* if the base graphic ("emerald", for example) has been redefined, but not the action graphic ("emerald.falling", for example), do not use an existing (in this case considered obsolete) action graphic anymore, but use the automatically determined default graphic */ if (base_redefined && !act_dir_redefined) continue; } if (action < 0) action = ACTION_DEFAULT; if (crumbled) { if (direction > -1) element_info[element].direction_crumbled[action][direction] = graphic; else element_info[element].crumbled[action] = graphic; } else { if (direction > -1) element_info[element].direction_graphic[action][direction] = graphic; else element_info[element].graphic[action] = graphic; } } /* initialize normal element/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int direction = property_mapping[i].ext2_index; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; boolean crumbled = FALSE; #if 0 if ((element == EL_EM_DYNAMITE || element == EL_EM_DYNAMITE_ACTIVE) && action == ACTION_ACTIVE && (special == GFX_SPECIAL_ARG_EDITOR || special == GFX_SPECIAL_ARG_PANEL)) printf("::: DYNAMIC: %d, %d, %d -> %d\n", element, action, special, graphic); #endif if (special == GFX_SPECIAL_ARG_CRUMBLED) { special = -1; crumbled = TRUE; } if (graphic_info[graphic].bitmap == NULL) continue; if (element >= MAX_NUM_ELEMENTS || special != -1) continue; if (action < 0) action = ACTION_DEFAULT; if (crumbled) { if (direction < 0) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[element].direction_crumbled[action][dir] = -1; if (direction > -1) element_info[element].direction_crumbled[action][direction] = graphic; else element_info[element].crumbled[action] = graphic; } else { if (direction < 0) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[element].direction_graphic[action][dir] = -1; if (direction > -1) element_info[element].direction_graphic[action][direction] = graphic; else element_info[element].graphic[action] = graphic; } } /* now copy all graphics that are defined to be cloned from other graphics */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int graphic = element_info[i].graphic[ACTION_DEFAULT]; int crumbled_like, diggable_like; if (graphic == -1) continue; crumbled_like = graphic_info[graphic].crumbled_like; diggable_like = graphic_info[graphic].diggable_like; if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1) { for (act = 0; act < NUM_ACTIONS; act++) element_info[i].crumbled[act] = element_info[crumbled_like].crumbled[act]; for (act = 0; act < NUM_ACTIONS; act++) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[i].direction_crumbled[act][dir] = element_info[crumbled_like].direction_crumbled[act][dir]; } if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1) { element_info[i].graphic[ACTION_DIGGING] = element_info[diggable_like].graphic[ACTION_DIGGING]; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[i].direction_graphic[ACTION_DIGGING][dir] = element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir]; } } #if 1 /* set hardcoded definitions for some runtime elements without graphic */ element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD; #endif #if 1 /* set hardcoded definitions for some internal elements without graphic */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_EDITOR_CASCADE_INACTIVE(i)) element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST; else if (IS_EDITOR_CASCADE_ACTIVE(i)) element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE; } #endif /* now set all undefined/invalid graphics to -1 to set to default after it */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { int graphic; graphic = element_info[i].graphic[act]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].graphic[act] = -1; graphic = element_info[i].crumbled[act]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].crumbled[act] = -1; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { graphic = element_info[i].direction_graphic[act][dir]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].direction_graphic[act][dir] = -1; graphic = element_info[i].direction_crumbled[act][dir]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].direction_crumbled[act][dir] = -1; } } } UPDATE_BUSY_STATE(); /* adjust graphics with 2nd tile for movement according to direction (do this before correcting '-1' values to minimize calculations) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { int graphic = element_info[i].direction_graphic[act][dir]; int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir); if (act == ACTION_FALLING) /* special case */ graphic = element_info[i].graphic[act]; if (graphic != -1 && graphic_info[graphic].double_movement && graphic_info[graphic].swap_double_tiles != 0) { struct GraphicInfo *g = &graphic_info[graphic]; int src_x_front = g->src_x; int src_y_front = g->src_y; int src_x_back = g->src_x + g->offset2_x; int src_y_back = g->src_y + g->offset2_y; boolean frames_are_ordered_diagonally = (g->offset_x != 0 && g->offset_y != 0); boolean front_is_left_or_upper = (src_x_front < src_x_back || src_y_front < src_y_back); boolean swap_movement_tiles_always = (g->swap_double_tiles == 1); boolean swap_movement_tiles_autodetected = (!frames_are_ordered_diagonally && ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) || (move_dir == MV_BIT_UP && !front_is_left_or_upper) || (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) || (move_dir == MV_BIT_DOWN && front_is_left_or_upper))); Bitmap *dummy; /* swap frontside and backside graphic tile coordinates, if needed */ if (swap_movement_tiles_always || swap_movement_tiles_autodetected) { /* get current (wrong) backside tile coordinates */ getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back, TRUE); /* set frontside tile coordinates to backside tile coordinates */ g->src_x = src_x_back; g->src_y = src_y_back; /* invert tile offset to point to new backside tile coordinates */ g->offset2_x *= -1; g->offset2_y *= -1; /* do not swap front and backside tiles again after correction */ g->swap_double_tiles = 0; } } } } } UPDATE_BUSY_STATE(); /* now set all '-1' values to element specific default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int default_graphic = element_info[i].graphic[ACTION_DEFAULT]; int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT]; int default_direction_graphic[NUM_DIRECTIONS_FULL]; int default_direction_crumbled[NUM_DIRECTIONS_FULL]; if (default_graphic == -1) default_graphic = IMG_UNKNOWN; #if 1 if (default_crumbled == -1) default_crumbled = default_graphic; #else /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */ if (default_crumbled == -1) default_crumbled = IMG_EMPTY; #endif for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { default_direction_graphic[dir] = element_info[i].direction_graphic[ACTION_DEFAULT][dir]; default_direction_crumbled[dir] = element_info[i].direction_crumbled[ACTION_DEFAULT][dir]; if (default_direction_graphic[dir] == -1) default_direction_graphic[dir] = default_graphic; #if 1 if (default_direction_crumbled[dir] == -1) default_direction_crumbled[dir] = default_direction_graphic[dir]; #else /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */ if (default_direction_crumbled[dir] == -1) default_direction_crumbled[dir] = default_crumbled; #endif } for (act = 0; act < NUM_ACTIONS; act++) { boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) || (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) || (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING)); boolean act_turning = (act == ACTION_TURNING_FROM_LEFT || act == ACTION_TURNING_FROM_RIGHT || act == ACTION_TURNING_FROM_UP || act == ACTION_TURNING_FROM_DOWN); /* generic default action graphic (defined by "[default]" directive) */ int default_action_graphic = element_info[EL_DEFAULT].graphic[act]; int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act]; int default_remove_graphic = IMG_EMPTY; if (act_remove && default_action_graphic != -1) default_remove_graphic = default_action_graphic; /* look for special default action graphic (classic game specific) */ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act]; if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act]; #if 1 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */ /* !!! make this better !!! */ if (i == EL_EMPTY_SPACE) { default_action_graphic = element_info[EL_DEFAULT].graphic[act]; default_action_crumbled = element_info[EL_DEFAULT].crumbled[act]; } #endif if (default_action_graphic == -1) default_action_graphic = default_graphic; #if 1 if (default_action_crumbled == -1) default_action_crumbled = default_action_graphic; #else /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */ if (default_action_crumbled == -1) default_action_crumbled = default_crumbled; #endif for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { /* use action graphic as the default direction graphic, if undefined */ int default_action_direction_graphic = element_info[i].graphic[act]; int default_action_direction_crumbled = element_info[i].crumbled[act]; /* no graphic for current action -- use default direction graphic */ if (default_action_direction_graphic == -1) default_action_direction_graphic = (act_remove ? default_remove_graphic : act_turning ? element_info[i].direction_graphic[ACTION_TURNING][dir] : default_action_graphic != default_graphic ? default_action_graphic : default_direction_graphic[dir]); if (element_info[i].direction_graphic[act][dir] == -1) element_info[i].direction_graphic[act][dir] = default_action_direction_graphic; #if 1 if (default_action_direction_crumbled == -1) default_action_direction_crumbled = element_info[i].direction_graphic[act][dir]; #else if (default_action_direction_crumbled == -1) default_action_direction_crumbled = (act_remove ? default_remove_graphic : act_turning ? element_info[i].direction_crumbled[ACTION_TURNING][dir] : default_action_crumbled != default_crumbled ? default_action_crumbled : default_direction_crumbled[dir]); #endif if (element_info[i].direction_crumbled[act][dir] == -1) element_info[i].direction_crumbled[act][dir] = default_action_direction_crumbled; } /* no graphic for this specific action -- use default action graphic */ if (element_info[i].graphic[act] == -1) element_info[i].graphic[act] = (act_remove ? default_remove_graphic : act_turning ? element_info[i].graphic[ACTION_TURNING] : default_action_graphic); #if 1 if (element_info[i].crumbled[act] == -1) element_info[i].crumbled[act] = element_info[i].graphic[act]; #else if (element_info[i].crumbled[act] == -1) element_info[i].crumbled[act] = (act_remove ? default_remove_graphic : act_turning ? element_info[i].crumbled[ACTION_TURNING] : default_action_crumbled); #endif } } UPDATE_BUSY_STATE(); #if 0 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */ /* set animation mode to "none" for each graphic with only 1 frame */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { int graphic = element_info[i].graphic[act]; int crumbled = element_info[i].crumbled[act]; if (graphic_info[graphic].anim_frames == 1) graphic_info[graphic].anim_mode = ANIM_NONE; if (graphic_info[crumbled].anim_frames == 1) graphic_info[crumbled].anim_mode = ANIM_NONE; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { graphic = element_info[i].direction_graphic[act][dir]; crumbled = element_info[i].direction_crumbled[act][dir]; if (graphic_info[graphic].anim_frames == 1) graphic_info[graphic].anim_mode = ANIM_NONE; if (graphic_info[crumbled].anim_frames == 1) graphic_info[crumbled].anim_mode = ANIM_NONE; } } } #endif #if 0 #if DEBUG if (options.verbose) { for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN && i != EL_UNKNOWN) Error(ERR_INFO, "warning: no graphic for element '%s' (%d)", element_info[i].token_name, i); } #endif #endif } void InitElementSpecialGraphicInfo() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i, j; /* always start with reliable default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) element_info[i].special_graphic[j] = element_info[i].graphic[ACTION_DEFAULT]; /* initialize special element/graphic mapping from static configuration */ for (i = 0; element_to_special_graphic[i].element > -1; i++) { int element = element_to_special_graphic[i].element; int special = element_to_special_graphic[i].special; int graphic = element_to_special_graphic[i].graphic; int base_graphic = el2baseimg(element); boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; #if 0 if ((element == EL_EM_DYNAMITE || element == EL_EM_DYNAMITE_ACTIVE) && (special == GFX_SPECIAL_ARG_EDITOR || special == GFX_SPECIAL_ARG_PANEL)) printf("::: SPECIAL STATIC: %d, %d -> %d\n", element, special, graphic); #endif /* if the base graphic ("emerald", for example) has been redefined, but not the special graphic ("emerald.EDITOR", for example), do not use an existing (in this case considered obsolete) special graphic anymore, but use the automatically created (down-scaled) graphic */ if (base_redefined && !special_redefined) continue; element_info[element].special_graphic[special] = graphic; } /* initialize special element/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int direction = property_mapping[i].ext2_index; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; #if 0 if ((element == EL_EM_DYNAMITE || element == EL_EM_DYNAMITE_ACTIVE || element == EL_CONVEYOR_BELT_1_MIDDLE || element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) && (special == GFX_SPECIAL_ARG_EDITOR || special == GFX_SPECIAL_ARG_PANEL)) printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n", element, special, graphic, property_mapping[i].ext1_index); #endif #if 0 if (element == EL_CONVEYOR_BELT_1_MIDDLE && action == ACTION_ACTIVE) { element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE; action = -1; } #endif #if 0 if (element == EL_MAGIC_WALL && action == ACTION_ACTIVE) { element = EL_MAGIC_WALL_ACTIVE; action = -1; } #endif #if 1 /* for action ".active", replace element with active element, if exists */ if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element)) { element = ELEMENT_ACTIVE(element); action = -1; } #endif if (element >= MAX_NUM_ELEMENTS) continue; /* do not change special graphic if action or direction was specified */ if (action != -1 || direction != -1) continue; if (IS_SPECIAL_GFX_ARG(special)) element_info[element].special_graphic[special] = graphic; } /* now set all undefined/invalid graphics to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL) element_info[i].special_graphic[j] = element_info[i].graphic[ACTION_DEFAULT]; } static int get_graphic_parameter_value(char *value_raw, char *suffix, int type) { if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC) return get_parameter_value(value_raw, suffix, type); if (strEqual(value_raw, ARG_UNDEFINED)) return ARG_UNDEFINED_VALUE; #if 1 if (type == TYPE_ELEMENT) { char *value = getHashEntry(element_token_hash, value_raw); return (value != NULL ? atoi(value) : EL_UNDEFINED); } else if (type == TYPE_GRAPHIC) { char *value = getHashEntry(graphic_token_hash, value_raw); return (value != NULL ? atoi(value) : IMG_UNDEFINED); } #else int i; int x = 0; /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */ /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */ /* !!! OPTIMIZE THIS BY USING HASH !!! */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (strEqual(element_info[i].token_name, value_raw)) return i; /* !!! OPTIMIZE THIS BY USING HASH !!! */ for (i = 0; image_config[i].token != NULL; i++) { int len_config_value = strlen(image_config[i].value); if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") && !strEqual(&image_config[i].value[len_config_value - 4], ".wav") && !strEqual(image_config[i].value, UNDEFINED_FILENAME)) continue; if (strEqual(image_config[i].token, value_raw)) return x; x++; } #endif return -1; } static int get_scaled_graphic_width(int graphic) { int original_width = getOriginalImageWidthFromImageID(graphic); int scale_up_factor = graphic_info[graphic].scale_up_factor; return original_width * scale_up_factor; } static int get_scaled_graphic_height(int graphic) { int original_height = getOriginalImageHeightFromImageID(graphic); int scale_up_factor = graphic_info[graphic].scale_up_factor; return original_height * scale_up_factor; } static void set_graphic_parameters_ext(int graphic, int *parameter, Bitmap *src_bitmap) { struct GraphicInfo *g = &graphic_info[graphic]; int anim_frames_per_row = 1, anim_frames_per_col = 1; int anim_frames_per_line = 1; /* always start with reliable default values */ g->src_image_width = 0; g->src_image_height = 0; g->src_x = 0; g->src_y = 0; g->width = TILEX; /* default for element graphics */ g->height = TILEY; /* default for element graphics */ g->offset_x = 0; /* one or both of these values ... */ g->offset_y = 0; /* ... will be corrected later */ g->offset2_x = 0; /* one or both of these values ... */ g->offset2_y = 0; /* ... will be corrected later */ g->swap_double_tiles = -1; /* auto-detect tile swapping */ g->crumbled_like = -1; /* do not use clone element */ g->diggable_like = -1; /* do not use clone element */ g->border_size = TILEX / 8; /* "CRUMBLED" border size */ g->scale_up_factor = 1; /* default: no scaling up */ g->clone_from = -1; /* do not use clone graphic */ g->anim_delay_fixed = 0; g->anim_delay_random = 0; g->post_delay_fixed = 0; g->post_delay_random = 0; g->fade_mode = FADE_MODE_DEFAULT; g->fade_delay = -1; g->post_delay = -1; g->auto_delay = -1; g->align = ALIGN_CENTER; /* default for title screens */ g->valign = VALIGN_MIDDLE; /* default for title screens */ g->sort_priority = 0; /* default for title screens */ g->class = 0; g->style = STYLE_DEFAULT; g->bitmap = src_bitmap; #if 1 /* optional zoom factor for scaling up the image to a larger size */ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE) g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR]; if (g->scale_up_factor < 1) g->scale_up_factor = 1; /* no scaling */ #endif #if 1 if (g->use_image_size) { /* set new default bitmap size (with scaling, but without small images) */ g->width = get_scaled_graphic_width(graphic); g->height = get_scaled_graphic_height(graphic); } #endif /* optional x and y tile position of animation frame sequence */ if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE) g->src_x = parameter[GFX_ARG_XPOS] * TILEX; if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE) g->src_y = parameter[GFX_ARG_YPOS] * TILEY; /* optional x and y pixel position of animation frame sequence */ if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE) g->src_x = parameter[GFX_ARG_X]; if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE) g->src_y = parameter[GFX_ARG_Y]; /* optional width and height of each animation frame */ if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE) g->width = parameter[GFX_ARG_WIDTH]; if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE) g->height = parameter[GFX_ARG_HEIGHT]; #if 0 /* optional zoom factor for scaling up the image to a larger size */ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE) g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR]; if (g->scale_up_factor < 1) g->scale_up_factor = 1; /* no scaling */ #endif if (src_bitmap) { /* get final bitmap size (with scaling, but without small images) */ int src_image_width = get_scaled_graphic_width(graphic); int src_image_height = get_scaled_graphic_height(graphic); if (src_image_width == 0 || src_image_height == 0) { /* only happens when loaded outside artwork system (like "global.busy") */ src_image_width = src_bitmap->width; src_image_height = src_bitmap->height; } anim_frames_per_row = src_image_width / g->width; anim_frames_per_col = src_image_height / g->height; g->src_image_width = src_image_width; g->src_image_height = src_image_height; } /* correct x or y offset dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */ { g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : g->height); anim_frames_per_line = anim_frames_per_col; } else /* frames are ordered horizontally */ { g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : g->width); anim_frames_per_line = anim_frames_per_row; } /* optionally, the x and y offset of frames can be specified directly */ if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE) g->offset_x = parameter[GFX_ARG_XOFFSET]; if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE) g->offset_y = parameter[GFX_ARG_YOFFSET]; /* optionally, moving animations may have separate start and end graphics */ g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE]; if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE) parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL]; /* correct x or y offset2 dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */ g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : g->height); else /* frames are ordered horizontally */ g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : g->width); /* optionally, the x and y offset of 2nd graphic can be specified directly */ if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE) g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET]; if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE) g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET]; /* optionally, the second movement tile can be specified as start tile */ if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE) g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES]; /* automatically determine correct number of frames, if not defined */ if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE) g->anim_frames = parameter[GFX_ARG_FRAMES]; else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL]) g->anim_frames = anim_frames_per_row; else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL]) g->anim_frames = anim_frames_per_col; else g->anim_frames = 1; if (g->anim_frames == 0) /* frames must be at least 1 */ g->anim_frames = 1; g->anim_frames_per_line = (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line); g->anim_delay = parameter[GFX_ARG_DELAY]; if (g->anim_delay == 0) /* delay must be at least 1 */ g->anim_delay = 1; g->anim_mode = parameter[GFX_ARG_ANIM_MODE]; #if 0 if (g->anim_frames == 1) g->anim_mode = ANIM_NONE; #endif /* automatically determine correct start frame, if not defined */ if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE) g->anim_start_frame = 0; else if (g->anim_mode & ANIM_REVERSE) g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1; else g->anim_start_frame = parameter[GFX_ARG_START_FRAME]; /* animation synchronized with global frame counter, not move position */ g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC]; /* optional element for cloning crumble graphics */ if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE) g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE]; /* optional element for cloning digging graphics */ if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE) g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE]; /* optional border size for "crumbling" diggable graphics */ if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE) g->border_size = parameter[GFX_ARG_BORDER_SIZE]; /* this is only used for player "boring" and "sleeping" actions */ if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE) g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED]; if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM]; if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE) g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED]; if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM]; /* this is only used for toon animations */ g->step_offset = parameter[GFX_ARG_STEP_OFFSET]; g->step_delay = parameter[GFX_ARG_STEP_DELAY]; /* this is only used for drawing font characters */ g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET]; g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET]; /* this is only used for drawing envelope graphics */ g->draw_masked = parameter[GFX_ARG_DRAW_MASKED]; /* optional graphic for cloning all graphics settings */ if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE) g->clone_from = parameter[GFX_ARG_CLONE_FROM]; /* optional settings for drawing title screens and title messages */ if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE) g->fade_mode = parameter[GFX_ARG_FADE_MODE]; if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE) g->fade_delay = parameter[GFX_ARG_FADE_DELAY]; if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE) g->post_delay = parameter[GFX_ARG_POST_DELAY]; if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE) g->auto_delay = parameter[GFX_ARG_AUTO_DELAY]; if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE) g->align = parameter[GFX_ARG_ALIGN]; if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE) g->valign = parameter[GFX_ARG_VALIGN]; if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE) g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY]; if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE) g->class = parameter[GFX_ARG_CLASS]; if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE) g->style = parameter[GFX_ARG_STYLE]; } static void set_graphic_parameters(int graphic) { #if 1 struct FileInfo *image = getImageListEntryFromImageID(graphic); char **parameter_raw = image->parameter; Bitmap *src_bitmap = getBitmapFromImageID(graphic); int parameter[NUM_GFX_ARGS]; int i; /* if fallback to default artwork is done, also use the default parameters */ if (image->fallback_to_default) parameter_raw = image->default_parameter; /* get integer values from string parameters */ for (i = 0; i < NUM_GFX_ARGS; i++) parameter[i] = get_graphic_parameter_value(parameter_raw[i], image_config_suffix[i].token, image_config_suffix[i].type); set_graphic_parameters_ext(graphic, parameter, src_bitmap); #else struct FileInfo *image = getImageListEntryFromImageID(graphic); char **parameter_raw = image->parameter; Bitmap *src_bitmap = getBitmapFromImageID(graphic); int parameter[NUM_GFX_ARGS]; int anim_frames_per_row = 1, anim_frames_per_col = 1; int anim_frames_per_line = 1; int i; /* if fallback to default artwork is done, also use the default parameters */ if (image->fallback_to_default) parameter_raw = image->default_parameter; /* get integer values from string parameters */ for (i = 0; i < NUM_GFX_ARGS; i++) parameter[i] = get_graphic_parameter_value(parameter_raw[i], image_config_suffix[i].token, image_config_suffix[i].type); graphic_info[graphic].bitmap = src_bitmap; /* always start with reliable default values */ graphic_info[graphic].src_image_width = 0; graphic_info[graphic].src_image_height = 0; graphic_info[graphic].src_x = 0; graphic_info[graphic].src_y = 0; graphic_info[graphic].width = TILEX; /* default for element graphics */ graphic_info[graphic].height = TILEY; /* default for element graphics */ graphic_info[graphic].offset_x = 0; /* one or both of these values ... */ graphic_info[graphic].offset_y = 0; /* ... will be corrected later */ graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */ graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */ graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */ graphic_info[graphic].crumbled_like = -1; /* do not use clone element */ graphic_info[graphic].diggable_like = -1; /* do not use clone element */ graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */ graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */ graphic_info[graphic].clone_from = -1; /* do not use clone graphic */ graphic_info[graphic].anim_delay_fixed = 0; graphic_info[graphic].anim_delay_random = 0; graphic_info[graphic].post_delay_fixed = 0; graphic_info[graphic].post_delay_random = 0; graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT; graphic_info[graphic].fade_delay = -1; graphic_info[graphic].post_delay = -1; graphic_info[graphic].auto_delay = -1; graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */ graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */ graphic_info[graphic].sort_priority = 0; /* default for title screens */ #if 1 /* optional zoom factor for scaling up the image to a larger size */ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE) graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR]; if (graphic_info[graphic].scale_up_factor < 1) graphic_info[graphic].scale_up_factor = 1; /* no scaling */ #endif #if 1 if (graphic_info[graphic].use_image_size) { /* set new default bitmap size (with scaling, but without small images) */ graphic_info[graphic].width = get_scaled_graphic_width(graphic); graphic_info[graphic].height = get_scaled_graphic_height(graphic); } #endif /* optional x and y tile position of animation frame sequence */ if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE) graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX; if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE) graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY; /* optional x and y pixel position of animation frame sequence */ if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE) graphic_info[graphic].src_x = parameter[GFX_ARG_X]; if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE) graphic_info[graphic].src_y = parameter[GFX_ARG_Y]; /* optional width and height of each animation frame */ if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE) graphic_info[graphic].width = parameter[GFX_ARG_WIDTH]; if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE) graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT]; #if 0 /* optional zoom factor for scaling up the image to a larger size */ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE) graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR]; if (graphic_info[graphic].scale_up_factor < 1) graphic_info[graphic].scale_up_factor = 1; /* no scaling */ #endif if (src_bitmap) { /* get final bitmap size (with scaling, but without small images) */ int src_image_width = get_scaled_graphic_width(graphic); int src_image_height = get_scaled_graphic_height(graphic); anim_frames_per_row = src_image_width / graphic_info[graphic].width; anim_frames_per_col = src_image_height / graphic_info[graphic].height; graphic_info[graphic].src_image_width = src_image_width; graphic_info[graphic].src_image_height = src_image_height; } /* correct x or y offset dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */ { graphic_info[graphic].offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height); anim_frames_per_line = anim_frames_per_col; } else /* frames are ordered horizontally */ { graphic_info[graphic].offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width); anim_frames_per_line = anim_frames_per_row; } /* optionally, the x and y offset of frames can be specified directly */ if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE) graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET]; if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE) graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET]; /* optionally, moving animations may have separate start and end graphics */ graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE]; if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE) parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL]; /* correct x or y offset2 dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */ graphic_info[graphic].offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height); else /* frames are ordered horizontally */ graphic_info[graphic].offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width); /* optionally, the x and y offset of 2nd graphic can be specified directly */ if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE) graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET]; if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE) graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET]; /* optionally, the second movement tile can be specified as start tile */ if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE) graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES]; /* automatically determine correct number of frames, if not defined */ if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE) graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES]; else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL]) graphic_info[graphic].anim_frames = anim_frames_per_row; else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL]) graphic_info[graphic].anim_frames = anim_frames_per_col; else graphic_info[graphic].anim_frames = 1; if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */ graphic_info[graphic].anim_frames = 1; graphic_info[graphic].anim_frames_per_line = (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line); graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY]; if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */ graphic_info[graphic].anim_delay = 1; graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE]; #if 0 if (graphic_info[graphic].anim_frames == 1) graphic_info[graphic].anim_mode = ANIM_NONE; #endif /* automatically determine correct start frame, if not defined */ if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE) graphic_info[graphic].anim_start_frame = 0; else if (graphic_info[graphic].anim_mode & ANIM_REVERSE) graphic_info[graphic].anim_start_frame = graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1; else graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME]; /* animation synchronized with global frame counter, not move position */ graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC]; /* optional element for cloning crumble graphics */ if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE) graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE]; /* optional element for cloning digging graphics */ if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE) graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE]; /* optional border size for "crumbling" diggable graphics */ if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE) graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE]; /* this is only used for player "boring" and "sleeping" actions */ if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE) graphic_info[graphic].anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED]; if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) graphic_info[graphic].anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM]; if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE) graphic_info[graphic].post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED]; if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) graphic_info[graphic].post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM]; /* this is only used for toon animations */ graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET]; graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY]; /* this is only used for drawing font characters */ graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET]; graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET]; /* this is only used for drawing envelope graphics */ graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED]; /* optional graphic for cloning all graphics settings */ if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE) graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM]; /* optional settings for drawing title screens and title messages */ if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE) graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE]; if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE) graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY]; if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE) graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY]; if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE) graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY]; if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE) graphic_info[graphic].align = parameter[GFX_ARG_ALIGN]; if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE) graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN]; if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE) graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY]; #endif UPDATE_BUSY_STATE(); } static void set_cloned_graphic_parameters(int graphic) { int fallback_graphic = IMG_CHAR_EXCLAM; int max_num_images = getImageListSize(); int clone_graphic = graphic_info[graphic].clone_from; int num_references_followed = 1; while (graphic_info[clone_graphic].clone_from != -1 && num_references_followed < max_num_images) { clone_graphic = graphic_info[clone_graphic].clone_from; num_references_followed++; } if (num_references_followed >= max_num_images) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic)); Error(ERR_INFO, "error: loop discovered when resolving cloned graphics"); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (graphic == fallback_graphic) Error(ERR_EXIT, "fatal error: no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[graphic] = graphic_info[fallback_graphic]; } else { graphic_info[graphic] = graphic_info[clone_graphic]; graphic_info[graphic].clone_from = clone_graphic; } } static void InitGraphicInfo() { int fallback_graphic = IMG_CHAR_EXCLAM; int num_images = getImageListSize(); int i; #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) static boolean clipmasks_initialized = FALSE; Pixmap src_pixmap; XGCValues clip_gc_values; unsigned long clip_gc_valuemask; GC copy_clipmask_gc = None; #endif /* use image size as default values for width and height for these images */ static int full_size_graphics[] = { IMG_GLOBAL_BORDER, IMG_GLOBAL_DOOR, IMG_BACKGROUND_ENVELOPE_1, IMG_BACKGROUND_ENVELOPE_2, IMG_BACKGROUND_ENVELOPE_3, IMG_BACKGROUND_ENVELOPE_4, IMG_BACKGROUND, IMG_BACKGROUND_TITLE_INITIAL, IMG_BACKGROUND_TITLE, IMG_BACKGROUND_MAIN, IMG_BACKGROUND_LEVELS, IMG_BACKGROUND_SCORES, IMG_BACKGROUND_EDITOR, IMG_BACKGROUND_INFO, IMG_BACKGROUND_INFO_ELEMENTS, IMG_BACKGROUND_INFO_MUSIC, IMG_BACKGROUND_INFO_CREDITS, IMG_BACKGROUND_INFO_PROGRAM, IMG_BACKGROUND_INFO_LEVELSET, IMG_BACKGROUND_SETUP, IMG_BACKGROUND_DOOR, IMG_TITLESCREEN_INITIAL_1, IMG_TITLESCREEN_INITIAL_2, IMG_TITLESCREEN_INITIAL_3, IMG_TITLESCREEN_INITIAL_4, IMG_TITLESCREEN_INITIAL_5, IMG_TITLESCREEN_1, IMG_TITLESCREEN_2, IMG_TITLESCREEN_3, IMG_TITLESCREEN_4, IMG_TITLESCREEN_5, -1 }; checked_free(graphic_info); graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo)); #if 1 /* initialize "use_image_size" flag with default value */ for (i = 0; i < num_images; i++) graphic_info[i].use_image_size = FALSE; /* initialize "use_image_size" flag from static configuration above */ for (i = 0; full_size_graphics[i] != -1; i++) graphic_info[full_size_graphics[i]].use_image_size = TRUE; #endif #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) if (clipmasks_initialized) { for (i = 0; i < num_images; i++) { if (graphic_info[i].clip_mask) XFreePixmap(display, graphic_info[i].clip_mask); if (graphic_info[i].clip_gc) XFreeGC(display, graphic_info[i].clip_gc); graphic_info[i].clip_mask = None; graphic_info[i].clip_gc = None; } } #endif /* first set all graphic paramaters ... */ for (i = 0; i < num_images; i++) set_graphic_parameters(i); /* ... then copy these parameters for cloned graphics */ for (i = 0; i < num_images; i++) if (graphic_info[i].clone_from != -1) set_cloned_graphic_parameters(i); for (i = 0; i < num_images; i++) { Bitmap *src_bitmap; int src_x, src_y; int width, height; int first_frame, last_frame; int src_bitmap_width, src_bitmap_height; /* now check if no animation frames are outside of the loaded image */ if (graphic_info[i].bitmap == NULL) continue; /* skip check for optional images that are undefined */ /* get image size (this can differ from the standard element tile size!) */ width = graphic_info[i].width; height = graphic_info[i].height; /* get final bitmap size (with scaling, but without small images) */ src_bitmap_width = graphic_info[i].src_image_width; src_bitmap_height = graphic_info[i].src_image_height; /* check if first animation frame is inside specified bitmap */ first_frame = 0; getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y); #if 1 /* this avoids calculating wrong start position for out-of-bounds frame */ src_x = graphic_info[i].src_x; src_y = graphic_info[i].src_y; #endif if (src_x < 0 || src_y < 0 || src_x + width > src_bitmap_width || src_y + height > src_bitmap_height) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i)); Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename); Error(ERR_INFO, "error: first animation frame out of bounds (%d, %d) [%d, %d]", src_x, src_y, src_bitmap_width, src_bitmap_height); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (i == fallback_graphic) Error(ERR_EXIT, "fatal error: no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[i] = graphic_info[fallback_graphic]; } /* check if last animation frame is inside specified bitmap */ last_frame = graphic_info[i].anim_frames - 1; getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y); if (src_x < 0 || src_y < 0 || src_x + width > src_bitmap_width || src_y + height > src_bitmap_height) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i)); Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename); Error(ERR_INFO, "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]", last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (i == fallback_graphic) Error(ERR_EXIT, "fatal error: no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[i] = graphic_info[fallback_graphic]; } #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) /* currently we only need a tile clip mask from the first frame */ getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y); if (copy_clipmask_gc == None) { clip_gc_values.graphics_exposures = False; clip_gc_valuemask = GCGraphicsExposures; copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask, clip_gc_valuemask, &clip_gc_values); } graphic_info[i].clip_mask = XCreatePixmap(display, window->drawable, TILEX, TILEY, 1); src_pixmap = src_bitmap->clip_mask; XCopyArea(display, src_pixmap, graphic_info[i].clip_mask, copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0); clip_gc_values.graphics_exposures = False; clip_gc_values.clip_mask = graphic_info[i].clip_mask; clip_gc_valuemask = GCGraphicsExposures | GCClipMask; graphic_info[i].clip_gc = XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values); #endif } #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) if (copy_clipmask_gc) XFreeGC(display, copy_clipmask_gc); clipmasks_initialized = TRUE; #endif } static void InitElementSoundInfo() { struct PropertyMapping *property_mapping = getSoundListPropertyMapping(); int num_property_mappings = getSoundListPropertyMappingSize(); int i, j, act; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (act = 0; act < NUM_ACTIONS; act++) element_info[i].sound[act] = -1; /* initialize element/sound mapping from static configuration */ for (i = 0; element_to_sound[i].element > -1; i++) { int element = element_to_sound[i].element; int action = element_to_sound[i].action; int sound = element_to_sound[i].sound; boolean is_class = element_to_sound[i].is_class; if (action < 0) action = ACTION_DEFAULT; if (!is_class) element_info[element].sound[action] = sound; else for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strEqual(element_info[j].class_name, element_info[element].class_name)) element_info[j].sound[action] = sound; } /* initialize element class/sound mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int action = property_mapping[i].ext1_index; int sound = property_mapping[i].artwork_index; if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS) continue; if (action < 0) action = ACTION_DEFAULT; for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strEqual(element_info[j].class_name, element_info[element_class].class_name)) element_info[j].sound[action] = sound; } /* initialize element/sound mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int sound = property_mapping[i].artwork_index; if (element >= MAX_NUM_ELEMENTS) continue; if (action < 0) action = ACTION_DEFAULT; element_info[element].sound[action] = sound; } /* now set all '-1' values to element specific default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { /* generic default action sound (defined by "[default]" directive) */ int default_action_sound = element_info[EL_DEFAULT].sound[act]; /* look for special default action sound (classic game specific) */ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_BD_DEFAULT].sound[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_SP_DEFAULT].sound[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_SB_DEFAULT].sound[act]; /* !!! there's no such thing as a "default action sound" !!! */ #if 0 /* look for element specific default sound (independent from action) */ if (element_info[i].sound[ACTION_DEFAULT] != -1) default_action_sound = element_info[i].sound[ACTION_DEFAULT]; #endif #if 1 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */ /* !!! make this better !!! */ if (i == EL_EMPTY_SPACE) default_action_sound = element_info[EL_DEFAULT].sound[act]; #endif /* no sound for this specific action -- use default action sound */ if (element_info[i].sound[act] == -1) element_info[i].sound[act] = default_action_sound; } } /* copy sound settings to some elements that are only stored in level file in native R'n'D levels, but are used by game engine in native EM levels */ for (i = 0; copy_properties[i][0] != -1; i++) for (j = 1; j <= 4; j++) for (act = 0; act < NUM_ACTIONS; act++) element_info[copy_properties[i][j]].sound[act] = element_info[copy_properties[i][0]].sound[act]; } static void InitGameModeSoundInfo() { int i; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) menu.sound[i] = -1; /* initialize gamemode/sound mapping from static configuration */ for (i = 0; gamemode_to_sound[i].sound > -1; i++) { int gamemode = gamemode_to_sound[i].gamemode; int sound = gamemode_to_sound[i].sound; if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; menu.sound[gamemode] = sound; } /* now set all '-1' values to levelset specific default values */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.sound[i] == -1) menu.sound[i] = menu.sound[GAME_MODE_DEFAULT]; #if 0 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.sound[i] != -1) printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]); #endif } static void set_sound_parameters(int sound, char **parameter_raw) { int parameter[NUM_SND_ARGS]; int i; /* get integer values from string parameters */ for (i = 0; i < NUM_SND_ARGS; i++) parameter[i] = get_parameter_value(parameter_raw[i], sound_config_suffix[i].token, sound_config_suffix[i].type); /* explicit loop mode setting in configuration overrides default value */ if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE) sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP]; /* sound volume to change the original volume when loading the sound file */ sound_info[sound].volume = parameter[SND_ARG_VOLUME]; /* sound priority to give certain sounds a higher or lower priority */ sound_info[sound].priority = parameter[SND_ARG_PRIORITY]; } static void InitSoundInfo() { int *sound_effect_properties; int num_sounds = getSoundListSize(); int i, j; checked_free(sound_info); sound_effect_properties = checked_calloc(num_sounds * sizeof(int)); sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo)); /* initialize sound effect for all elements to "no sound" */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_ACTIONS; j++) element_info[i].sound[j] = SND_UNDEFINED; for (i = 0; i < num_sounds; i++) { struct FileInfo *sound = getSoundListEntry(i); int len_effect_text = strlen(sound->token); sound_effect_properties[i] = ACTION_OTHER; sound_info[i].loop = FALSE; /* default: play sound only once */ #if 0 printf("::: sound %d: '%s'\n", i, sound->token); #endif /* determine all loop sounds and identify certain sound classes */ for (j = 0; element_action_info[j].suffix; j++) { int len_action_text = strlen(element_action_info[j].suffix); if (len_action_text < len_effect_text && strEqual(&sound->token[len_effect_text - len_action_text], element_action_info[j].suffix)) { sound_effect_properties[i] = element_action_info[j].value; sound_info[i].loop = element_action_info[j].is_loop_sound; break; } } /* associate elements and some selected sound actions */ for (j = 0; j < MAX_NUM_ELEMENTS; j++) { if (element_info[j].class_name) { int len_class_text = strlen(element_info[j].class_name); if (len_class_text + 1 < len_effect_text && strncmp(sound->token, element_info[j].class_name, len_class_text) == 0 && sound->token[len_class_text] == '.') { int sound_action_value = sound_effect_properties[i]; element_info[j].sound[sound_action_value] = i; } } } set_sound_parameters(i, sound->parameter); } free(sound_effect_properties); } static void InitGameModeMusicInfo() { struct PropertyMapping *property_mapping = getMusicListPropertyMapping(); int num_property_mappings = getMusicListPropertyMappingSize(); int default_levelset_music = -1; int i; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_LEVELS; i++) levelset.music[i] = -1; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) menu.music[i] = -1; /* initialize gamemode/music mapping from static configuration */ for (i = 0; gamemode_to_music[i].music > -1; i++) { int gamemode = gamemode_to_music[i].gamemode; int music = gamemode_to_music[i].music; #if 0 printf("::: gamemode == %d, music == %d\n", gamemode, music); #endif if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; menu.music[gamemode] = music; } /* initialize gamemode/music mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int prefix = property_mapping[i].base_index; int gamemode = property_mapping[i].ext1_index; int level = property_mapping[i].ext2_index; int music = property_mapping[i].artwork_index; #if 0 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n", prefix, gamemode, level, music); #endif if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES) continue; if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; /* level specific music only allowed for in-game music */ if (level != -1 && gamemode == GAME_MODE_DEFAULT) gamemode = GAME_MODE_PLAYING; if (level == -1) { level = 0; default_levelset_music = music; } if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT) levelset.music[level] = music; if (gamemode != GAME_MODE_PLAYING) menu.music[gamemode] = music; } /* now set all '-1' values to menu specific default values */ /* (undefined values of "levelset.music[]" might stay at "-1" to allow dynamic selection of music files from music directory!) */ for (i = 0; i < MAX_LEVELS; i++) if (levelset.music[i] == -1) levelset.music[i] = default_levelset_music; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.music[i] == -1) menu.music[i] = menu.music[GAME_MODE_DEFAULT]; #if 0 for (i = 0; i < MAX_LEVELS; i++) if (levelset.music[i] != -1) printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]); for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.music[i] != -1) printf("::: menu.music[%d] == %d\n", i, menu.music[i]); #endif } static void set_music_parameters(int music, char **parameter_raw) { int parameter[NUM_MUS_ARGS]; int i; /* get integer values from string parameters */ for (i = 0; i < NUM_MUS_ARGS; i++) parameter[i] = get_parameter_value(parameter_raw[i], music_config_suffix[i].token, music_config_suffix[i].type); /* explicit loop mode setting in configuration overrides default value */ if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE) music_info[music].loop = parameter[MUS_ARG_MODE_LOOP]; } static void InitMusicInfo() { int num_music = getMusicListSize(); int i, j; checked_free(music_info); music_info = checked_calloc(num_music * sizeof(struct MusicInfo)); for (i = 0; i < num_music; i++) { struct FileInfo *music = getMusicListEntry(i); int len_music_text = strlen(music->token); music_info[i].loop = TRUE; /* default: play music in loop mode */ /* determine all loop music */ for (j = 0; music_prefix_info[j].prefix; j++) { int len_prefix_text = strlen(music_prefix_info[j].prefix); if (len_prefix_text < len_music_text && strncmp(music->token, music_prefix_info[j].prefix, len_prefix_text) == 0) { music_info[i].loop = music_prefix_info[j].is_loop_music; break; } } set_music_parameters(i, music->parameter); } } static void ReinitializeGraphics() { print_timestamp_init("ReinitializeGraphics"); InitGraphicInfo(); /* graphic properties mapping */ print_timestamp_time("InitGraphicInfo"); InitElementGraphicInfo(); /* element game graphic mapping */ print_timestamp_time("InitElementGraphicInfo"); InitElementSpecialGraphicInfo(); /* element special graphic mapping */ print_timestamp_time("InitElementSpecialGraphicInfo"); InitElementSmallImages(); /* scale elements to all needed sizes */ print_timestamp_time("InitElementSmallImages"); InitScaledImages(); /* scale all other images, if needed */ print_timestamp_time("InitScaledImages"); InitFontGraphicInfo(); /* initialize text drawing functions */ print_timestamp_time("InitFontGraphicInfo"); InitGraphicInfo_EM(); /* graphic mapping for EM engine */ print_timestamp_time("InitGraphicInfo_EM"); SetMainBackgroundImage(IMG_BACKGROUND); print_timestamp_time("SetMainBackgroundImage"); SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); print_timestamp_time("SetDoorBackgroundImage"); InitGadgets(); print_timestamp_time("InitGadgets"); InitToons(); print_timestamp_time("InitToons"); print_timestamp_done("ReinitializeGraphics"); } static void ReinitializeSounds() { InitSoundInfo(); /* sound properties mapping */ InitElementSoundInfo(); /* element game sound mapping */ InitGameModeSoundInfo(); /* game mode sound mapping */ InitPlayLevelSound(); /* internal game sound settings */ } static void ReinitializeMusic() { InitMusicInfo(); /* music properties mapping */ InitGameModeMusicInfo(); /* game mode music mapping */ } static int get_special_property_bit(int element, int property_bit_nr) { struct PropertyBitInfo { int element; int bit_nr; }; static struct PropertyBitInfo pb_can_move_into_acid[] = { /* the player may be able fall into acid when gravity is activated */ { EL_PLAYER_1, 0 }, { EL_PLAYER_2, 0 }, { EL_PLAYER_3, 0 }, { EL_PLAYER_4, 0 }, { EL_SP_MURPHY, 0 }, { EL_SOKOBAN_FIELD_PLAYER, 0 }, /* all elements that can move may be able to also move into acid */ { EL_BUG, 1 }, { EL_BUG_LEFT, 1 }, { EL_BUG_RIGHT, 1 }, { EL_BUG_UP, 1 }, { EL_BUG_DOWN, 1 }, { EL_SPACESHIP, 2 }, { EL_SPACESHIP_LEFT, 2 }, { EL_SPACESHIP_RIGHT, 2 }, { EL_SPACESHIP_UP, 2 }, { EL_SPACESHIP_DOWN, 2 }, { EL_BD_BUTTERFLY, 3 }, { EL_BD_BUTTERFLY_LEFT, 3 }, { EL_BD_BUTTERFLY_RIGHT, 3 }, { EL_BD_BUTTERFLY_UP, 3 }, { EL_BD_BUTTERFLY_DOWN, 3 }, { EL_BD_FIREFLY, 4 }, { EL_BD_FIREFLY_LEFT, 4 }, { EL_BD_FIREFLY_RIGHT, 4 }, { EL_BD_FIREFLY_UP, 4 }, { EL_BD_FIREFLY_DOWN, 4 }, { EL_YAMYAM, 5 }, { EL_YAMYAM_LEFT, 5 }, { EL_YAMYAM_RIGHT, 5 }, { EL_YAMYAM_UP, 5 }, { EL_YAMYAM_DOWN, 5 }, { EL_DARK_YAMYAM, 6 }, { EL_ROBOT, 7 }, { EL_PACMAN, 8 }, { EL_PACMAN_LEFT, 8 }, { EL_PACMAN_RIGHT, 8 }, { EL_PACMAN_UP, 8 }, { EL_PACMAN_DOWN, 8 }, { EL_MOLE, 9 }, { EL_MOLE_LEFT, 9 }, { EL_MOLE_RIGHT, 9 }, { EL_MOLE_UP, 9 }, { EL_MOLE_DOWN, 9 }, { EL_PENGUIN, 10 }, { EL_PIG, 11 }, { EL_DRAGON, 12 }, { EL_SATELLITE, 13 }, { EL_SP_SNIKSNAK, 14 }, { EL_SP_ELECTRON, 15 }, { EL_BALLOON, 16 }, { EL_SPRING, 17 }, { EL_EMC_ANDROID, 18 }, { -1, -1 }, }; static struct PropertyBitInfo pb_dont_collide_with[] = { { EL_SP_SNIKSNAK, 0 }, { EL_SP_ELECTRON, 1 }, { -1, -1 }, }; static struct { int bit_nr; struct PropertyBitInfo *pb_info; } pb_definition[] = { { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid }, { EP_DONT_COLLIDE_WITH, pb_dont_collide_with }, { -1, NULL }, }; struct PropertyBitInfo *pb_info = NULL; int i; for (i = 0; pb_definition[i].bit_nr != -1; i++) if (pb_definition[i].bit_nr == property_bit_nr) pb_info = pb_definition[i].pb_info; if (pb_info == NULL) return -1; for (i = 0; pb_info[i].element != -1; i++) if (pb_info[i].element == element) return pb_info[i].bit_nr; return -1; } void setBitfieldProperty(int *bitfield, int property_bit_nr, int element, boolean property_value) { int bit_nr = get_special_property_bit(element, property_bit_nr); if (bit_nr > -1) { if (property_value) *bitfield |= (1 << bit_nr); else *bitfield &= ~(1 << bit_nr); } } boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element) { int bit_nr = get_special_property_bit(element, property_bit_nr); if (bit_nr > -1) return ((*bitfield & (1 << bit_nr)) != 0); return FALSE; } static void ResolveGroupElementExt(int group_element, int recursion_depth) { static int group_nr; static struct ElementGroupInfo *group; struct ElementGroupInfo *actual_group = element_info[group_element].group; int i; if (actual_group == NULL) /* not yet initialized */ return; if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */ { Error(ERR_WARN, "recursion too deep when resolving group element %d", group_element - EL_GROUP_START + 1); /* replace element which caused too deep recursion by question mark */ group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN; return; } if (recursion_depth == 0) /* initialization */ { group = actual_group; group_nr = GROUP_NR(group_element); group->num_elements_resolved = 0; group->choice_pos = 0; for (i = 0; i < MAX_NUM_ELEMENTS; i++) element_info[i].in_group[group_nr] = FALSE; } for (i = 0; i < actual_group->num_elements; i++) { int element = actual_group->element[i]; if (group->num_elements_resolved == NUM_FILE_ELEMENTS) break; if (IS_GROUP_ELEMENT(element)) ResolveGroupElementExt(element, recursion_depth + 1); else { group->element_resolved[group->num_elements_resolved++] = element; element_info[element].in_group[group_nr] = TRUE; } } } void ResolveGroupElement(int group_element) { ResolveGroupElementExt(group_element, 0); } void InitElementPropertiesStatic() { static boolean clipboard_elements_initialized = FALSE; static int ep_diggable[] = { EL_SAND, EL_SP_BASE, EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, EL_TRAP, EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE, EL_EMC_GRASS, /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */ /* (if amoeba can grow into anything diggable, maybe keep these out) */ #if 0 EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP_ACTIVE, EL_SP_BUGGY_BASE_ACTIVE, EL_EMC_PLANT, #endif -1 }; static int ep_collectible_only[] = { EL_BD_DIAMOND, EL_EMERALD, EL_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_DYNAMITE, EL_EM_DYNAMITE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_INFOTRON, EL_SP_DISK_RED, EL_PEARL, EL_CRYSTAL, EL_DC_KEY_WHITE, EL_SHIELD_NORMAL, EL_SHIELD_DEADLY, EL_EXTRA_TIME, EL_ENVELOPE_1, EL_ENVELOPE_2, EL_ENVELOPE_3, EL_ENVELOPE_4, EL_SPEED_PILL, EL_EMC_LENSES, EL_EMC_MAGNIFIER, #if 0 /* !!! handle separately !!! */ EL_DC_LANDMINE, /* deadly when running into, but can be snapped */ #endif -1 }; static int ep_dont_run_into[] = { /* same elements as in 'ep_dont_touch' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, /* same elements as in 'ep_dont_collide_with' */ EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, /* new elements */ EL_AMOEBA_DROP, EL_ACID, /* !!! maybe this should better be handled by 'ep_diggable' !!! */ #if 1 EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP_ACTIVE, EL_SP_BUGGY_BASE_ACTIVE, EL_EMC_PLANT, #endif -1 }; static int ep_dont_collide_with[] = { /* same elements as in 'ep_dont_touch' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, /* new elements */ EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, -1 }; static int ep_dont_touch[] = { EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, -1 }; static int ep_indestructible[] = { EL_STEELWALL, EL_ACID, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_STEEL_EXIT_OPENING, EL_STEEL_EXIT_CLOSING, EL_EM_STEEL_EXIT_CLOSED, EL_EM_STEEL_EXIT_OPEN, EL_EM_STEEL_EXIT_OPENING, EL_EM_STEEL_EXIT_CLOSING, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_CRYSTAL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_DC_GATE_FAKE_GRAY, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_OPENING, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_CLOSING, #if 1 EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, #endif EL_TIMEGATE_OPEN, EL_TIMEGATE_OPENING, EL_TIMEGATE_CLOSED, EL_TIMEGATE_CLOSING, #if 1 EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE, #endif EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_EXPANDABLE_STEELWALL_ANY, -1 }; static int ep_slippery[] = { EL_WALL_SLIPPERY, EL_BD_WALL, EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_LAMP_ACTIVE, EL_LAMP, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_SATELLITE, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SPEED_PILL, EL_STEELWALL_SLIPPERY, EL_PEARL, EL_CRYSTAL, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_ACTIVE, -1 }; static int ep_can_change[] = { -1 }; static int ep_can_move[] = { /* same elements as in 'pb_can_move_into_acid' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_MOLE, EL_PENGUIN, EL_PIG, EL_DRAGON, EL_SATELLITE, EL_SP_SNIKSNAK, EL_SP_ELECTRON, EL_BALLOON, EL_SPRING, EL_EMC_ANDROID, -1 }; static int ep_can_fall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_AMOEBA_DROP, EL_QUICKSAND_FULL, EL_QUICKSAND_FAST_FULL, EL_MAGIC_WALL_FULL, EL_BD_MAGIC_WALL_FULL, EL_DC_MAGIC_WALL_FULL, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_DISK_ORANGE, EL_PEARL, EL_CRYSTAL, EL_SPRING, EL_DX_SUPABOMB, -1 }; static int ep_can_smash_player[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_AMOEBA_DROP, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_DISK_ORANGE, EL_PEARL, EL_CRYSTAL, EL_SPRING, EL_DX_SUPABOMB, -1 }; static int ep_can_smash_enemies[] = { EL_ROCK, EL_BD_ROCK, EL_SP_ZONK, -1 }; static int ep_can_smash_everything[] = { EL_ROCK, EL_BD_ROCK, EL_SP_ZONK, -1 }; static int ep_explodes_by_fire[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* same elements as in 'ep_explodes_smashed' */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, /* new elements */ EL_DYNAMITE, EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_DISK_RED_ACTIVE, EL_BUG, EL_PENGUIN, EL_SP_DISK_RED, EL_SP_DISK_YELLOW, EL_SP_SNIKSNAK, EL_SP_ELECTRON, #if 0 EL_BLACK_ORB, #endif -1 }; static int ep_explodes_smashed[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* new elements */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, -1 }; static int ep_explodes_impact[] = { EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, -1 }; static int ep_walkable_over[] = { EL_EMPTY_SPACE, EL_SP_EMPTY_SPACE, EL_SOKOBAN_FIELD_EMPTY, EL_EXIT_OPEN, EL_EM_EXIT_OPEN, #if 1 EL_EM_EXIT_OPENING, #endif EL_SP_EXIT_OPEN, EL_SP_EXIT_OPENING, EL_STEEL_EXIT_OPEN, EL_EM_STEEL_EXIT_OPEN, #if 1 EL_EM_STEEL_EXIT_OPENING, #endif EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_PENGUIN, EL_PIG, EL_DRAGON, -1 }; static int ep_walkable_inside[] = { EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, -1 }; static int ep_walkable_under[] = { -1 }; static int ep_passable_over[] = { EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_TIMEGATE_OPEN, -1 }; static int ep_passable_inside[] = { EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, -1 }; static int ep_passable_under[] = { -1 }; static int ep_droppable[] = { -1 }; static int ep_explodes_1x1_old[] = { -1 }; static int ep_pushable[] = { EL_ROCK, EL_BOMB, EL_DX_SUPABOMB, EL_NUT, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_DISK_ORANGE, EL_SPRING, EL_BD_ROCK, EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_FULL, EL_SATELLITE, EL_SP_DISK_YELLOW, EL_BALLOON, EL_EMC_ANDROID, -1 }; static int ep_explodes_cross_old[] = { -1 }; static int ep_protected[] = { /* same elements as in 'ep_walkable_inside' */ EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, /* same elements as in 'ep_passable_over' */ EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_TIMEGATE_OPEN, /* same elements as in 'ep_passable_inside' */ EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, -1 }; static int ep_throwable[] = { -1 }; static int ep_can_explode[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* same elements as in 'ep_explodes_smashed' */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, /* elements that can explode by explosion or by dragonfire */ EL_DYNAMITE, EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_DISK_RED_ACTIVE, EL_BUG, EL_PENGUIN, EL_SP_DISK_RED, EL_SP_DISK_YELLOW, EL_SP_SNIKSNAK, EL_SP_ELECTRON, /* elements that can explode only by explosion */ EL_BLACK_ORB, -1 }; static int ep_gravity_reachable[] = { EL_SAND, EL_SP_BASE, EL_TRAP, EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE, EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_EMC_GRASS, -1 }; static int ep_player[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_SP_MURPHY, EL_SOKOBAN_FIELD_PLAYER, EL_TRIGGER_PLAYER, -1 }; static int ep_can_pass_magic_wall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_can_pass_dc_magic_wall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_switchable[] = { EL_ROBOT_WHEEL, EL_SP_TERMINAL, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH, EL_BALLOON_SWITCH_LEFT, EL_BALLOON_SWITCH_RIGHT, EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_ANY, EL_BALLOON_SWITCH_NONE, EL_LAMP, EL_TIME_ORB_FULL, EL_EMC_MAGIC_BALL_SWITCH, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE, -1 }; static int ep_bd_element[] = { EL_EMPTY, EL_SAND, EL_WALL_SLIPPERY, EL_BD_WALL, EL_ROCK, EL_BD_ROCK, EL_BD_DIAMOND, EL_BD_MAGIC_WALL, EL_EXIT_CLOSED, EL_EXIT_OPEN, EL_STEELWALL, EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_BD_FIREFLY, EL_BD_FIREFLY_1, EL_BD_FIREFLY_2, EL_BD_FIREFLY_3, EL_BD_FIREFLY_4, EL_BD_BUTTERFLY, EL_BD_BUTTERFLY_1, EL_BD_BUTTERFLY_2, EL_BD_BUTTERFLY_3, EL_BD_BUTTERFLY_4, EL_BD_AMOEBA, EL_CHAR_QUESTION, EL_UNKNOWN, -1 }; static int ep_sp_element[] = { /* should always be valid */ EL_EMPTY, /* standard classic Supaplex elements */ EL_SP_EMPTY, EL_SP_ZONK, EL_SP_BASE, EL_SP_MURPHY, EL_SP_INFOTRON, EL_SP_CHIP_SINGLE, EL_SP_HARDWARE_GRAY, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_SP_DISK_ORANGE, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT, EL_SP_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_UP, EL_SP_SNIKSNAK, EL_SP_DISK_YELLOW, EL_SP_TERMINAL, EL_SP_DISK_RED, EL_SP_PORT_VERTICAL, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_ANY, EL_SP_ELECTRON, EL_SP_BUGGY_BASE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, /* additional elements that appeared in newer Supaplex levels */ EL_INVISIBLE_WALL, /* additional gravity port elements (not switching, but setting gravity) */ EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, /* more than one Murphy in a level results in an inactive clone */ EL_SP_MURPHY_CLONE, /* runtime Supaplex elements */ EL_SP_DISK_RED_ACTIVE, EL_SP_TERMINAL_ACTIVE, EL_SP_BUGGY_BASE_ACTIVATING, EL_SP_BUGGY_BASE_ACTIVE, EL_SP_EXIT_OPENING, EL_SP_EXIT_CLOSING, -1 }; static int ep_sb_element[] = { EL_EMPTY, EL_STEELWALL, EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_SOKOBAN_FIELD_PLAYER, EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_INVISIBLE_STEELWALL, -1 }; static int ep_gem[] = { EL_BD_DIAMOND, EL_EMERALD, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_food_dark_yamyam[] = { EL_SAND, EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_ROBOT, EL_PACMAN, EL_AMOEBA_DROP, EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_food_penguin[] = { EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_food_pig[] = { EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_historic_wall[] = { EL_STEELWALL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EXIT_CLOSED, EL_EXIT_OPENING, EL_EXIT_OPEN, EL_WALL, EL_WALL_SLIPPERY, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_EXPANDABLE_WALL_GROWING, EL_BD_EXPANDABLE_WALL, EL_BD_WALL, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, -1 }; static int ep_historic_solid[] = { EL_WALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_BD_EXPANDABLE_WALL, EL_BD_WALL, EL_WALL_SLIPPERY, EL_EXIT_CLOSED, EL_EXIT_OPENING, EL_EXIT_OPEN, EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL, EL_QUICKSAND_FILLING, EL_QUICKSAND_EMPTYING, EL_MAGIC_WALL, EL_MAGIC_WALL_ACTIVE, EL_MAGIC_WALL_EMPTYING, EL_MAGIC_WALL_FILLING, EL_MAGIC_WALL_FULL, EL_MAGIC_WALL_DEAD, EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_ACTIVE, EL_BD_MAGIC_WALL_EMPTYING, EL_BD_MAGIC_WALL_FULL, EL_BD_MAGIC_WALL_FILLING, EL_BD_MAGIC_WALL_DEAD, EL_GAME_OF_LIFE, EL_BIOMAZE, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_TIMEGATE_SWITCH, EL_TIMEGATE_SWITCH_ACTIVE, EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_WALL_PEARL, EL_WALL_CRYSTAL, /* the following elements are a direct copy of "indestructible" elements, except "EL_ACID", which is "indestructible", but not "solid"! */ #if 0 EL_ACID, #endif EL_STEELWALL, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_CRYSTAL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_OPENING, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_CLOSING, EL_TIMEGATE_OPEN, EL_TIMEGATE_OPENING, EL_TIMEGATE_CLOSED, EL_TIMEGATE_CLOSING, EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, -1 }; static int ep_classic_enemy[] = { EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, -1 }; static int ep_belt[] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_RIGHT, -1 }; static int ep_belt_active[] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_1_RIGHT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_2_RIGHT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_3_RIGHT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_4_RIGHT_ACTIVE, -1 }; static int ep_belt_switch[] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, -1 }; static int ep_tube[] = { EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, EL_TUBE_HORIZONTAL, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_VERTICAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_ANY, -1 }; static int ep_acid_pool[] = { EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, -1 }; static int ep_keygate[] = { EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, -1 }; static int ep_amoeboid[] = { EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_DRIPPER, -1 }; static int ep_amoebalive[] = { EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_DRIPPER, -1 }; static int ep_has_editor_content[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_SOKOBAN_FIELD_PLAYER, EL_SP_MURPHY, EL_YAMYAM, EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT, EL_YAMYAM_UP, EL_YAMYAM_DOWN, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_MAGIC_BALL, EL_EMC_ANDROID, -1 }; static int ep_can_turn_each_move[] = { /* !!! do something with this one !!! */ -1 }; static int ep_can_grow[] = { EL_BD_AMOEBA, EL_AMOEBA_DROP, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_GAME_OF_LIFE, EL_BIOMAZE, EL_EMC_DRIPPER, -1 }; static int ep_active_bomb[] = { EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_SP_DISK_RED_ACTIVE, -1 }; static int ep_inactive[] = { EL_EMPTY, EL_SAND, EL_WALL, EL_BD_WALL, EL_WALL_SLIPPERY, EL_STEELWALL, EL_AMOEBA_DEAD, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FAST_EMPTY, EL_STONEBLOCK, EL_ROBOT_WHEEL, EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_DC_GATE_FAKE_GRAY, EL_DYNAMITE, EL_EM_DYNAMITE, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_WALL, EL_INVISIBLE_SAND, EL_LAMP, EL_LAMP_ACTIVE, EL_WALL_EMERALD, EL_WALL_DIAMOND, EL_WALL_BD_DIAMOND, EL_WALL_EMERALD_YELLOW, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, #if 0 EL_SOKOBAN_OBJECT, #endif EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_WALL_EMERALD_RED, EL_WALL_EMERALD_PURPLE, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_MAGIC_WALL, EL_MAGIC_WALL_DEAD, EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_DEAD, EL_DC_MAGIC_WALL, EL_DC_MAGIC_WALL_DEAD, EL_AMOEBA_TO_DIAMOND, EL_BLOCKED, EL_SP_EMPTY, EL_SP_BASE, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT, EL_SP_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_UP, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_DISK_RED, #if 0 EL_SP_DISK_YELLOW, #endif EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_EMC_WALL_9, EL_EMC_WALL_10, EL_EMC_WALL_11, EL_EMC_WALL_12, EL_EMC_WALL_13, EL_EMC_WALL_14, EL_EMC_WALL_15, EL_EMC_WALL_16, -1 }; static int ep_em_slippery_wall[] = { -1 }; static int ep_gfx_crumbled[] = { EL_SAND, EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP, EL_TRAP_ACTIVE, -1 }; static int ep_editor_cascade_active[] = { EL_INTERNAL_CASCADE_BD_ACTIVE, EL_INTERNAL_CASCADE_EM_ACTIVE, EL_INTERNAL_CASCADE_EMC_ACTIVE, EL_INTERNAL_CASCADE_RND_ACTIVE, EL_INTERNAL_CASCADE_SB_ACTIVE, EL_INTERNAL_CASCADE_SP_ACTIVE, EL_INTERNAL_CASCADE_DC_ACTIVE, EL_INTERNAL_CASCADE_DX_ACTIVE, EL_INTERNAL_CASCADE_CHARS_ACTIVE, EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE, EL_INTERNAL_CASCADE_CE_ACTIVE, EL_INTERNAL_CASCADE_GE_ACTIVE, EL_INTERNAL_CASCADE_REF_ACTIVE, EL_INTERNAL_CASCADE_USER_ACTIVE, EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE, -1 }; static int ep_editor_cascade_inactive[] = { EL_INTERNAL_CASCADE_BD, EL_INTERNAL_CASCADE_EM, EL_INTERNAL_CASCADE_EMC, EL_INTERNAL_CASCADE_RND, EL_INTERNAL_CASCADE_SB, EL_INTERNAL_CASCADE_SP, EL_INTERNAL_CASCADE_DC, EL_INTERNAL_CASCADE_DX, EL_INTERNAL_CASCADE_CHARS, EL_INTERNAL_CASCADE_STEEL_CHARS, EL_INTERNAL_CASCADE_CE, EL_INTERNAL_CASCADE_GE, EL_INTERNAL_CASCADE_REF, EL_INTERNAL_CASCADE_USER, EL_INTERNAL_CASCADE_DYNAMIC, -1 }; static int ep_obsolete[] = { EL_PLAYER_OBSOLETE, EL_KEY_OBSOLETE, EL_EM_KEY_1_FILE_OBSOLETE, EL_EM_KEY_2_FILE_OBSOLETE, EL_EM_KEY_3_FILE_OBSOLETE, EL_EM_KEY_4_FILE_OBSOLETE, EL_ENVELOPE_OBSOLETE, -1 }; static struct { int *elements; int property; } element_properties[] = { { ep_diggable, EP_DIGGABLE }, { ep_collectible_only, EP_COLLECTIBLE_ONLY }, { ep_dont_run_into, EP_DONT_RUN_INTO }, { ep_dont_collide_with, EP_DONT_COLLIDE_WITH }, { ep_dont_touch, EP_DONT_TOUCH }, { ep_indestructible, EP_INDESTRUCTIBLE }, { ep_slippery, EP_SLIPPERY }, { ep_can_change, EP_CAN_CHANGE }, { ep_can_move, EP_CAN_MOVE }, { ep_can_fall, EP_CAN_FALL }, { ep_can_smash_player, EP_CAN_SMASH_PLAYER }, { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES }, { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING }, { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE }, { ep_explodes_smashed, EP_EXPLODES_SMASHED }, { ep_explodes_impact, EP_EXPLODES_IMPACT }, { ep_walkable_over, EP_WALKABLE_OVER }, { ep_walkable_inside, EP_WALKABLE_INSIDE }, { ep_walkable_under, EP_WALKABLE_UNDER }, { ep_passable_over, EP_PASSABLE_OVER }, { ep_passable_inside, EP_PASSABLE_INSIDE }, { ep_passable_under, EP_PASSABLE_UNDER }, { ep_droppable, EP_DROPPABLE }, { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD }, { ep_pushable, EP_PUSHABLE }, { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD }, { ep_protected, EP_PROTECTED }, { ep_throwable, EP_THROWABLE }, { ep_can_explode, EP_CAN_EXPLODE }, { ep_gravity_reachable, EP_GRAVITY_REACHABLE }, { ep_player, EP_PLAYER }, { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL }, { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL }, { ep_switchable, EP_SWITCHABLE }, { ep_bd_element, EP_BD_ELEMENT }, { ep_sp_element, EP_SP_ELEMENT }, { ep_sb_element, EP_SB_ELEMENT }, { ep_gem, EP_GEM }, { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM }, { ep_food_penguin, EP_FOOD_PENGUIN }, { ep_food_pig, EP_FOOD_PIG }, { ep_historic_wall, EP_HISTORIC_WALL }, { ep_historic_solid, EP_HISTORIC_SOLID }, { ep_classic_enemy, EP_CLASSIC_ENEMY }, { ep_belt, EP_BELT }, { ep_belt_active, EP_BELT_ACTIVE }, { ep_belt_switch, EP_BELT_SWITCH }, { ep_tube, EP_TUBE }, { ep_acid_pool, EP_ACID_POOL }, { ep_keygate, EP_KEYGATE }, { ep_amoeboid, EP_AMOEBOID }, { ep_amoebalive, EP_AMOEBALIVE }, { ep_has_editor_content, EP_HAS_EDITOR_CONTENT }, { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE }, { ep_can_grow, EP_CAN_GROW }, { ep_active_bomb, EP_ACTIVE_BOMB }, { ep_inactive, EP_INACTIVE }, { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL }, { ep_gfx_crumbled, EP_GFX_CRUMBLED }, { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE }, { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE }, { ep_obsolete, EP_OBSOLETE }, { NULL, -1 } }; int i, j, k; /* always start with reliable default values (element has no properties) */ /* (but never initialize clipboard elements after the very first time) */ /* (to be able to use clipboard elements between several levels) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized) for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++) SET_PROPERTY(i, j, FALSE); /* set all base element properties from above array definitions */ for (i = 0; element_properties[i].elements != NULL; i++) for (j = 0; (element_properties[i].elements)[j] != -1; j++) SET_PROPERTY((element_properties[i].elements)[j], element_properties[i].property, TRUE); /* copy properties to some elements that are only stored in level file */ for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) for (j = 0; copy_properties[j][0] != -1; j++) if (HAS_PROPERTY(copy_properties[j][0], i)) for (k = 1; k <= 4; k++) SET_PROPERTY(copy_properties[j][k], i, TRUE); /* set static element properties that are not listed in array definitions */ for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++) SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE); clipboard_elements_initialized = TRUE; } void InitElementPropertiesEngine(int engine_version) { static int no_wall_properties[] = { EP_DIGGABLE, EP_COLLECTIBLE_ONLY, EP_DONT_RUN_INTO, EP_DONT_COLLIDE_WITH, EP_CAN_MOVE, EP_CAN_FALL, EP_CAN_SMASH_PLAYER, EP_CAN_SMASH_ENEMIES, EP_CAN_SMASH_EVERYTHING, EP_PUSHABLE, EP_PLAYER, EP_GEM, EP_FOOD_DARK_YAMYAM, EP_FOOD_PENGUIN, EP_BELT, EP_BELT_ACTIVE, EP_TUBE, EP_AMOEBOID, EP_AMOEBALIVE, EP_ACTIVE_BOMB, EP_ACCESSIBLE, -1 }; int i, j; /* important: after initialization in InitElementPropertiesStatic(), the elements are not again initialized to a default value; therefore all changes have to make sure that they leave the element with a defined property (which means that conditional property changes must be set to a reliable default value before) */ /* resolve group elements */ for (i = 0; i < NUM_GROUP_ELEMENTS; i++) ResolveGroupElement(EL_GROUP_START + i); /* set all special, combined or engine dependent element properties */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { /* do not change (already initialized) clipboard elements here */ if (IS_CLIPBOARD_ELEMENT(i)) continue; /* ---------- INACTIVE ------------------------------------------------- */ SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START && i <= EL_CHAR_END) || (i >= EL_STEEL_CHAR_START && i <= EL_STEEL_CHAR_END))); /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */ SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) || IS_WALKABLE_INSIDE(i) || IS_WALKABLE_UNDER(i))); SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) || IS_PASSABLE_INSIDE(i) || IS_PASSABLE_UNDER(i))); SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) || IS_PASSABLE_OVER(i))); SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) || IS_PASSABLE_INSIDE(i))); SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) || IS_PASSABLE_UNDER(i))); SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) || IS_PASSABLE(i))); /* ---------- COLLECTIBLE ---------------------------------------------- */ SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) || IS_DROPPABLE(i) || IS_THROWABLE(i))); /* ---------- SNAPPABLE ------------------------------------------------ */ SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) || IS_COLLECTIBLE(i) || IS_SWITCHABLE(i) || i == EL_BD_ROCK)); /* ---------- WALL ----------------------------------------------------- */ SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */ for (j = 0; no_wall_properties[j] != -1; j++) if (HAS_PROPERTY(i, no_wall_properties[j]) || i >= EL_FIRST_RUNTIME_UNREAL) SET_PROPERTY(i, EP_WALL, FALSE); if (IS_HISTORIC_WALL(i)) SET_PROPERTY(i, EP_WALL, TRUE); /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */ if (engine_version < VERSION_IDENT(2,2,0,0)) SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i)); else SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) && !IS_DIGGABLE(i) && !IS_COLLECTIBLE(i))); /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */ if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION) SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE); else SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) && IS_INDESTRUCTIBLE(i))); /* ---------- EXPLOSION_PROOF ------------------------------------------ */ if (i == EL_FLAMES) SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE); else if (engine_version < VERSION_IDENT(2,2,0,0)) SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i)); else SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) && (!IS_WALKABLE(i) || IS_PROTECTED(i)))); if (IS_CUSTOM_ELEMENT(i)) { /* these are additional properties which are initially false when set */ /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */ if (DONT_TOUCH(i)) SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE); if (DONT_COLLIDE_WITH(i)) SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE); /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */ if (CAN_SMASH_EVERYTHING(i)) SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE); if (CAN_SMASH_ENEMIES(i)) SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE); } /* ---------- CAN_SMASH ------------------------------------------------ */ SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) || CAN_SMASH_ENEMIES(i) || CAN_SMASH_EVERYTHING(i))); /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) && EXPLODES_BY_FIRE(i))); /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) && EXPLODES_SMASHED(i))); /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) && EXPLODES_IMPACT(i))); /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i)); /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) || i == EL_BLACK_ORB)); /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */ SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) || CAN_MOVE(i) || IS_CUSTOM_ELEMENT(i))); /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */ SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK || i == EL_SP_ELECTRON)); /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */ if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i)) SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID, getMoveIntoAcidProperty(&level, i)); /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */ if (MAYBE_DONT_COLLIDE_WITH(i)) SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, getDontCollideWithProperty(&level, i)); /* ---------- SP_PORT -------------------------------------------------- */ SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) && IS_PASSABLE_INSIDE(i))); /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */ for (j = 0; j < level.num_android_clone_elements; j++) SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID, (i != EL_EMPTY && IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j]))); /* ---------- CAN_CHANGE ----------------------------------------------- */ SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */ for (j = 0; j < element_info[i].num_change_pages; j++) if (element_info[i].change_page[j].can_change) SET_PROPERTY(i, EP_CAN_CHANGE, TRUE); /* ---------- HAS_ACTION ----------------------------------------------- */ SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */ for (j = 0; j < element_info[i].num_change_pages; j++) if (element_info[i].change_page[j].has_action) SET_PROPERTY(i, EP_HAS_ACTION, TRUE); /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */ SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) || HAS_ACTION(i))); /* ---------- GFX_CRUMBLED --------------------------------------------- */ #if 1 SET_PROPERTY(i, EP_GFX_CRUMBLED, element_info[i].crumbled[ACTION_DEFAULT] != element_info[i].graphic[ACTION_DEFAULT]); #else /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */ SET_PROPERTY(i, EP_GFX_CRUMBLED, element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY); #endif /* ---------- EDITOR_CASCADE ------------------------------------------- */ SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) || IS_EDITOR_CASCADE_INACTIVE(i))); } /* dynamically adjust element properties according to game engine version */ { static int ep_em_slippery_wall[] = { EL_WALL, EL_STEELWALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_EXPANDABLE_STEELWALL_ANY, EL_EXPANDABLE_STEELWALL_GROWING, -1 }; static int ep_em_explodes_by_fire[] = { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_MOLE, -1 }; /* special EM style gems behaviour */ for (i = 0; ep_em_slippery_wall[i] != -1; i++) SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL, level.em_slippery_gems); /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */ SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL, (level.em_slippery_gems && engine_version > VERSION_IDENT(2,0,1,0))); /* special EM style explosion behaviour regarding chain reactions */ for (i = 0; ep_em_explodes_by_fire[i] != -1; i++) SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE, level.em_explodes_by_fire); } /* this is needed because some graphics depend on element properties */ if (game_status == GAME_MODE_PLAYING) InitElementGraphicInfo(); } void InitElementPropertiesAfterLoading(int engine_version) { int i; /* set some other uninitialized values of custom elements in older levels */ if (engine_version < VERSION_IDENT(3,1,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; element_info[element].access_direction = MV_ALL_DIRECTIONS; element_info[element].explosion_delay = 17; element_info[element].ignition_delay = 8; } } } void InitElementPropertiesGfxElement() { int i; for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i); } } static void InitGlobal() { int graphic; int i; for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++) { /* check if element_name_info entry defined for each element in "main.h" */ if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL) Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i); element_info[i].token_name = element_name_info[i].token_name; element_info[i].class_name = element_name_info[i].class_name; element_info[i].editor_description= element_name_info[i].editor_description; #if 0 printf("%04d: %s\n", i, element_name_info[i].token_name); #endif } /* create hash from image config list */ image_config_hash = newSetupFileHash(); for (i = 0; image_config[i].token != NULL; i++) setHashEntry(image_config_hash, image_config[i].token, image_config[i].value); /* create hash from element token list */ element_token_hash = newSetupFileHash(); for (i = 0; element_name_info[i].token_name != NULL; i++) setHashEntry(element_token_hash, element_name_info[i].token_name, int2str(i, 0)); /* create hash from graphic token list */ graphic_token_hash = newSetupFileHash(); for (graphic = 0, i = 0; image_config[i].token != NULL; i++) if (strSuffix(image_config[i].value, ".pcx") || strSuffix(image_config[i].value, ".wav") || strEqual(image_config[i].value, UNDEFINED_FILENAME)) setHashEntry(graphic_token_hash, image_config[i].token, int2str(graphic++, 0)); /* create hash from font token list */ font_token_hash = newSetupFileHash(); for (i = 0; font_info[i].token_name != NULL; i++) setHashEntry(font_token_hash, font_info[i].token_name, int2str(i, 0)); /* always start with reliable default values (all elements) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) ActiveElement[i] = i; /* now add all entries that have an active state (active elements) */ for (i = 0; element_with_active_state[i].element != -1; i++) { int element = element_with_active_state[i].element; int element_active = element_with_active_state[i].element_active; ActiveElement[element] = element_active; } /* always start with reliable default values (all buttons) */ for (i = 0; i < NUM_IMAGE_FILES; i++) ActiveButton[i] = i; /* now add all entries that have an active state (active buttons) */ for (i = 0; button_with_active_state[i].button != -1; i++) { int button = button_with_active_state[i].button; int button_active = button_with_active_state[i].button_active; ActiveButton[button] = button_active; } /* always start with reliable default values (all fonts) */ for (i = 0; i < NUM_FONTS; i++) ActiveFont[i] = i; /* now add all entries that have an active state (active fonts) */ for (i = 0; font_with_active_state[i].font_nr != -1; i++) { int font = font_with_active_state[i].font_nr; int font_active = font_with_active_state[i].font_nr_active; ActiveFont[font] = font_active; } global.autoplay_leveldir = NULL; global.convert_leveldir = NULL; global.create_images_dir = NULL; global.frames_per_second = 0; global.fps_slowdown = FALSE; global.fps_slowdown_factor = 1; global.border_status = GAME_MODE_MAIN; #if 0 global.fading_status = GAME_MODE_MAIN; global.fading_type = TYPE_ENTER_MENU; #endif } void Execute_Command(char *command) { int i; if (strEqual(command, "print graphicsinfo.conf")) { printf("# You can configure additional/alternative image files here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); printf("\n"); for (i = 0; image_config[i].token != NULL; i++) printf("# %s\n", getFormattedSetupEntry(image_config[i].token, image_config[i].value)); exit(0); } else if (strEqual(command, "print soundsinfo.conf")) { printf("# You can configure additional/alternative sound files here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); printf("\n"); for (i = 0; sound_config[i].token != NULL; i++) printf("# %s\n", getFormattedSetupEntry(sound_config[i].token, sound_config[i].value)); exit(0); } else if (strEqual(command, "print musicinfo.conf")) { printf("# You can configure additional/alternative music files here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Music")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); printf("\n"); for (i = 0; music_config[i].token != NULL; i++) printf("# %s\n", getFormattedSetupEntry(music_config[i].token, music_config[i].value)); exit(0); } else if (strEqual(command, "print editorsetup.conf")) { printf("# You can configure your personal editor element list here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); /* this is needed to be able to check element list for cascade elements */ InitElementPropertiesStatic(); InitElementPropertiesEngine(GAME_VERSION_ACTUAL); PrintEditorElementList(); exit(0); } else if (strEqual(command, "print helpanim.conf")) { printf("# You can configure different element help animations here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); for (i = 0; helpanim_config[i].token != NULL; i++) { printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token, helpanim_config[i].value)); if (strEqual(helpanim_config[i].token, "end")) printf("#\n"); } exit(0); } else if (strEqual(command, "print helptext.conf")) { printf("# You can configure different element help text here.\n"); printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); for (i = 0; helptext_config[i].token != NULL; i++) printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token, helptext_config[i].value)); exit(0); } else if (strPrefix(command, "dump level ")) { char *filename = &command[11]; if (!fileExists(filename)) Error(ERR_EXIT, "cannot open file '%s'", filename); LoadLevelFromFilename(&level, filename); DumpLevel(&level); exit(0); } else if (strPrefix(command, "dump tape ")) { char *filename = &command[10]; if (!fileExists(filename)) Error(ERR_EXIT, "cannot open file '%s'", filename); LoadTapeFromFilename(filename); DumpTape(&tape); exit(0); } else if (strPrefix(command, "autoplay ")) { char *str_ptr = getStringCopy(&command[9]); /* read command parameters */ while (*str_ptr != '\0') /* continue parsing string */ { /* cut leading whitespace from string, replace it by string terminator */ while (*str_ptr == ' ' || *str_ptr == '\t') *str_ptr++ = '\0'; if (*str_ptr == '\0') /* end of string reached */ break; if (global.autoplay_leveldir == NULL) /* read level set string */ { global.autoplay_leveldir = str_ptr; global.autoplay_all = TRUE; /* default: play all tapes */ for (i = 0; i < MAX_TAPES_PER_SET; i++) global.autoplay_level[i] = FALSE; } else /* read level number string */ { int level_nr = atoi(str_ptr); /* get level_nr value */ if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET) global.autoplay_level[level_nr] = TRUE; global.autoplay_all = FALSE; } /* advance string pointer to the next whitespace (or end of string) */ while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0') str_ptr++; } } else if (strPrefix(command, "convert ")) { char *str_copy = getStringCopy(strchr(command, ' ') + 1); char *str_ptr = strchr(str_copy, ' '); global.convert_leveldir = str_copy; global.convert_level_nr = -1; if (str_ptr != NULL) /* level number follows */ { *str_ptr++ = '\0'; /* terminate leveldir string */ global.convert_level_nr = atoi(str_ptr); /* get level_nr value */ } } else if (strPrefix(command, "create images ")) { #if defined(TARGET_SDL) global.create_images_dir = getStringCopy(&command[14]); if (access(global.create_images_dir, W_OK) != 0) Error(ERR_EXIT, "image target directory '%s' not found or not writable", global.create_images_dir); #else Error(ERR_EXIT, "command only available for SDL target"); #endif } #if DEBUG #if defined(TARGET_SDL) else if (strEqual(command, "SDL_ListModes")) { SDL_Rect **modes; int i; SDL_Init(SDL_INIT_VIDEO); /* get available fullscreen/hardware modes */ modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); /* check if there are any modes available */ if (modes == NULL) { printf("No modes available!\n"); exit(-1); } /* check if our resolution is restricted */ if (modes == (SDL_Rect **)-1) { printf("All resolutions available.\n"); } else { printf("Available Modes:\n"); for(i = 0; modes[i]; i++) printf(" %d x %d\n", modes[i]->w, modes[i]->h); } exit(0); } #endif #endif else { Error(ERR_EXIT_HELP, "unrecognized command '%s'", command); } } static void InitSetup() { LoadSetup(); /* global setup info */ /* set some options from setup file */ if (setup.options.verbose) options.verbose = TRUE; } static void InitGameInfo() { game.restart_level = FALSE; } static void InitPlayerInfo() { int i; /* choose default local player */ local_player = &stored_player[0]; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = FALSE; local_player->connected = TRUE; } static void InitArtworkInfo() { LoadArtworkInfo(); } static char *get_string_in_brackets(char *string) { char *string_in_brackets = checked_malloc(strlen(string) + 3); sprintf(string_in_brackets, "[%s]", string); return string_in_brackets; } static char *get_level_id_suffix(int id_nr) { char *id_suffix = checked_malloc(1 + 3 + 1); if (id_nr < 0 || id_nr > 999) id_nr = 0; sprintf(id_suffix, ".%03d", id_nr); return id_suffix; } #if 0 static char *get_element_class_token(int element) { char *element_class_name = element_info[element].class_name; char *element_class_token = checked_malloc(strlen(element_class_name) + 3); sprintf(element_class_token, "[%s]", element_class_name); return element_class_token; } static char *get_action_class_token(int action) { char *action_class_name = &element_action_info[action].suffix[1]; char *action_class_token = checked_malloc(strlen(action_class_name) + 3); sprintf(action_class_token, "[%s]", action_class_name); return action_class_token; } #endif static void InitArtworkConfig() { static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1]; static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1]; static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1]; static char *action_id_suffix[NUM_ACTIONS + 1]; static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1]; static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1]; static char *level_id_suffix[MAX_LEVELS + 1]; static char *dummy[1] = { NULL }; static char *ignore_generic_tokens[] = { "name", "sort_priority", NULL }; static char **ignore_image_tokens; static char **ignore_sound_tokens; static char **ignore_music_tokens; int num_ignore_generic_tokens; int num_ignore_image_tokens; int num_ignore_sound_tokens; int num_ignore_music_tokens; int i; /* dynamically determine list of generic tokens to be ignored */ num_ignore_generic_tokens = 0; for (i = 0; ignore_generic_tokens[i] != NULL; i++) num_ignore_generic_tokens++; /* dynamically determine list of image tokens to be ignored */ num_ignore_image_tokens = num_ignore_generic_tokens; for (i = 0; image_config_vars[i].token != NULL; i++) num_ignore_image_tokens++; ignore_image_tokens = checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_image_tokens[i] = ignore_generic_tokens[i]; for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++) ignore_image_tokens[num_ignore_generic_tokens + i] = image_config_vars[i].token; ignore_image_tokens[num_ignore_image_tokens] = NULL; /* dynamically determine list of sound tokens to be ignored */ num_ignore_sound_tokens = num_ignore_generic_tokens; ignore_sound_tokens = checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_sound_tokens[i] = ignore_generic_tokens[i]; ignore_sound_tokens[num_ignore_sound_tokens] = NULL; /* dynamically determine list of music tokens to be ignored */ num_ignore_music_tokens = num_ignore_generic_tokens; ignore_music_tokens = checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_music_tokens[i] = ignore_generic_tokens[i]; ignore_music_tokens[num_ignore_music_tokens] = NULL; for (i = 0; i < MAX_NUM_ELEMENTS; i++) image_id_prefix[i] = element_info[i].token_name; for (i = 0; i < NUM_FONTS; i++) image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name; image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL; for (i = 0; i < MAX_NUM_ELEMENTS; i++) sound_id_prefix[i] = element_info[i].token_name; for (i = 0; i < MAX_NUM_ELEMENTS; i++) sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_string_in_brackets(element_info[i].class_name); sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL; for (i = 0; i < NUM_MUSIC_PREFIXES; i++) music_id_prefix[i] = music_prefix_info[i].prefix; music_id_prefix[NUM_MUSIC_PREFIXES] = NULL; for (i = 0; i < NUM_ACTIONS; i++) action_id_suffix[i] = element_action_info[i].suffix; action_id_suffix[NUM_ACTIONS] = NULL; for (i = 0; i < NUM_DIRECTIONS_FULL; i++) direction_id_suffix[i] = element_direction_info[i].suffix; direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) special_id_suffix[i] = special_suffix_info[i].suffix; special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL; for (i = 0; i < MAX_LEVELS; i++) level_id_suffix[i] = get_level_id_suffix(i); level_id_suffix[MAX_LEVELS] = NULL; InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix, image_id_prefix, action_id_suffix, direction_id_suffix, special_id_suffix, ignore_image_tokens); InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix, sound_id_prefix, action_id_suffix, dummy, special_id_suffix, ignore_sound_tokens); InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix, music_id_prefix, special_id_suffix, level_id_suffix, dummy, ignore_music_tokens); } static void InitMixer() { OpenAudio(); StartMixer(); } void InitGfxBuffers() { ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH); ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH); ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH); ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH); /* initialize screen properties */ InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, bitmap_db_field); InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE); InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE); InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE); InitGfxScrollbufferInfo(FXSIZE, FYSIZE); InitGfxClipRegion(FALSE, -1, -1, -1, -1); InitGfxBuffers_SP(); } void InitGfx() { struct GraphicInfo *graphic_info_last = graphic_info; char *filename_font_initial = NULL; char *filename_anim_initial = NULL; Bitmap *bitmap_font_initial = NULL; int font_height; int i, j; /* determine settings for initial font (for displaying startup messages) */ for (i = 0; image_config[i].token != NULL; i++) { for (j = 0; j < NUM_INITIAL_FONTS; j++) { char font_token[128]; int len_font_token; sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1); len_font_token = strlen(font_token); if (strEqual(image_config[i].token, font_token)) filename_font_initial = image_config[i].value; else if (strlen(image_config[i].token) > len_font_token && strncmp(image_config[i].token, font_token, len_font_token) == 0) { if (strEqual(&image_config[i].token[len_font_token], ".x")) font_initial[j].src_x = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".y")) font_initial[j].src_y = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".width")) font_initial[j].width = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".height")) font_initial[j].height = atoi(image_config[i].value); } } } for (j = 0; j < NUM_INITIAL_FONTS; j++) { font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT; font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE; } if (filename_font_initial == NULL) /* should not happen */ Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL); #if 1 InitGfxBuffers(); #else /* create additional image buffers for double-buffering and cross-fading */ bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH); bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH); bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH); /* initialize screen properties */ InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, bitmap_db_field); InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE); InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE); InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE); InitGfxScrollbufferInfo(FXSIZE, FYSIZE); #endif InitGfxCustomArtworkInfo(); bitmap_font_initial = LoadCustomImage(filename_font_initial); for (j = 0; j < NUM_INITIAL_FONTS; j++) font_initial[j].bitmap = bitmap_font_initial; InitFontGraphicInfo(); font_height = getFontHeight(FC_RED); #if 1 DrawInitText(getWindowTitleString(), 20, FC_YELLOW); #else DrawInitText(getProgramInitString(), 20, FC_YELLOW); #endif DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED); DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED); DrawInitText("Loading graphics", 120, FC_GREEN); #if 1 #if 1 /* initialize busy animation with default values */ int parameter[NUM_GFX_ARGS]; for (i = 0; i < NUM_GFX_ARGS; i++) parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value, image_config_suffix[i].token, image_config_suffix[i].type); #if 0 for (i = 0; i < NUM_GFX_ARGS; i++) printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]); #endif #endif /* determine settings for busy animation (when displaying startup messages) */ for (i = 0; image_config[i].token != NULL; i++) { char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY; int len_anim_token = strlen(anim_token); if (strEqual(image_config[i].token, anim_token)) filename_anim_initial = image_config[i].value; else if (strlen(image_config[i].token) > len_anim_token && strncmp(image_config[i].token, anim_token, len_anim_token) == 0) { #if 1 for (j = 0; image_config_suffix[j].token != NULL; j++) { if (strEqual(&image_config[i].token[len_anim_token], image_config_suffix[j].token)) parameter[j] = get_graphic_parameter_value(image_config[i].value, image_config_suffix[j].token, image_config_suffix[j].type); } #else if (strEqual(&image_config[i].token[len_anim_token], ".x")) anim_initial.src_x = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".y")) anim_initial.src_y = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".width")) anim_initial.width = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".height")) anim_initial.height = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".frames")) anim_initial.anim_frames = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".frames_per_line")) anim_initial.anim_frames_per_line = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_anim_token], ".delay")) anim_initial.anim_delay = atoi(image_config[i].value); #endif } } #if defined(CREATE_SPECIAL_EDITION_RND_JUE) filename_anim_initial = "loading.pcx"; parameter[GFX_ARG_X] = 0; parameter[GFX_ARG_Y] = 0; parameter[GFX_ARG_WIDTH] = 128; parameter[GFX_ARG_HEIGHT] = 40; parameter[GFX_ARG_FRAMES] = 32; parameter[GFX_ARG_DELAY] = 4; parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE; #endif if (filename_anim_initial == NULL) /* should not happen */ Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY); anim_initial.bitmap = LoadCustomImage(filename_anim_initial); graphic_info = &anim_initial; /* graphic == 0 => anim_initial */ set_graphic_parameters_ext(0, parameter, anim_initial.bitmap); #if 0 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n", graphic_info[0].anim_frames_per_line, get_scaled_graphic_width(0), graphic_info[0].width, getOriginalImageWidthFromImageID(0), graphic_info[0].scale_up_factor); #endif graphic_info = graphic_info_last; init.busy.width = anim_initial.width; init.busy.height = anim_initial.height; InitMenuDesignSettings_Static(); InitGfxDrawBusyAnimFunction(DrawInitAnim); /* use copy of busy animation to prevent change while reloading artwork */ init_last = init; #endif } void RedrawBackground() { BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); redraw_mask = REDRAW_ALL; } void InitGfxBackground() { int x, y; fieldbuffer = bitmap_db_field; SetDrawtoField(DRAW_BACKBUFFER); #if 1 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE); #else RedrawBackground(); ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE); #endif for (x = 0; x < MAX_BUF_XSIZE; x++) for (y = 0; y < MAX_BUF_YSIZE; y++) redraw[x][y] = 0; redraw_tiles = 0; redraw_mask = REDRAW_ALL; } static void InitLevelInfo() { LoadLevelInfo(); /* global level info */ LoadLevelSetup_LastSeries(); /* last played series info */ LoadLevelSetup_SeriesInfo(); /* last played level info */ } static void InitLevelArtworkInfo() { LoadLevelArtworkInfo(); } static void InitImages() { print_timestamp_init("InitImages"); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS)); #endif setLevelArtworkDir(artwork.gfx_first); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS)); #endif #if 0 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n", leveldir_current->identifier, artwork.gfx_current_identifier, artwork.gfx_current->identifier, leveldir_current->graphics_set, leveldir_current->graphics_path); #endif UPDATE_BUSY_STATE(); ReloadCustomImages(); print_timestamp_time("ReloadCustomImages"); UPDATE_BUSY_STATE(); LoadCustomElementDescriptions(); print_timestamp_time("LoadCustomElementDescriptions"); UPDATE_BUSY_STATE(); LoadMenuDesignSettings(); print_timestamp_time("LoadMenuDesignSettings"); UPDATE_BUSY_STATE(); ReinitializeGraphics(); print_timestamp_time("ReinitializeGraphics"); UPDATE_BUSY_STATE(); print_timestamp_done("InitImages"); } static void InitSound(char *identifier) { print_timestamp_init("InitSound"); if (identifier == NULL) identifier = artwork.snd_current->identifier; /* set artwork path to send it to the sound server process */ setLevelArtworkDir(artwork.snd_first); InitReloadCustomSounds(identifier); print_timestamp_time("InitReloadCustomSounds"); ReinitializeSounds(); print_timestamp_time("ReinitializeSounds"); print_timestamp_done("InitSound"); } static void InitMusic(char *identifier) { print_timestamp_init("InitMusic"); if (identifier == NULL) identifier = artwork.mus_current->identifier; /* set artwork path to send it to the sound server process */ setLevelArtworkDir(artwork.mus_first); InitReloadCustomMusic(identifier); print_timestamp_time("InitReloadCustomMusic"); ReinitializeMusic(); print_timestamp_time("ReinitializeMusic"); print_timestamp_done("InitMusic"); } void InitNetworkServer() { #if defined(NETWORK_AVALIABLE) int nr_wanted; #endif if (!options.network) return; #if defined(NETWORK_AVALIABLE) nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED); if (!ConnectToServer(options.server_host, options.server_port)) Error(ERR_EXIT, "cannot connect to network game server"); SendToServer_PlayerName(setup.player_name); SendToServer_ProtocolVersion(); if (nr_wanted) SendToServer_NrWanted(nr_wanted); #endif } static boolean CheckArtworkConfigForCustomElements(char *filename) { SetupFileHash *setup_file_hash; boolean redefined_ce_found = FALSE; /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */ if ((setup_file_hash = loadSetupFileHash(filename)) != NULL) { BEGIN_HASH_ITERATION(setup_file_hash, itr) { char *token = HASH_ITERATION_TOKEN(itr); if (strPrefix(token, "custom_")) { redefined_ce_found = TRUE; break; } } END_HASH_ITERATION(setup_file_hash, itr) freeSetupFileHash(setup_file_hash); } return redefined_ce_found; } static boolean CheckArtworkTypeForRedefinedCustomElements(int type) { char *filename_base, *filename_local; boolean redefined_ce_found = FALSE; setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type)); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, type)); #endif /* first look for special artwork configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(type); #if 0 printf("::: filename_base == '%s'\n", filename_base); #endif if (fileExists(filename_base)) redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base); filename_local = getCustomArtworkConfigFilename(type); #if 0 printf("::: filename_local == '%s'\n", filename_local); #endif if (filename_local != NULL && !strEqual(filename_base, filename_local)) redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local); #if 0 printf("::: redefined_ce_found == %d\n", redefined_ce_found); #endif return redefined_ce_found; } static void InitOverrideArtwork() { boolean redefined_ce_found = FALSE; /* to check if this level set redefines any CEs, do not use overriding */ gfx.override_level_graphics = FALSE; gfx.override_level_sounds = FALSE; gfx.override_level_music = FALSE; /* now check if this level set has definitions for custom elements */ if (setup.override_level_graphics == AUTO || setup.override_level_sounds == AUTO || setup.override_level_music == AUTO) redefined_ce_found = (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) | CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) | CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC)); #if 0 printf("::: redefined_ce_found == %d\n", redefined_ce_found); #endif if (redefined_ce_found) { /* this level set has CE definitions: change "AUTO" to "FALSE" */ gfx.override_level_graphics = (setup.override_level_graphics == TRUE); gfx.override_level_sounds = (setup.override_level_sounds == TRUE); gfx.override_level_music = (setup.override_level_music == TRUE); } else { /* this level set has no CE definitions: change "AUTO" to "TRUE" */ gfx.override_level_graphics = (setup.override_level_graphics != FALSE); gfx.override_level_sounds = (setup.override_level_sounds != FALSE); gfx.override_level_music = (setup.override_level_music != FALSE); } #if 0 printf("::: => %d, %d, %d\n", gfx.override_level_graphics, gfx.override_level_sounds, gfx.override_level_music); #endif } static char *getNewArtworkIdentifier(int type) { static char *leveldir_current_identifier[3] = { NULL, NULL, NULL }; static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE }; static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE }; static boolean initialized[3] = { FALSE, FALSE, FALSE }; TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); #if 1 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type); #else boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type); #endif char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type); char *leveldir_identifier = leveldir_current->identifier; #if 1 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */ char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node); #else char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type); #endif boolean has_level_artwork_set = (leveldir_artwork_set != NULL); char *artwork_current_identifier; char *artwork_new_identifier = NULL; /* default: nothing has changed */ /* leveldir_current may be invalid (level group, parent link) */ if (!validLevelSeries(leveldir_current)) return NULL; /* 1st step: determine artwork set to be activated in descending order: -------------------------------------------------------------------- 1. setup artwork (when configured to override everything else) 2. artwork set configured in "levelinfo.conf" of current level set (artwork in level directory will have priority when loading later) 3. artwork in level directory (stored in artwork sub-directory) 4. setup artwork (currently configured in setup menu) */ if (setup_override_artwork) artwork_current_identifier = setup_artwork_set; else if (leveldir_artwork_set != NULL) artwork_current_identifier = leveldir_artwork_set; else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier)) artwork_current_identifier = leveldir_identifier; else artwork_current_identifier = setup_artwork_set; /* 2nd step: check if it is really needed to reload artwork set ------------------------------------------------------------ */ #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n", artwork_new_identifier, ARTWORK_CURRENT_IDENTIFIER(artwork, type), artwork_current_identifier, leveldir_current->graphics_set, leveldir_current->identifier); #endif /* ---------- reload if level set and also artwork set has changed ------- */ if (leveldir_current_identifier[type] != leveldir_identifier && (last_has_level_artwork_set[type] || has_level_artwork_set)) artwork_new_identifier = artwork_current_identifier; leveldir_current_identifier[type] = leveldir_identifier; last_has_level_artwork_set[type] = has_level_artwork_set; #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("::: 1: '%s'\n", artwork_new_identifier); #endif /* ---------- reload if "override artwork" setting has changed ----------- */ if (last_override_level_artwork[type] != setup_override_artwork) artwork_new_identifier = artwork_current_identifier; last_override_level_artwork[type] = setup_override_artwork; #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("::: 2: '%s'\n", artwork_new_identifier); #endif /* ---------- reload if current artwork identifier has changed ----------- */ if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type), artwork_current_identifier)) artwork_new_identifier = artwork_current_identifier; *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier; #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("::: 3: '%s'\n", artwork_new_identifier); #endif /* ---------- do not reload directly after starting ---------------------- */ if (!initialized[type]) artwork_new_identifier = NULL; initialized[type] = TRUE; #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("::: 4: '%s'\n", artwork_new_identifier); #endif #if 0 if (type == ARTWORK_TYPE_GRAPHICS) printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n", artwork.gfx_current_identifier, artwork_current_identifier, artwork.gfx_current->identifier, leveldir_current->graphics_set, artwork_new_identifier); #endif return artwork_new_identifier; } void ReloadCustomArtwork(int force_reload) { int last_game_status = game_status; /* save current game status */ char *gfx_new_identifier; char *snd_new_identifier; char *mus_new_identifier; boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS)); boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS)); boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC)); boolean reload_needed; InitOverrideArtwork(); force_reload_gfx |= AdjustGraphicsForEMC(); gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS); snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS); mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC); reload_needed = (gfx_new_identifier != NULL || force_reload_gfx || snd_new_identifier != NULL || force_reload_snd || mus_new_identifier != NULL || force_reload_mus); if (!reload_needed) return; print_timestamp_init("ReloadCustomArtwork"); game_status = GAME_MODE_LOADING; FadeOut(REDRAW_ALL); #if 1 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); #else ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE); #endif print_timestamp_time("ClearRectangle"); #if 0 printf("::: fading in ... %d\n", fading.fade_mode); #endif FadeIn(REDRAW_ALL); #if 0 printf("::: done\n"); #endif if (gfx_new_identifier != NULL || force_reload_gfx) { #if 0 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n", artwork.gfx_current_identifier, gfx_new_identifier, artwork.gfx_current->identifier, leveldir_current->graphics_set); #endif InitImages(); print_timestamp_time("InitImages"); } if (snd_new_identifier != NULL || force_reload_snd) { InitSound(snd_new_identifier); print_timestamp_time("InitSound"); } if (mus_new_identifier != NULL || force_reload_mus) { InitMusic(mus_new_identifier); print_timestamp_time("InitMusic"); } game_status = last_game_status; /* restore current game status */ init_last = init; /* switch to new busy animation */ #if 0 printf("::: ----------------DELAY 1 ...\n"); Delay(3000); #endif #if 0 printf("::: FadeOut @ ReloadCustomArtwork ...\n"); #endif FadeOut(REDRAW_ALL); #if 0 printf("::: FadeOut @ ReloadCustomArtwork done\n"); #endif RedrawBackground(); /* force redraw of (open or closed) door graphics */ SetDoorState(DOOR_OPEN_ALL); CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY); #if 1 #if 1 #if 1 FadeSetEnterScreen(); FadeSkipNextFadeOut(); // FadeSetDisabled(); #else FadeSkipNext(); #endif #else fading = fading_none; #endif #endif #if 0 redraw_mask = REDRAW_ALL; #endif print_timestamp_done("ReloadCustomArtwork"); } void KeyboardAutoRepeatOffUnlessAutoplay() { if (global.autoplay_leveldir == NULL) KeyboardAutoRepeatOff(); } /* ========================================================================= */ /* OpenAll() */ /* ========================================================================= */ void OpenAll() { print_timestamp_init("OpenAll"); game_status = GAME_MODE_LOADING; #if 1 InitCounter(); #endif InitGlobal(); /* initialize some global variables */ print_timestamp_time("[init global stuff]"); if (options.execute_command) Execute_Command(options.execute_command); if (options.serveronly) { #if defined(PLATFORM_UNIX) NetworkServer(options.server_port, options.serveronly); #else Error(ERR_WARN, "networking only supported in Unix version"); #endif exit(0); /* never reached, server loops forever */ } InitSetup(); InitGameInfo(); InitPlayerInfo(); InitArtworkInfo(); /* needed before loading gfx, sound & music */ InitArtworkConfig(); /* needed before forking sound child process */ InitMixer(); #if 0 InitCounter(); #endif InitRND(NEW_RANDOMIZE); InitSimpleRandom(NEW_RANDOMIZE); InitJoysticks(); print_timestamp_time("[init setup/config stuff]"); InitVideoDisplay(); InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); InitEventFilter(FilterMouseMotionEvents); print_timestamp_time("[init video stuff]"); InitElementPropertiesStatic(); InitElementPropertiesEngine(GAME_VERSION_ACTUAL); InitElementPropertiesGfxElement(); print_timestamp_time("[init element properties stuff]"); InitGfx(); print_timestamp_time("InitGfx"); InitLevelInfo(); print_timestamp_time("InitLevelInfo"); InitLevelArtworkInfo(); print_timestamp_time("InitLevelArtworkInfo"); InitOverrideArtwork(); /* needs to know current level directory */ print_timestamp_time("InitOverrideArtwork"); InitImages(); /* needs to know current level directory */ print_timestamp_time("InitImages"); InitSound(NULL); /* needs to know current level directory */ print_timestamp_time("InitSound"); InitMusic(NULL); /* needs to know current level directory */ print_timestamp_time("InitMusic"); InitGfxBackground(); #if 1 em_open_all(); #endif #if 1 sp_open_all(); #endif if (global.autoplay_leveldir) { AutoPlayTape(); return; } else if (global.convert_leveldir) { ConvertLevels(); return; } else if (global.create_images_dir) { CreateLevelSketchImages(); return; } game_status = GAME_MODE_MAIN; #if 1 FadeSetEnterScreen(); if (!(fading.fade_mode & FADE_TYPE_TRANSFORM)) FadeSkipNextFadeOut(); // FadeSetDisabled(); #else fading = fading_none; #endif print_timestamp_time("[post-artwork]"); print_timestamp_done("OpenAll"); DrawMainMenu(); InitNetworkServer(); } void CloseAllAndExit(int exit_value) { StopSounds(); FreeAllSounds(); FreeAllMusic(); CloseAudio(); /* called after freeing sounds (needed for SDL) */ #if 1 em_close_all(); #endif #if 1 sp_close_all(); #endif FreeAllImages(); #if defined(TARGET_SDL) if (network_server) /* terminate network server */ SDL_KillThread(server_thread); #endif CloseVideoDisplay(); ClosePlatformDependentStuff(); if (exit_value != 0) NotifyUserAboutErrorFile(); exit(exit_value); } rocksndiamonds-3.3.0.1+dfsg1/src/editor.h0000644000175000017500000000217310577777422017101 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * editor.h * ***********************************************************/ #ifndef EDITOR_H #define EDITOR_H #include "main.h" void CreateLevelEditorGadgets(); void FreeLevelEditorGadgets(); void UnmapLevelEditorGadgets(); void DrawLevelEd(void); void HandleLevelEditorKeyInput(Key); void HandleLevelEditorIdle(); void HandleEditorGadgetInfoText(void *ptr); void RequestExitLevelEditor(boolean, boolean); void PrintEditorElementList(); void DumpBrush(); void DumpBrush_Small(); #endif rocksndiamonds-3.3.0.1+dfsg1/src/network.h0000644000175000017500000000232110471550176017263 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * network.h * ***********************************************************/ #ifndef NETWORK_H #define NETWORK_H #include "main.h" #define NETWORK_STOP_BY_PLAYER 0 #define NETWORK_STOP_BY_ERROR 1 boolean ConnectToServer(char *, int); void SendToServer_PlayerName(char *); void SendToServer_ProtocolVersion(void); void SendToServer_NrWanted(int); void SendToServer_StartPlaying(void); void SendToServer_PausePlaying(void); void SendToServer_ContinuePlaying(void); void SendToServer_StopPlaying(int); void SendToServer_MovePlayer(byte); void HandleNetworking(void); #endif rocksndiamonds-3.3.0.1+dfsg1/src/conf_e2g.c0000644000175000017500000031111611375255512017254 0ustar dimkadimka/*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* * (c) 1995-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * conf_e2g.c * ***********************************************************/ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_E2G_C #define CONF_E2G_C /* values for element/graphics mapping configuration (normal) */ static struct { int element; int action; int direction; boolean crumbled; int graphic; } element_to_graphic[] = { { EL_BD_WALL, -1, -1, FALSE, IMG_BD_WALL }, { EL_BD_ROCK, -1, -1, FALSE, IMG_BD_ROCK }, { EL_BD_ROCK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_BD_ROCK_MOVING_LEFT }, { EL_BD_ROCK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_BD_ROCK_MOVING_RIGHT }, { EL_BD_ROCK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_BD_ROCK_PUSHING_LEFT }, { EL_BD_ROCK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_BD_ROCK_PUSHING_RIGHT }, { EL_BD_DIAMOND, -1, -1, FALSE, IMG_BD_DIAMOND }, { EL_BD_DIAMOND, ACTION_MOVING, -1, FALSE, IMG_BD_DIAMOND_MOVING }, { EL_BD_DIAMOND, ACTION_FALLING, -1, FALSE, IMG_BD_DIAMOND_FALLING }, { EL_BD_MAGIC_WALL, -1, -1, FALSE, IMG_BD_MAGIC_WALL }, { EL_BD_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_BD_MAGIC_WALL_FULL }, { EL_BD_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_BD_MAGIC_WALL_EMPTYING }, { EL_BD_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_BD_MAGIC_WALL_EMPTYING }, { EL_BD_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_BD_MAGIC_WALL_DEAD }, { EL_BD_AMOEBA, -1, -1, FALSE, IMG_BD_AMOEBA }, { EL_BD_BUTTERFLY, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_RIGHT, -1, -1, FALSE, IMG_BD_BUTTERFLY_RIGHT }, { EL_BD_BUTTERFLY, -1, MV_BIT_RIGHT, FALSE, IMG_BD_BUTTERFLY_RIGHT }, { EL_BD_BUTTERFLY_UP, -1, -1, FALSE, IMG_BD_BUTTERFLY_UP }, { EL_BD_BUTTERFLY, -1, MV_BIT_UP, FALSE, IMG_BD_BUTTERFLY_UP }, { EL_BD_BUTTERFLY_LEFT, -1, -1, FALSE, IMG_BD_BUTTERFLY_LEFT }, { EL_BD_BUTTERFLY, -1, MV_BIT_LEFT, FALSE, IMG_BD_BUTTERFLY_LEFT }, { EL_BD_BUTTERFLY_DOWN, -1, -1, FALSE, IMG_BD_BUTTERFLY_DOWN }, { EL_BD_BUTTERFLY, -1, MV_BIT_DOWN, FALSE, IMG_BD_BUTTERFLY_DOWN }, { EL_BD_FIREFLY, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_RIGHT, -1, -1, FALSE, IMG_BD_FIREFLY_RIGHT }, { EL_BD_FIREFLY, -1, MV_BIT_RIGHT, FALSE, IMG_BD_FIREFLY_RIGHT }, { EL_BD_FIREFLY_UP, -1, -1, FALSE, IMG_BD_FIREFLY_UP }, { EL_BD_FIREFLY, -1, MV_BIT_UP, FALSE, IMG_BD_FIREFLY_UP }, { EL_BD_FIREFLY_LEFT, -1, -1, FALSE, IMG_BD_FIREFLY_LEFT }, { EL_BD_FIREFLY, -1, MV_BIT_LEFT, FALSE, IMG_BD_FIREFLY_LEFT }, { EL_BD_FIREFLY_DOWN, -1, -1, FALSE, IMG_BD_FIREFLY_DOWN }, { EL_BD_FIREFLY, -1, MV_BIT_DOWN, FALSE, IMG_BD_FIREFLY_DOWN }, { EL_SP_DEFAULT, ACTION_EXPLODING, -1, FALSE, IMG_SP_DEFAULT_EXPLODING }, { EL_SP_ZONK, -1, -1, FALSE, IMG_SP_ZONK }, { EL_SP_ZONK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_ZONK_MOVING_LEFT }, { EL_SP_ZONK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_ZONK_MOVING_RIGHT }, { EL_SP_ZONK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_SP_ZONK_PUSHING_LEFT }, { EL_SP_ZONK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_SP_ZONK_PUSHING_RIGHT }, { EL_SP_BASE, -1, -1, FALSE, IMG_SP_BASE }, { EL_SP_BASE, ACTION_DIGGING, -1, FALSE, IMG_SP_BASE_DIGGING }, { EL_SP_BASE, ACTION_SNAPPING, -1, FALSE, IMG_SP_BASE_SNAPPING }, { EL_SP_MURPHY, -1, -1, FALSE, IMG_SP_MURPHY }, { EL_SP_MURPHY, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_MOVING_LEFT }, { EL_SP_MURPHY, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_MOVING_RIGHT }, { EL_SP_MURPHY, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_DIGGING_LEFT }, { EL_SP_MURPHY, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_DIGGING_RIGHT }, { EL_SP_MURPHY, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_COLLECTING_LEFT }, { EL_SP_MURPHY, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_COLLECTING_RIGHT }, { EL_SP_MURPHY, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_PUSHING_LEFT }, { EL_SP_MURPHY, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_PUSHING_RIGHT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_SNAPPING_LEFT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_SNAPPING_RIGHT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_SP_MURPHY_SNAPPING_UP }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_SP_MURPHY_SNAPPING_DOWN }, { EL_SP_MURPHY, ACTION_BORING, -1, FALSE, IMG_SP_MURPHY_BORING }, { EL_SP_MURPHY, ACTION_BORING_1, -1, FALSE, IMG_SP_MURPHY_BORING_1 }, { EL_SP_MURPHY, ACTION_SLEEPING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_SLEEPING_LEFT }, { EL_SP_MURPHY, ACTION_SLEEPING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_SLEEPING_RIGHT }, { EL_SP_MURPHY, ACTION_DROPPING, -1, FALSE, IMG_SP_MURPHY_DROPPING }, { EL_SP_MURPHY, ACTION_SHRINKING, -1, FALSE, IMG_SP_MURPHY_SHRINKING }, { EL_SP_MURPHY_CLONE, -1, -1, FALSE, IMG_SP_MURPHY_CLONE }, { EL_SP_INFOTRON, -1, -1, FALSE, IMG_SP_INFOTRON }, { EL_SP_INFOTRON, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_INFOTRON_MOVING_LEFT }, { EL_SP_INFOTRON, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_INFOTRON_MOVING_RIGHT }, { EL_SP_INFOTRON, ACTION_COLLECTING, -1, FALSE, IMG_SP_INFOTRON_COLLECTING }, { EL_SP_CHIP_SINGLE, -1, -1, FALSE, IMG_SP_CHIP_SINGLE }, { EL_SP_CHIP_LEFT, -1, -1, FALSE, IMG_SP_CHIP_LEFT }, { EL_SP_CHIP_RIGHT, -1, -1, FALSE, IMG_SP_CHIP_RIGHT }, { EL_SP_CHIP_TOP, -1, -1, FALSE, IMG_SP_CHIP_TOP }, { EL_SP_CHIP_BOTTOM, -1, -1, FALSE, IMG_SP_CHIP_BOTTOM }, { EL_SP_HARDWARE_GRAY, -1, -1, FALSE, IMG_SP_HARDWARE_GRAY }, { EL_SP_HARDWARE_GREEN, -1, -1, FALSE, IMG_SP_HARDWARE_GREEN }, { EL_SP_HARDWARE_BLUE, -1, -1, FALSE, IMG_SP_HARDWARE_BLUE }, { EL_SP_HARDWARE_RED, -1, -1, FALSE, IMG_SP_HARDWARE_RED }, { EL_SP_HARDWARE_YELLOW, -1, -1, FALSE, IMG_SP_HARDWARE_YELLOW }, { EL_SP_EXIT_CLOSED, -1, -1, FALSE, IMG_SP_EXIT_CLOSED }, { EL_SP_EXIT_OPENING, -1, -1, FALSE, IMG_SP_EXIT_OPENING }, { EL_SP_EXIT_OPEN, -1, -1, FALSE, IMG_SP_EXIT_OPEN }, { EL_SP_EXIT_CLOSING, -1, -1, FALSE, IMG_SP_EXIT_CLOSING }, { EL_SP_DISK_ORANGE, -1, -1, FALSE, IMG_SP_DISK_ORANGE }, { EL_SP_DISK_YELLOW, -1, -1, FALSE, IMG_SP_DISK_YELLOW }, { EL_SP_DISK_RED, -1, -1, FALSE, IMG_SP_DISK_RED }, { EL_SP_DISK_RED, ACTION_COLLECTING, -1, FALSE, IMG_SP_DISK_RED_COLLECTING }, { EL_SP_DISK_RED_ACTIVE, -1, -1, FALSE, IMG_SP_DISK_RED_ACTIVE }, { EL_SP_DISK_RED, ACTION_ACTIVE, -1, FALSE, IMG_SP_DISK_RED_ACTIVE }, { EL_SP_PORT_RIGHT, -1, -1, FALSE, IMG_SP_PORT_RIGHT }, { EL_SP_PORT_DOWN, -1, -1, FALSE, IMG_SP_PORT_DOWN }, { EL_SP_PORT_LEFT, -1, -1, FALSE, IMG_SP_PORT_LEFT }, { EL_SP_PORT_UP, -1, -1, FALSE, IMG_SP_PORT_UP }, { EL_SP_PORT_HORIZONTAL, -1, -1, FALSE, IMG_SP_PORT_HORIZONTAL }, { EL_SP_PORT_VERTICAL, -1, -1, FALSE, IMG_SP_PORT_VERTICAL }, { EL_SP_PORT_ANY, -1, -1, FALSE, IMG_SP_PORT_ANY }, { EL_SP_GRAVITY_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_RIGHT }, { EL_SP_GRAVITY_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_DOWN }, { EL_SP_GRAVITY_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_LEFT }, { EL_SP_GRAVITY_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_UP }, { EL_SP_GRAVITY_ON_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_RIGHT }, { EL_SP_GRAVITY_ON_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_DOWN }, { EL_SP_GRAVITY_ON_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_UP }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_RIGHT }, { EL_SP_GRAVITY_OFF_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_DOWN }, { EL_SP_GRAVITY_OFF_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_UP }, { EL_SP_SNIKSNAK, -1, -1, FALSE, IMG_SP_SNIKSNAK }, { EL_SP_SNIKSNAK, -1, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_LEFT }, { EL_SP_SNIKSNAK, -1, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_RIGHT }, { EL_SP_SNIKSNAK, -1, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_UP }, { EL_SP_SNIKSNAK, -1, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT }, { EL_SP_ELECTRON, -1, -1, FALSE, IMG_SP_ELECTRON }, { EL_SP_ELECTRON, ACTION_EXPLODING, -1, FALSE, IMG_SP_ELECTRON_EXPLODING }, { EL_SP_TERMINAL, -1, -1, FALSE, IMG_SP_TERMINAL }, { EL_SP_TERMINAL_ACTIVE, -1, -1, FALSE, IMG_SP_TERMINAL_ACTIVE }, { EL_SP_TERMINAL, ACTION_ACTIVE, -1, FALSE, IMG_SP_TERMINAL_ACTIVE }, { EL_SP_BUGGY_BASE, -1, -1, FALSE, IMG_SP_BUGGY_BASE }, { EL_SP_BUGGY_BASE_ACTIVATING, -1, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVATING }, { EL_SP_BUGGY_BASE, ACTION_ACTIVATING, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVATING }, { EL_SP_BUGGY_BASE_ACTIVE, -1, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVE }, { EL_SP_BUGGY_BASE, ACTION_ACTIVE, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVE }, { EL_SP_HARDWARE_BASE_1, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_1 }, { EL_SP_HARDWARE_BASE_2, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_2 }, { EL_SP_HARDWARE_BASE_3, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_3 }, { EL_SP_HARDWARE_BASE_4, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_4 }, { EL_SP_HARDWARE_BASE_5, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_5 }, { EL_SP_HARDWARE_BASE_6, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_6 }, { EL_SOKOBAN_OBJECT, -1, -1, FALSE, IMG_SOKOBAN_OBJECT }, { EL_SOKOBAN_FIELD_EMPTY, -1, -1, FALSE, IMG_SOKOBAN_FIELD_EMPTY }, { EL_SOKOBAN_FIELD_FULL, -1, -1, FALSE, IMG_SOKOBAN_FIELD_FULL }, { EL_SOKOBAN_FIELD_PLAYER, -1, -1, FALSE, IMG_SOKOBAN_FIELD_PLAYER }, { EL_EMPTY_SPACE, -1, -1, FALSE, IMG_EMPTY_SPACE }, { EL_SAND, -1, -1, FALSE, IMG_SAND }, { EL_SAND, -1, -1, TRUE, IMG_SAND_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_SAND_DIGGING_LEFT }, { EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_SAND_DIGGING_RIGHT }, { EL_SAND, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_SAND_DIGGING_UP }, { EL_SAND, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_SAND_DIGGING_DOWN }, { EL_SAND, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_SAND_DIGGING_LEFT_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_SAND_DIGGING_RIGHT_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_SAND_DIGGING_UP_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_SAND_DIGGING_DOWN_CRUMBLED }, { EL_WALL, -1, -1, FALSE, IMG_WALL }, { EL_WALL_SLIPPERY, -1, -1, FALSE, IMG_WALL_SLIPPERY }, { EL_STEELWALL, -1, -1, FALSE, IMG_STEELWALL }, { EL_ROCK, -1, -1, FALSE, IMG_ROCK }, { EL_ROCK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_ROCK_MOVING_LEFT }, { EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_ROCK_MOVING_RIGHT }, { EL_ROCK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_ROCK_PUSHING_LEFT }, { EL_ROCK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_ROCK_PUSHING_RIGHT }, { EL_EMERALD, -1, -1, FALSE, IMG_EMERALD }, { EL_EMERALD, ACTION_MOVING, -1, FALSE, IMG_EMERALD_MOVING }, { EL_EMERALD, ACTION_FALLING, -1, FALSE, IMG_EMERALD_FALLING }, { EL_EMERALD, ACTION_COLLECTING, -1, FALSE, IMG_EMERALD_COLLECTING }, { EL_DIAMOND, -1, -1, FALSE, IMG_DIAMOND }, { EL_DIAMOND, ACTION_MOVING, -1, FALSE, IMG_DIAMOND_MOVING }, { EL_DIAMOND, ACTION_FALLING, -1, FALSE, IMG_DIAMOND_FALLING }, { EL_DIAMOND, ACTION_COLLECTING, -1, FALSE, IMG_DIAMOND_COLLECTING }, { EL_BOMB, -1, -1, FALSE, IMG_BOMB }, { EL_NUT, -1, -1, FALSE, IMG_NUT }, { EL_NUT_BREAKING, -1, -1, FALSE, IMG_NUT_BREAKING }, { EL_NUT, ACTION_BREAKING, -1, FALSE, IMG_NUT_BREAKING }, { EL_DYNAMITE, -1, -1, FALSE, IMG_DYNAMITE }, { EL_DYNAMITE_ACTIVE, -1, -1, FALSE, IMG_DYNAMITE_ACTIVE }, { EL_DYNAMITE, ACTION_ACTIVE, -1, FALSE, IMG_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, -1, -1, FALSE, IMG_EM_DYNAMITE }, { EL_EM_DYNAMITE_ACTIVE, -1, -1, FALSE, IMG_EM_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, ACTION_ACTIVE, -1, FALSE, IMG_EM_DYNAMITE_ACTIVE }, { EL_WALL_EMERALD, -1, -1, FALSE, IMG_WALL_EMERALD }, { EL_WALL_DIAMOND, -1, -1, FALSE, IMG_WALL_DIAMOND }, { EL_BUG, -1, -1, FALSE, IMG_BUG }, { EL_BUG_RIGHT, -1, -1, FALSE, IMG_BUG_RIGHT }, { EL_BUG, -1, MV_BIT_RIGHT, FALSE, IMG_BUG_RIGHT }, { EL_BUG_UP, -1, -1, FALSE, IMG_BUG_UP }, { EL_BUG, -1, MV_BIT_UP, FALSE, IMG_BUG_UP }, { EL_BUG_LEFT, -1, -1, FALSE, IMG_BUG_LEFT }, { EL_BUG, -1, MV_BIT_LEFT, FALSE, IMG_BUG_LEFT }, { EL_BUG_DOWN, -1, -1, FALSE, IMG_BUG_DOWN }, { EL_BUG, -1, MV_BIT_DOWN, FALSE, IMG_BUG_DOWN }, { EL_BUG, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_BUG_MOVING_RIGHT }, { EL_BUG, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_BUG_MOVING_UP }, { EL_BUG, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_BUG_MOVING_LEFT }, { EL_BUG, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_BUG_MOVING_DOWN }, { EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_BUG_TURNING_FROM_RIGHT_UP }, { EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_BUG_TURNING_FROM_UP_LEFT }, { EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_BUG_TURNING_FROM_LEFT_DOWN }, { EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_BUG_TURNING_FROM_DOWN_RIGHT }, { EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_BUG_TURNING_FROM_RIGHT_DOWN }, { EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_BUG_TURNING_FROM_UP_RIGHT }, { EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_BUG_TURNING_FROM_LEFT_UP }, { EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_BUG_TURNING_FROM_DOWN_LEFT }, { EL_SPACESHIP, -1, -1, FALSE, IMG_SPACESHIP }, { EL_SPACESHIP_RIGHT, -1, -1, FALSE, IMG_SPACESHIP_RIGHT }, { EL_SPACESHIP, -1, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_RIGHT }, { EL_SPACESHIP_UP, -1, -1, FALSE, IMG_SPACESHIP_UP }, { EL_SPACESHIP, -1, MV_BIT_UP, FALSE, IMG_SPACESHIP_UP }, { EL_SPACESHIP_LEFT, -1, -1, FALSE, IMG_SPACESHIP_LEFT }, { EL_SPACESHIP, -1, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_LEFT }, { EL_SPACESHIP_DOWN, -1, -1, FALSE, IMG_SPACESHIP_DOWN }, { EL_SPACESHIP, -1, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_DOWN }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_MOVING_RIGHT }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_SPACESHIP_MOVING_UP }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_MOVING_LEFT }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_MOVING_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_SPACESHIP_TURNING_FROM_RIGHT_UP }, { EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_TURNING_FROM_UP_LEFT }, { EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT }, { EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_TURNING_FROM_UP_RIGHT }, { EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_SPACESHIP_TURNING_FROM_LEFT_UP }, { EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT }, { EL_YAMYAM, -1, -1, FALSE, IMG_YAMYAM }, { EL_YAMYAM_LEFT, -1, -1, FALSE, IMG_YAMYAM_LEFT }, { EL_YAMYAM, -1, MV_BIT_LEFT, FALSE, IMG_YAMYAM_LEFT }, { EL_YAMYAM_RIGHT, -1, -1, FALSE, IMG_YAMYAM_RIGHT }, { EL_YAMYAM, -1, MV_BIT_RIGHT, FALSE, IMG_YAMYAM_RIGHT }, { EL_YAMYAM_UP, -1, -1, FALSE, IMG_YAMYAM_UP }, { EL_YAMYAM, -1, MV_BIT_UP, FALSE, IMG_YAMYAM_UP }, { EL_YAMYAM_DOWN, -1, -1, FALSE, IMG_YAMYAM_DOWN }, { EL_YAMYAM, -1, MV_BIT_DOWN, FALSE, IMG_YAMYAM_DOWN }, { EL_YAMYAM, ACTION_MOVING, -1, FALSE, IMG_YAMYAM_MOVING }, { EL_ROBOT, -1, -1, FALSE, IMG_ROBOT }, { EL_ROBOT, ACTION_MOVING, -1, FALSE, IMG_ROBOT_MOVING }, { EL_ROBOT_WHEEL, -1, -1, FALSE, IMG_ROBOT_WHEEL }, { EL_ROBOT_WHEEL_ACTIVE, -1, -1, FALSE, IMG_ROBOT_WHEEL_ACTIVE }, { EL_ROBOT_WHEEL, ACTION_ACTIVE, -1, FALSE, IMG_ROBOT_WHEEL_ACTIVE }, { EL_MAGIC_WALL, -1, -1, FALSE, IMG_MAGIC_WALL }, { EL_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_MAGIC_WALL_FULL }, { EL_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_MAGIC_WALL_EMPTYING }, { EL_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_MAGIC_WALL_EMPTYING }, { EL_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_MAGIC_WALL_DEAD }, { EL_DC_MAGIC_WALL, -1, -1, FALSE, IMG_DC_MAGIC_WALL }, { EL_DC_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_DC_MAGIC_WALL_FULL }, { EL_DC_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_DC_MAGIC_WALL_EMPTYING }, { EL_DC_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_DC_MAGIC_WALL_EMPTYING }, { EL_DC_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_DC_MAGIC_WALL_DEAD }, { EL_QUICKSAND_EMPTY, -1, -1, FALSE, IMG_QUICKSAND_EMPTY }, { EL_QUICKSAND_FILLING, -1, -1, FALSE, IMG_QUICKSAND_FILLING }, { EL_QUICKSAND_FULL, -1, -1, FALSE, IMG_QUICKSAND_FULL }, { EL_QUICKSAND_EMPTYING, -1, -1, FALSE, IMG_QUICKSAND_EMPTYING }, { EL_QUICKSAND_FAST_EMPTY, -1, -1, FALSE, IMG_QUICKSAND_FAST_EMPTY }, { EL_QUICKSAND_FAST_FILLING, -1, -1, FALSE, IMG_QUICKSAND_FAST_FILLING }, { EL_QUICKSAND_FAST_FULL, -1, -1, FALSE, IMG_QUICKSAND_FAST_FULL }, { EL_QUICKSAND_FAST_EMPTYING, -1, -1, FALSE, IMG_QUICKSAND_FAST_EMPTYING }, { EL_ACID_POOL_TOPLEFT, -1, -1, FALSE, IMG_ACID_POOL_TOPLEFT }, { EL_ACID_POOL_TOPRIGHT, -1, -1, FALSE, IMG_ACID_POOL_TOPRIGHT }, { EL_ACID_POOL_BOTTOMLEFT, -1, -1, FALSE, IMG_ACID_POOL_BOTTOMLEFT }, { EL_ACID_POOL_BOTTOM, -1, -1, FALSE, IMG_ACID_POOL_BOTTOM }, { EL_ACID_POOL_BOTTOMRIGHT, -1, -1, FALSE, IMG_ACID_POOL_BOTTOMRIGHT }, { EL_ACID, -1, -1, FALSE, IMG_ACID }, { EL_ACID_SPLASH_LEFT, -1, -1, FALSE, IMG_ACID_SPLASH_LEFT }, { EL_ACID_SPLASH_RIGHT, -1, -1, FALSE, IMG_ACID_SPLASH_RIGHT }, { EL_AMOEBA_DROP, -1, -1, FALSE, IMG_AMOEBA_DROP }, { EL_AMOEBA_GROWING, -1, -1, FALSE, IMG_AMOEBA_GROWING }, { EL_AMOEBA, ACTION_GROWING, -1, FALSE, IMG_AMOEBA_GROWING }, { EL_AMOEBA_SHRINKING, -1, -1, FALSE, IMG_AMOEBA_SHRINKING }, { EL_AMOEBA, ACTION_SHRINKING, -1, FALSE, IMG_AMOEBA_SHRINKING }, { EL_AMOEBA_WET, -1, -1, FALSE, IMG_AMOEBA_WET }, { EL_AMOEBA_DROPPING, -1, -1, FALSE, IMG_AMOEBA_DROPPING }, { EL_AMOEBA, ACTION_DROPPING, -1, FALSE, IMG_AMOEBA_DROPPING }, { EL_AMOEBA_DRY, -1, -1, FALSE, IMG_AMOEBA_DRY }, { EL_AMOEBA_FULL, -1, -1, FALSE, IMG_AMOEBA_FULL }, { EL_AMOEBA_DEAD, -1, -1, FALSE, IMG_AMOEBA_DEAD }, { EL_EM_KEY_1, -1, -1, FALSE, IMG_EM_KEY_1 }, { EL_EM_KEY_2, -1, -1, FALSE, IMG_EM_KEY_2 }, { EL_EM_KEY_3, -1, -1, FALSE, IMG_EM_KEY_3 }, { EL_EM_KEY_4, -1, -1, FALSE, IMG_EM_KEY_4 }, { EL_DC_KEY_WHITE, -1, -1, FALSE, IMG_DC_KEY_WHITE }, { EL_EM_GATE_1, -1, -1, FALSE, IMG_EM_GATE_1 }, { EL_EM_GATE_2, -1, -1, FALSE, IMG_EM_GATE_2 }, { EL_EM_GATE_3, -1, -1, FALSE, IMG_EM_GATE_3 }, { EL_EM_GATE_4, -1, -1, FALSE, IMG_EM_GATE_4 }, { EL_DC_GATE_WHITE, -1, -1, FALSE, IMG_DC_GATE_WHITE }, { EL_EM_GATE_1_GRAY, -1, -1, FALSE, IMG_EM_GATE_1_GRAY }, { EL_EM_GATE_1_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_1_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, -1, -1, FALSE, IMG_EM_GATE_2_GRAY }, { EL_EM_GATE_2_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, -1, -1, FALSE, IMG_EM_GATE_3_GRAY }, { EL_EM_GATE_3_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, -1, -1, FALSE, IMG_EM_GATE_4_GRAY }, { EL_EM_GATE_4_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_4_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_4_GRAY_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, -1, -1, FALSE, IMG_DC_GATE_WHITE_GRAY }, { EL_DC_GATE_WHITE_GRAY_ACTIVE, -1, -1, FALSE, IMG_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_GATE_FAKE_GRAY, -1, -1, FALSE, IMG_DC_GATE_FAKE_GRAY }, { EL_EXIT_CLOSED, -1, -1, FALSE, IMG_EXIT_CLOSED }, { EL_EXIT_OPENING, -1, -1, FALSE, IMG_EXIT_OPENING }, { EL_EXIT_OPEN, -1, -1, FALSE, IMG_EXIT_OPEN }, { EL_EXIT_CLOSING, -1, -1, FALSE, IMG_EXIT_CLOSING }, { EL_STEEL_EXIT_CLOSED, -1, -1, FALSE, IMG_STEEL_EXIT_CLOSED }, { EL_STEEL_EXIT_OPENING, -1, -1, FALSE, IMG_STEEL_EXIT_OPENING }, { EL_STEEL_EXIT_OPEN, -1, -1, FALSE, IMG_STEEL_EXIT_OPEN }, { EL_STEEL_EXIT_CLOSING, -1, -1, FALSE, IMG_STEEL_EXIT_CLOSING }, { EL_EM_EXIT_CLOSED, -1, -1, FALSE, IMG_EM_EXIT_CLOSED }, { EL_EM_EXIT_OPENING, -1, -1, FALSE, IMG_EM_EXIT_OPENING }, { EL_EM_EXIT_OPEN, -1, -1, FALSE, IMG_EM_EXIT_OPEN }, { EL_EM_EXIT_CLOSING, -1, -1, FALSE, IMG_EM_EXIT_CLOSING }, { EL_EM_STEEL_EXIT_CLOSED, -1, -1, FALSE, IMG_EM_STEEL_EXIT_CLOSED }, { EL_EM_STEEL_EXIT_OPENING, -1, -1, FALSE, IMG_EM_STEEL_EXIT_OPENING }, { EL_EM_STEEL_EXIT_OPEN, -1, -1, FALSE, IMG_EM_STEEL_EXIT_OPEN }, { EL_EM_STEEL_EXIT_CLOSING, -1, -1, FALSE, IMG_EM_STEEL_EXIT_CLOSING }, { EL_BALLOON, -1, -1, FALSE, IMG_BALLOON }, { EL_BALLOON, ACTION_MOVING, -1, FALSE, IMG_BALLOON_MOVING }, { EL_BALLOON, ACTION_PUSHING, -1, FALSE, IMG_BALLOON_PUSHING }, { EL_BALLOON_SWITCH_LEFT, -1, -1, FALSE, IMG_BALLOON_SWITCH_LEFT }, { EL_BALLOON_SWITCH_RIGHT, -1, -1, FALSE, IMG_BALLOON_SWITCH_RIGHT }, { EL_BALLOON_SWITCH_UP, -1, -1, FALSE, IMG_BALLOON_SWITCH_UP }, { EL_BALLOON_SWITCH_DOWN, -1, -1, FALSE, IMG_BALLOON_SWITCH_DOWN }, { EL_BALLOON_SWITCH_ANY, -1, -1, FALSE, IMG_BALLOON_SWITCH_ANY }, { EL_BALLOON_SWITCH_NONE, -1, -1, FALSE, IMG_BALLOON_SWITCH_NONE }, { EL_SPRING, -1, -1, FALSE, IMG_SPRING }, { EL_EMC_STEELWALL_1, -1, -1, FALSE, IMG_EMC_STEELWALL_1 }, { EL_EMC_STEELWALL_2, -1, -1, FALSE, IMG_EMC_STEELWALL_2 }, { EL_EMC_STEELWALL_3, -1, -1, FALSE, IMG_EMC_STEELWALL_3 }, { EL_EMC_STEELWALL_4, -1, -1, FALSE, IMG_EMC_STEELWALL_4 }, { EL_EMC_WALL_1, -1, -1, FALSE, IMG_EMC_WALL_1 }, { EL_EMC_WALL_2, -1, -1, FALSE, IMG_EMC_WALL_2 }, { EL_EMC_WALL_3, -1, -1, FALSE, IMG_EMC_WALL_3 }, { EL_EMC_WALL_4, -1, -1, FALSE, IMG_EMC_WALL_4 }, { EL_EMC_WALL_5, -1, -1, FALSE, IMG_EMC_WALL_5 }, { EL_EMC_WALL_6, -1, -1, FALSE, IMG_EMC_WALL_6 }, { EL_EMC_WALL_7, -1, -1, FALSE, IMG_EMC_WALL_7 }, { EL_EMC_WALL_8, -1, -1, FALSE, IMG_EMC_WALL_8 }, { EL_INVISIBLE_STEELWALL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL }, { EL_INVISIBLE_STEELWALL_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_STEELWALL, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_WALL, -1, -1, FALSE, IMG_INVISIBLE_WALL }, { EL_INVISIBLE_WALL_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_WALL_ACTIVE }, { EL_INVISIBLE_WALL, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_WALL_ACTIVE }, { EL_INVISIBLE_SAND, -1, -1, FALSE, IMG_INVISIBLE_SAND }, { EL_INVISIBLE_SAND_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_SAND, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_SAND, ACTION_ACTIVE, -1, TRUE, IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, -1, -1, TRUE, IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED }, { EL_CONVEYOR_BELT_1_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE }, { EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT }, { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT }, { EL_CONVEYOR_BELT_1_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_LEFT }, { EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_1_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_2_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE }, { EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT }, { EL_CONVEYOR_BELT_2_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT }, { EL_CONVEYOR_BELT_2_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_LEFT }, { EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_2_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_3_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE }, { EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT }, { EL_CONVEYOR_BELT_3_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT }, { EL_CONVEYOR_BELT_3_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_LEFT }, { EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_3_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_4_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE }, { EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT }, { EL_CONVEYOR_BELT_4_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT }, { EL_CONVEYOR_BELT_4_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_LEFT }, { EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_4_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_RIGHT }, { EL_SWITCHGATE_SWITCH_UP, -1, -1, FALSE, IMG_SWITCHGATE_SWITCH_UP }, { EL_SWITCHGATE_SWITCH_DOWN, -1, -1, FALSE, IMG_SWITCHGATE_SWITCH_DOWN }, { EL_DC_SWITCHGATE_SWITCH_UP, -1, -1, FALSE, IMG_DC_SWITCHGATE_SWITCH_UP }, { EL_DC_SWITCHGATE_SWITCH_DOWN, -1, -1, FALSE, IMG_DC_SWITCHGATE_SWITCH_DOWN }, { EL_LIGHT_SWITCH, -1, -1, FALSE, IMG_LIGHT_SWITCH }, { EL_LIGHT_SWITCH_ACTIVE, -1, -1, FALSE, IMG_LIGHT_SWITCH_ACTIVE }, { EL_LIGHT_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_LIGHT_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH, -1, -1, FALSE, IMG_TIMEGATE_SWITCH }, { EL_TIMEGATE_SWITCH_ACTIVE, -1, -1, FALSE, IMG_TIMEGATE_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_TIMEGATE_SWITCH_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, -1, -1, FALSE, IMG_DC_TIMEGATE_SWITCH }, { EL_DC_TIMEGATE_SWITCH_ACTIVE, -1, -1, FALSE, IMG_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_ENVELOPE_1, -1, -1, FALSE, IMG_ENVELOPE_1 }, { EL_ENVELOPE_1, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_1_COLLECTING }, { EL_ENVELOPE_2, -1, -1, FALSE, IMG_ENVELOPE_2 }, { EL_ENVELOPE_2, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_2_COLLECTING }, { EL_ENVELOPE_3, -1, -1, FALSE, IMG_ENVELOPE_3 }, { EL_ENVELOPE_3, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_3_COLLECTING }, { EL_ENVELOPE_4, -1, -1, FALSE, IMG_ENVELOPE_4 }, { EL_ENVELOPE_4, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_4_COLLECTING }, { EL_SIGN_RADIOACTIVITY, -1, -1, FALSE, IMG_SIGN_RADIOACTIVITY }, { EL_SIGN_GIVE_WAY, -1, -1, FALSE, IMG_SIGN_GIVE_WAY }, { EL_SIGN_NO_ENTRY, -1, -1, FALSE, IMG_SIGN_NO_ENTRY }, { EL_SIGN_EMERGENCY_EXIT, -1, -1, FALSE, IMG_SIGN_EMERGENCY_EXIT }, { EL_SIGN_YIN_YANG, -1, -1, FALSE, IMG_SIGN_YIN_YANG }, { EL_SIGN_EXCLAMATION, -1, -1, FALSE, IMG_SIGN_EXCLAMATION }, { EL_SIGN_STOP, -1, -1, FALSE, IMG_SIGN_STOP }, { EL_SIGN_PARKING, -1, -1, FALSE, IMG_SIGN_PARKING }, { EL_SIGN_WHEELCHAIR, -1, -1, FALSE, IMG_SIGN_WHEELCHAIR }, { EL_SIGN_ENTRY_FORBIDDEN, -1, -1, FALSE, IMG_SIGN_ENTRY_FORBIDDEN }, { EL_SPERMS, -1, -1, FALSE, IMG_SPERMS }, { EL_BULLET, -1, -1, FALSE, IMG_BULLET }, { EL_HEART, -1, -1, FALSE, IMG_HEART }, { EL_CROSS, -1, -1, FALSE, IMG_CROSS }, { EL_FRANKIE, -1, -1, FALSE, IMG_FRANKIE }, { EL_SIGN_SPERMS, -1, -1, FALSE, IMG_SIGN_SPERMS }, { EL_SIGN_BULLET, -1, -1, FALSE, IMG_SIGN_BULLET }, { EL_SIGN_HEART, -1, -1, FALSE, IMG_SIGN_HEART }, { EL_SIGN_CROSS, -1, -1, FALSE, IMG_SIGN_CROSS }, { EL_SIGN_FRANKIE, -1, -1, FALSE, IMG_SIGN_FRANKIE }, { EL_LANDMINE, -1, -1, FALSE, IMG_LANDMINE }, { EL_DC_LANDMINE, -1, -1, FALSE, IMG_DC_LANDMINE }, { EL_STEELWALL_SLIPPERY, -1, -1, FALSE, IMG_STEELWALL_SLIPPERY }, { EL_EXTRA_TIME, -1, -1, FALSE, IMG_EXTRA_TIME }, { EL_SHIELD_NORMAL, -1, -1, FALSE, IMG_SHIELD_NORMAL }, { EL_SHIELD_NORMAL_ACTIVE, -1, -1, FALSE, IMG_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_NORMAL, ACTION_ACTIVE, -1, FALSE, IMG_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_DEADLY, -1, -1, FALSE, IMG_SHIELD_DEADLY }, { EL_SHIELD_DEADLY_ACTIVE, -1, -1, FALSE, IMG_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_DEADLY, ACTION_ACTIVE, -1, FALSE, IMG_SHIELD_DEADLY_ACTIVE }, { EL_SWITCHGATE_CLOSED, -1, -1, FALSE, IMG_SWITCHGATE_CLOSED }, { EL_SWITCHGATE_OPENING, -1, -1, FALSE, IMG_SWITCHGATE_OPENING }, { EL_SWITCHGATE_OPEN, -1, -1, FALSE, IMG_SWITCHGATE_OPEN }, { EL_SWITCHGATE_CLOSING, -1, -1, FALSE, IMG_SWITCHGATE_CLOSING }, { EL_TIMEGATE_CLOSED, -1, -1, FALSE, IMG_TIMEGATE_CLOSED }, { EL_TIMEGATE_OPENING, -1, -1, FALSE, IMG_TIMEGATE_OPENING }, { EL_TIMEGATE_OPEN, -1, -1, FALSE, IMG_TIMEGATE_OPEN }, { EL_TIMEGATE_CLOSING, -1, -1, FALSE, IMG_TIMEGATE_CLOSING }, { EL_PEARL, -1, -1, FALSE, IMG_PEARL }, { EL_PEARL_BREAKING, -1, -1, FALSE, IMG_PEARL_BREAKING }, { EL_PEARL, ACTION_BREAKING, -1, FALSE, IMG_PEARL_BREAKING }, { EL_CRYSTAL, -1, -1, FALSE, IMG_CRYSTAL }, { EL_WALL_PEARL, -1, -1, FALSE, IMG_WALL_PEARL }, { EL_WALL_CRYSTAL, -1, -1, FALSE, IMG_WALL_CRYSTAL }, { EL_DC_STEELWALL_1_LEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_LEFT }, { EL_DC_STEELWALL_1_RIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_RIGHT }, { EL_DC_STEELWALL_1_TOP, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOP }, { EL_DC_STEELWALL_1_BOTTOM, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOM }, { EL_DC_STEELWALL_1_HORIZONTAL, -1, -1, FALSE, IMG_DC_STEELWALL_1_HORIZONTAL }, { EL_DC_STEELWALL_1_VERTICAL, -1, -1, FALSE, IMG_DC_STEELWALL_1_VERTICAL }, { EL_DC_STEELWALL_1_TOPLEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPLEFT }, { EL_DC_STEELWALL_1_TOPRIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPRIGHT }, { EL_DC_STEELWALL_1_BOTTOMLEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMLEFT }, { EL_DC_STEELWALL_1_BOTTOMRIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMRIGHT }, { EL_DC_STEELWALL_1_TOPLEFT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPLEFT_2 }, { EL_DC_STEELWALL_1_TOPRIGHT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPRIGHT_2 }, { EL_DC_STEELWALL_1_BOTTOMLEFT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMLEFT_2 }, { EL_DC_STEELWALL_1_BOTTOMRIGHT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMRIGHT_2 }, { EL_DC_STEELWALL_2_LEFT, -1, -1, FALSE, IMG_DC_STEELWALL_2_LEFT }, { EL_DC_STEELWALL_2_RIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_2_RIGHT }, { EL_DC_STEELWALL_2_TOP, -1, -1, FALSE, IMG_DC_STEELWALL_2_TOP }, { EL_DC_STEELWALL_2_BOTTOM, -1, -1, FALSE, IMG_DC_STEELWALL_2_BOTTOM }, { EL_DC_STEELWALL_2_HORIZONTAL, -1, -1, FALSE, IMG_DC_STEELWALL_2_HORIZONTAL }, { EL_DC_STEELWALL_2_VERTICAL, -1, -1, FALSE, IMG_DC_STEELWALL_2_VERTICAL }, { EL_DC_STEELWALL_2_MIDDLE, -1, -1, FALSE, IMG_DC_STEELWALL_2_MIDDLE }, { EL_DC_STEELWALL_2_SINGLE, -1, -1, FALSE, IMG_DC_STEELWALL_2_SINGLE }, { EL_TUBE_RIGHT_DOWN, -1, -1, FALSE, IMG_TUBE_RIGHT_DOWN }, { EL_TUBE_HORIZONTAL_DOWN, -1, -1, FALSE, IMG_TUBE_HORIZONTAL_DOWN }, { EL_TUBE_LEFT_DOWN, -1, -1, FALSE, IMG_TUBE_LEFT_DOWN }, { EL_TUBE_HORIZONTAL, -1, -1, FALSE, IMG_TUBE_HORIZONTAL }, { EL_TUBE_VERTICAL_RIGHT, -1, -1, FALSE, IMG_TUBE_VERTICAL_RIGHT }, { EL_TUBE_ANY, -1, -1, FALSE, IMG_TUBE_ANY }, { EL_TUBE_VERTICAL_LEFT, -1, -1, FALSE, IMG_TUBE_VERTICAL_LEFT }, { EL_TUBE_VERTICAL, -1, -1, FALSE, IMG_TUBE_VERTICAL }, { EL_TUBE_RIGHT_UP, -1, -1, FALSE, IMG_TUBE_RIGHT_UP }, { EL_TUBE_HORIZONTAL_UP, -1, -1, FALSE, IMG_TUBE_HORIZONTAL_UP }, { EL_TUBE_LEFT_UP, -1, -1, FALSE, IMG_TUBE_LEFT_UP }, { EL_TRAP, -1, -1, FALSE, IMG_TRAP }, { EL_TRAP_ACTIVE, -1, -1, FALSE, IMG_TRAP_ACTIVE }, { EL_TRAP, ACTION_ACTIVE, -1, FALSE, IMG_TRAP_ACTIVE }, { EL_DX_SUPABOMB, -1, -1, FALSE, IMG_DX_SUPABOMB }, { EL_KEY_1, -1, -1, FALSE, IMG_KEY_1 }, { EL_KEY_2, -1, -1, FALSE, IMG_KEY_2 }, { EL_KEY_3, -1, -1, FALSE, IMG_KEY_3 }, { EL_KEY_4, -1, -1, FALSE, IMG_KEY_4 }, { EL_GATE_1, -1, -1, FALSE, IMG_GATE_1 }, { EL_GATE_2, -1, -1, FALSE, IMG_GATE_2 }, { EL_GATE_3, -1, -1, FALSE, IMG_GATE_3 }, { EL_GATE_4, -1, -1, FALSE, IMG_GATE_4 }, { EL_GATE_1_GRAY, -1, -1, FALSE, IMG_GATE_1_GRAY }, { EL_GATE_1_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_1_GRAY_ACTIVE }, { EL_GATE_1_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_1_GRAY_ACTIVE }, { EL_GATE_2_GRAY, -1, -1, FALSE, IMG_GATE_2_GRAY }, { EL_GATE_2_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_2_GRAY_ACTIVE }, { EL_GATE_2_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_2_GRAY_ACTIVE }, { EL_GATE_3_GRAY, -1, -1, FALSE, IMG_GATE_3_GRAY }, { EL_GATE_3_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_3_GRAY_ACTIVE }, { EL_GATE_3_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_3_GRAY_ACTIVE }, { EL_GATE_4_GRAY, -1, -1, FALSE, IMG_GATE_4_GRAY }, { EL_GATE_4_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_4_GRAY_ACTIVE }, { EL_GATE_4_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_4_GRAY_ACTIVE }, { EL_GAME_OF_LIFE, -1, -1, FALSE, IMG_GAME_OF_LIFE }, { EL_BIOMAZE, -1, -1, FALSE, IMG_BIOMAZE }, { EL_PACMAN, -1, -1, FALSE, IMG_PACMAN }, { EL_PACMAN_RIGHT, -1, -1, FALSE, IMG_PACMAN_RIGHT }, { EL_PACMAN, -1, MV_BIT_RIGHT, FALSE, IMG_PACMAN_RIGHT }, { EL_PACMAN_UP, -1, -1, FALSE, IMG_PACMAN_UP }, { EL_PACMAN, -1, MV_BIT_UP, FALSE, IMG_PACMAN_UP }, { EL_PACMAN_LEFT, -1, -1, FALSE, IMG_PACMAN_LEFT }, { EL_PACMAN, -1, MV_BIT_LEFT, FALSE, IMG_PACMAN_LEFT }, { EL_PACMAN_DOWN, -1, -1, FALSE, IMG_PACMAN_DOWN }, { EL_PACMAN, -1, MV_BIT_DOWN, FALSE, IMG_PACMAN_DOWN }, { EL_PACMAN, ACTION_TURNING_FROM_RIGHT, -1, FALSE, IMG_PACMAN_TURNING_FROM_RIGHT }, { EL_PACMAN, ACTION_TURNING_FROM_UP, -1, FALSE, IMG_PACMAN_TURNING_FROM_UP }, { EL_PACMAN, ACTION_TURNING_FROM_LEFT, -1, FALSE, IMG_PACMAN_TURNING_FROM_LEFT }, { EL_PACMAN, ACTION_TURNING_FROM_DOWN, -1, FALSE, IMG_PACMAN_TURNING_FROM_DOWN }, { EL_LAMP, -1, -1, FALSE, IMG_LAMP }, { EL_LAMP_ACTIVE, -1, -1, FALSE, IMG_LAMP_ACTIVE }, { EL_LAMP, ACTION_ACTIVE, -1, FALSE, IMG_LAMP_ACTIVE }, { EL_TIME_ORB_FULL, -1, -1, FALSE, IMG_TIME_ORB_FULL }, { EL_TIME_ORB_EMPTY, -1, -1, FALSE, IMG_TIME_ORB_EMPTY }, { EL_EMERALD_YELLOW, -1, -1, FALSE, IMG_EMERALD_YELLOW }, { EL_EMERALD_YELLOW, ACTION_MOVING, -1, FALSE, IMG_EMERALD_YELLOW_MOVING }, { EL_EMERALD_YELLOW, ACTION_FALLING, -1, FALSE, IMG_EMERALD_YELLOW_FALLING }, { EL_EMERALD_RED, -1, -1, FALSE, IMG_EMERALD_RED }, { EL_EMERALD_RED, ACTION_MOVING, -1, FALSE, IMG_EMERALD_RED_MOVING }, { EL_EMERALD_RED, ACTION_FALLING, -1, FALSE, IMG_EMERALD_RED_FALLING }, { EL_EMERALD_PURPLE, -1, -1, FALSE, IMG_EMERALD_PURPLE }, { EL_EMERALD_PURPLE, ACTION_MOVING, -1, FALSE, IMG_EMERALD_PURPLE_MOVING }, { EL_EMERALD_PURPLE, ACTION_FALLING, -1, FALSE, IMG_EMERALD_PURPLE_FALLING }, { EL_WALL_EMERALD_YELLOW, -1, -1, FALSE, IMG_WALL_EMERALD_YELLOW }, { EL_WALL_EMERALD_RED, -1, -1, FALSE, IMG_WALL_EMERALD_RED }, { EL_WALL_EMERALD_PURPLE, -1, -1, FALSE, IMG_WALL_EMERALD_PURPLE }, { EL_WALL_BD_DIAMOND, -1, -1, FALSE, IMG_WALL_BD_DIAMOND }, { EL_EXPANDABLE_WALL, -1, -1, FALSE, IMG_EXPANDABLE_WALL }, { EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1, FALSE, IMG_EXPANDABLE_WALL_HORIZONTAL }, { EL_EXPANDABLE_WALL_VERTICAL, -1, -1, FALSE, IMG_EXPANDABLE_WALL_VERTICAL }, { EL_EXPANDABLE_WALL_ANY, -1, -1, FALSE, IMG_EXPANDABLE_WALL_ANY }, { EL_EXPANDABLE_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_HORIZONTAL }, { EL_EXPANDABLE_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_VERTICAL }, { EL_EXPANDABLE_STEELWALL_ANY, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_ANY }, { EL_BD_EXPANDABLE_WALL, -1, -1, FALSE, IMG_BD_EXPANDABLE_WALL }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_WALL_GROWING_LEFT }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_WALL_GROWING_LEFT }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_WALL_GROWING_RIGHT }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_WALL_GROWING_RIGHT }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_UP, FALSE, IMG_EXPANDABLE_WALL_GROWING_UP }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_UP, FALSE, IMG_EXPANDABLE_WALL_GROWING_UP }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_WALL_GROWING_DOWN }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_WALL_GROWING_DOWN }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_UP, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_UP }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_UP, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_UP }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN }, { EL_BLACK_ORB, -1, -1, FALSE, IMG_BLACK_ORB }, { EL_SPEED_PILL, -1, -1, FALSE, IMG_SPEED_PILL }, { EL_DARK_YAMYAM, -1, -1, FALSE, IMG_DARK_YAMYAM }, { EL_DYNABOMB, -1, -1, FALSE, IMG_DYNABOMB }, { EL_DYNABOMB_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_ACTIVE }, { EL_DYNABOMB, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_ACTIVE }, { EL_DYNABOMB_PLAYER_1, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_1 }, { EL_DYNABOMB_PLAYER_1_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_1, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_2, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_2 }, { EL_DYNABOMB_PLAYER_2_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_2, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_3, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_3 }, { EL_DYNABOMB_PLAYER_3_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_3, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_4, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_4 }, { EL_DYNABOMB_PLAYER_4_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNABOMB_PLAYER_4, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNABOMB_INCREASE_NUMBER, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_NUMBER }, { EL_DYNABOMB_INCREASE_SIZE, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_SIZE }, { EL_DYNABOMB_INCREASE_POWER, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_POWER }, { EL_PIG, -1, -1, FALSE, IMG_PIG }, { EL_PIG, -1, MV_BIT_DOWN, FALSE, IMG_PIG_DOWN }, { EL_PIG, -1, MV_BIT_UP, FALSE, IMG_PIG_UP }, { EL_PIG, -1, MV_BIT_LEFT, FALSE, IMG_PIG_LEFT }, { EL_PIG, -1, MV_BIT_RIGHT, FALSE, IMG_PIG_RIGHT }, { EL_PIG, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PIG_MOVING_DOWN }, { EL_PIG, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PIG_MOVING_UP }, { EL_PIG, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PIG_MOVING_LEFT }, { EL_PIG, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PIG_MOVING_RIGHT }, { EL_PIG, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PIG_DIGGING_DOWN }, { EL_PIG, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PIG_DIGGING_UP }, { EL_PIG, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PIG_DIGGING_LEFT }, { EL_PIG, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PIG_DIGGING_RIGHT }, { EL_DRAGON, -1, -1, FALSE, IMG_DRAGON }, { EL_DRAGON, -1, MV_BIT_DOWN, FALSE, IMG_DRAGON_DOWN }, { EL_DRAGON, -1, MV_BIT_UP, FALSE, IMG_DRAGON_UP }, { EL_DRAGON, -1, MV_BIT_LEFT, FALSE, IMG_DRAGON_LEFT }, { EL_DRAGON, -1, MV_BIT_RIGHT, FALSE, IMG_DRAGON_RIGHT }, { EL_DRAGON, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_DRAGON_MOVING_DOWN }, { EL_DRAGON, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_DRAGON_MOVING_UP }, { EL_DRAGON, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_DRAGON_MOVING_LEFT }, { EL_DRAGON, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_DRAGON_MOVING_RIGHT }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_DOWN, FALSE, IMG_DRAGON_ATTACKING_DOWN }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_UP, FALSE, IMG_DRAGON_ATTACKING_UP }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_LEFT, FALSE, IMG_DRAGON_ATTACKING_LEFT }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_RIGHT, FALSE, IMG_DRAGON_ATTACKING_RIGHT }, { EL_MOLE, -1, -1, FALSE, IMG_MOLE }, { EL_MOLE_DOWN, -1, -1, FALSE, IMG_MOLE_DOWN }, { EL_MOLE, -1, MV_BIT_DOWN, FALSE, IMG_MOLE_DOWN }, { EL_MOLE_UP, -1, -1, FALSE, IMG_MOLE_UP }, { EL_MOLE, -1, MV_BIT_UP, FALSE, IMG_MOLE_UP }, { EL_MOLE_LEFT, -1, -1, FALSE, IMG_MOLE_LEFT }, { EL_MOLE, -1, MV_BIT_LEFT, FALSE, IMG_MOLE_LEFT }, { EL_MOLE_RIGHT, -1, -1, FALSE, IMG_MOLE_RIGHT }, { EL_MOLE, -1, MV_BIT_RIGHT, FALSE, IMG_MOLE_RIGHT }, { EL_MOLE, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_MOLE_MOVING_DOWN }, { EL_MOLE, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_MOLE_MOVING_UP }, { EL_MOLE, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_MOLE_MOVING_LEFT }, { EL_MOLE, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_MOLE_MOVING_RIGHT }, { EL_MOLE, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_MOLE_DIGGING_DOWN }, { EL_MOLE, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_MOLE_DIGGING_UP }, { EL_MOLE, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_MOLE_DIGGING_LEFT }, { EL_MOLE, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_MOLE_DIGGING_RIGHT }, { EL_PENGUIN, -1, -1, FALSE, IMG_PENGUIN }, { EL_PENGUIN, -1, MV_BIT_DOWN, FALSE, IMG_PENGUIN_DOWN }, { EL_PENGUIN, -1, MV_BIT_UP, FALSE, IMG_PENGUIN_UP }, { EL_PENGUIN, -1, MV_BIT_LEFT, FALSE, IMG_PENGUIN_LEFT }, { EL_PENGUIN, -1, MV_BIT_RIGHT, FALSE, IMG_PENGUIN_RIGHT }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PENGUIN_MOVING_DOWN }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PENGUIN_MOVING_UP }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PENGUIN_MOVING_LEFT }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PENGUIN_MOVING_RIGHT }, { EL_SATELLITE, -1, -1, FALSE, IMG_SATELLITE }, { EL_STONEBLOCK, -1, -1, FALSE, IMG_STONEBLOCK }, { EL_PLAYER_1, -1, -1, FALSE, IMG_PLAYER_1 }, { EL_PLAYER_1, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_DOWN }, { EL_PLAYER_1, -1, MV_BIT_UP, FALSE, IMG_PLAYER_1_UP }, { EL_PLAYER_1, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_LEFT }, { EL_PLAYER_1, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_RIGHT }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_MOVING_DOWN }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_1_MOVING_UP }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_MOVING_LEFT }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_MOVING_RIGHT }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_DIGGING_DOWN }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_1_DIGGING_UP }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_DIGGING_LEFT }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_DIGGING_RIGHT }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_COLLECTING_DOWN }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_1_COLLECTING_UP }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_COLLECTING_LEFT }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_COLLECTING_RIGHT }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_PUSHING_DOWN }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_1_PUSHING_UP }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_PUSHING_LEFT }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_PUSHING_RIGHT }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_SNAPPING_DOWN }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_1_SNAPPING_UP }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_SNAPPING_LEFT }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_SNAPPING_RIGHT }, { EL_PLAYER_2, -1, -1, FALSE, IMG_PLAYER_2 }, { EL_PLAYER_2, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_DOWN }, { EL_PLAYER_2, -1, MV_BIT_UP, FALSE, IMG_PLAYER_2_UP }, { EL_PLAYER_2, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_LEFT }, { EL_PLAYER_2, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_RIGHT }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_MOVING_DOWN }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_2_MOVING_UP }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_MOVING_LEFT }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_MOVING_RIGHT }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_DIGGING_DOWN }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_2_DIGGING_UP }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_DIGGING_LEFT }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_DIGGING_RIGHT }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_COLLECTING_DOWN }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_2_COLLECTING_UP }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_COLLECTING_LEFT }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_COLLECTING_RIGHT }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_PUSHING_DOWN }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_2_PUSHING_UP }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_PUSHING_LEFT }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_PUSHING_RIGHT }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_SNAPPING_DOWN }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_2_SNAPPING_UP }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_SNAPPING_LEFT }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_SNAPPING_RIGHT }, { EL_PLAYER_3, -1, -1, FALSE, IMG_PLAYER_3 }, { EL_PLAYER_3, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_DOWN }, { EL_PLAYER_3, -1, MV_BIT_UP, FALSE, IMG_PLAYER_3_UP }, { EL_PLAYER_3, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_LEFT }, { EL_PLAYER_3, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_RIGHT }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_MOVING_DOWN }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_3_MOVING_UP }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_MOVING_LEFT }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_MOVING_RIGHT }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_DIGGING_DOWN }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_3_DIGGING_UP }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_DIGGING_LEFT }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_DIGGING_RIGHT }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_COLLECTING_DOWN }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_3_COLLECTING_UP }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_COLLECTING_LEFT }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_COLLECTING_RIGHT }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_PUSHING_DOWN }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_3_PUSHING_UP }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_PUSHING_LEFT }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_PUSHING_RIGHT }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_SNAPPING_DOWN }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_3_SNAPPING_UP }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_SNAPPING_LEFT }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_SNAPPING_RIGHT }, { EL_PLAYER_4, -1, -1, FALSE, IMG_PLAYER_4 }, { EL_PLAYER_4, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_DOWN }, { EL_PLAYER_4, -1, MV_BIT_UP, FALSE, IMG_PLAYER_4_UP }, { EL_PLAYER_4, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_LEFT }, { EL_PLAYER_4, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_RIGHT }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_MOVING_DOWN }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_4_MOVING_UP }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_MOVING_LEFT }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_MOVING_RIGHT }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_DIGGING_DOWN }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_4_DIGGING_UP }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_DIGGING_LEFT }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_DIGGING_RIGHT }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_COLLECTING_DOWN }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_4_COLLECTING_UP }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_COLLECTING_LEFT }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_COLLECTING_RIGHT }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_PUSHING_DOWN }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_4_PUSHING_UP }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_PUSHING_LEFT }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_PUSHING_RIGHT }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_SNAPPING_DOWN }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_4_SNAPPING_UP }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_SNAPPING_LEFT }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_SNAPPING_RIGHT }, { EL_DEFAULT, ACTION_EXPLODING, -1, FALSE, IMG_DEFAULT_EXPLODING }, { EL_STEELWALL_TOPLEFT, -1, -1, FALSE, IMG_STEELWALL_TOPLEFT }, { EL_STEELWALL_TOPRIGHT, -1, -1, FALSE, IMG_STEELWALL_TOPRIGHT }, { EL_STEELWALL_BOTTOMLEFT, -1, -1, FALSE, IMG_STEELWALL_BOTTOMLEFT }, { EL_STEELWALL_BOTTOMRIGHT, -1, -1, FALSE, IMG_STEELWALL_BOTTOMRIGHT }, { EL_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_STEELWALL_HORIZONTAL }, { EL_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_STEELWALL_VERTICAL }, { EL_INVISIBLE_STEELWALL_TOPLEFT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_TOPLEFT }, { EL_INVISIBLE_STEELWALL_TOPRIGHT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_TOPRIGHT }, { EL_INVISIBLE_STEELWALL_BOTTOMLEFT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT }, { EL_INVISIBLE_STEELWALL_BOTTOMRIGHT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT }, { EL_INVISIBLE_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_HORIZONTAL }, { EL_INVISIBLE_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_VERTICAL }, { EL_ARROW_LEFT, -1, -1, FALSE, IMG_ARROW_LEFT }, { EL_ARROW_RIGHT, -1, -1, FALSE, IMG_ARROW_RIGHT }, { EL_ARROW_UP, -1, -1, FALSE, IMG_ARROW_UP }, { EL_ARROW_DOWN, -1, -1, FALSE, IMG_ARROW_DOWN }, { EL_UNKNOWN, -1, -1, FALSE, IMG_UNKNOWN }, { EL_TRIGGER_ELEMENT, -1, -1, FALSE, IMG_TRIGGER_ELEMENT }, { EL_TRIGGER_PLAYER, -1, -1, FALSE, IMG_TRIGGER_PLAYER }, { EL_TRIGGER_CE_VALUE, -1, -1, FALSE, IMG_TRIGGER_CE_VALUE }, { EL_TRIGGER_CE_SCORE, -1, -1, FALSE, IMG_TRIGGER_CE_SCORE }, { EL_CURRENT_CE_VALUE, -1, -1, FALSE, IMG_CURRENT_CE_VALUE }, { EL_CURRENT_CE_SCORE, -1, -1, FALSE, IMG_CURRENT_CE_SCORE }, { EL_PREV_CE_1, -1, -1, FALSE, IMG_PREV_CE_1 }, { EL_PREV_CE_2, -1, -1, FALSE, IMG_PREV_CE_2 }, { EL_PREV_CE_3, -1, -1, FALSE, IMG_PREV_CE_3 }, { EL_PREV_CE_4, -1, -1, FALSE, IMG_PREV_CE_4 }, { EL_PREV_CE_5, -1, -1, FALSE, IMG_PREV_CE_5 }, { EL_PREV_CE_6, -1, -1, FALSE, IMG_PREV_CE_6 }, { EL_PREV_CE_7, -1, -1, FALSE, IMG_PREV_CE_7 }, { EL_PREV_CE_8, -1, -1, FALSE, IMG_PREV_CE_8 }, { EL_NEXT_CE_1, -1, -1, FALSE, IMG_NEXT_CE_1 }, { EL_NEXT_CE_2, -1, -1, FALSE, IMG_NEXT_CE_2 }, { EL_NEXT_CE_3, -1, -1, FALSE, IMG_NEXT_CE_3 }, { EL_NEXT_CE_4, -1, -1, FALSE, IMG_NEXT_CE_4 }, { EL_NEXT_CE_5, -1, -1, FALSE, IMG_NEXT_CE_5 }, { EL_NEXT_CE_6, -1, -1, FALSE, IMG_NEXT_CE_6 }, { EL_NEXT_CE_7, -1, -1, FALSE, IMG_NEXT_CE_7 }, { EL_NEXT_CE_8, -1, -1, FALSE, IMG_NEXT_CE_8 }, { EL_SELF, -1, -1, FALSE, IMG_SELF }, { EL_ANY_ELEMENT, -1, -1, FALSE, IMG_ANY_ELEMENT }, { EL_EMC_KEY_5, -1, -1, FALSE, IMG_EMC_KEY_5 }, { EL_EMC_KEY_6, -1, -1, FALSE, IMG_EMC_KEY_6 }, { EL_EMC_KEY_7, -1, -1, FALSE, IMG_EMC_KEY_7 }, { EL_EMC_KEY_8, -1, -1, FALSE, IMG_EMC_KEY_8 }, { EL_EMC_GATE_5, -1, -1, FALSE, IMG_EMC_GATE_5 }, { EL_EMC_GATE_6, -1, -1, FALSE, IMG_EMC_GATE_6 }, { EL_EMC_GATE_7, -1, -1, FALSE, IMG_EMC_GATE_7 }, { EL_EMC_GATE_8, -1, -1, FALSE, IMG_EMC_GATE_8 }, { EL_EMC_GATE_5_GRAY, -1, -1, FALSE, IMG_EMC_GATE_5_GRAY }, { EL_EMC_GATE_5_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_5_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, -1, -1, FALSE, IMG_EMC_GATE_6_GRAY }, { EL_EMC_GATE_6_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, -1, -1, FALSE, IMG_EMC_GATE_7_GRAY }, { EL_EMC_GATE_7_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, -1, -1, FALSE, IMG_EMC_GATE_8_GRAY }, { EL_EMC_GATE_8_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_ANDROID, -1, -1, FALSE, IMG_EMC_ANDROID }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT, FALSE, IMG_EMC_ANDROID_SHRINKING_UPLEFT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT, FALSE, IMG_EMC_ANDROID_GROWING_DOWNRIGHT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT, FALSE, IMG_EMC_ANDROID_SHRINKING_DOWNLEFT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT, FALSE, IMG_EMC_ANDROID_GROWING_UPRIGHT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT, FALSE, IMG_EMC_ANDROID_SHRINKING_UPRIGHT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT, FALSE, IMG_EMC_ANDROID_GROWING_DOWNLEFT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT, FALSE, IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT, FALSE, IMG_EMC_ANDROID_GROWING_UPLEFT }, { EL_EMC_GRASS, -1, -1, FALSE, IMG_EMC_GRASS }, { EL_EMC_GRASS, -1, -1, TRUE, IMG_EMC_GRASS_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_EMC_GRASS_DIGGING_LEFT }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_EMC_GRASS_DIGGING_RIGHT }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_EMC_GRASS_DIGGING_UP }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_EMC_GRASS_DIGGING_DOWN }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_EMC_GRASS_DIGGING_UP_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED }, { EL_EMC_MAGIC_BALL, -1, -1, FALSE, IMG_EMC_MAGIC_BALL }, { EL_EMC_MAGIC_BALL_ACTIVE, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1, FALSE, IMG_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1, FALSE, IMG_EMC_MAGIC_BALL_DROPPING }, { EL_EMC_MAGIC_BALL_SWITCH, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH }, { EL_EMC_MAGIC_BALL_SWITCH_ACTIVE, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_SPRING_BUMPER, -1, -1, FALSE, IMG_EMC_SPRING_BUMPER }, { EL_EMC_SPRING_BUMPER_ACTIVE, -1, -1, FALSE, IMG_EMC_SPRING_BUMPER_ACTIVE }, { EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1, FALSE, IMG_EMC_SPRING_BUMPER_ACTIVE }, { EL_EMC_PLANT, -1, -1, FALSE, IMG_EMC_PLANT }, { EL_EMC_PLANT, -1, -1, TRUE, IMG_EMC_PLANT_CRUMBLED }, { EL_EMC_LENSES, -1, -1, FALSE, IMG_EMC_LENSES }, { EL_EMC_MAGNIFIER, -1, -1, FALSE, IMG_EMC_MAGNIFIER }, { EL_EMC_WALL_9, -1, -1, FALSE, IMG_EMC_WALL_9 }, { EL_EMC_WALL_10, -1, -1, FALSE, IMG_EMC_WALL_10 }, { EL_EMC_WALL_11, -1, -1, FALSE, IMG_EMC_WALL_11 }, { EL_EMC_WALL_12, -1, -1, FALSE, IMG_EMC_WALL_12 }, { EL_EMC_WALL_13, -1, -1, FALSE, IMG_EMC_WALL_13 }, { EL_EMC_WALL_14, -1, -1, FALSE, IMG_EMC_WALL_14 }, { EL_EMC_WALL_15, -1, -1, FALSE, IMG_EMC_WALL_15 }, { EL_EMC_WALL_16, -1, -1, FALSE, IMG_EMC_WALL_16 }, { EL_EMC_WALL_SLIPPERY_1, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_1 }, { EL_EMC_WALL_SLIPPERY_2, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_2 }, { EL_EMC_WALL_SLIPPERY_3, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_3 }, { EL_EMC_WALL_SLIPPERY_4, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_4 }, { EL_EMC_FAKE_GRASS, -1, -1, FALSE, IMG_EMC_FAKE_GRASS }, { EL_EMC_FAKE_GRASS, -1, -1, TRUE, IMG_EMC_FAKE_GRASS_CRUMBLED }, { EL_EMC_FAKE_GRASS_ACTIVE, -1, -1, FALSE, IMG_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1, FALSE, IMG_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1, TRUE, IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED }, { EL_EMC_FAKE_GRASS_ACTIVE, -1, -1, TRUE, IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED }, { EL_EMC_FAKE_ACID, -1, -1, FALSE, IMG_EMC_FAKE_ACID }, { EL_EMC_DRIPPER, -1, -1, FALSE, IMG_EMC_DRIPPER }, { EL_EMC_DRIPPER_ACTIVE, -1, -1, FALSE, IMG_EMC_DRIPPER_ACTIVE }, { EL_EMC_DRIPPER, ACTION_ACTIVE, -1, FALSE, IMG_EMC_DRIPPER_ACTIVE }, { EL_GRAPHIC_1, -1, -1, FALSE, IMG_GRAPHIC_1 }, { EL_GRAPHIC_2, -1, -1, FALSE, IMG_GRAPHIC_2 }, { EL_GRAPHIC_3, -1, -1, FALSE, IMG_GRAPHIC_3 }, { EL_GRAPHIC_4, -1, -1, FALSE, IMG_GRAPHIC_4 }, { EL_GRAPHIC_5, -1, -1, FALSE, IMG_GRAPHIC_5 }, { EL_GRAPHIC_6, -1, -1, FALSE, IMG_GRAPHIC_6 }, { EL_GRAPHIC_7, -1, -1, FALSE, IMG_GRAPHIC_7 }, { EL_GRAPHIC_8, -1, -1, FALSE, IMG_GRAPHIC_8 }, { EL_BD_BUTTERFLY_DOWN, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_LEFT, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_RIGHT, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_UP, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_FIREFLY_DOWN, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_LEFT, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_RIGHT, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_UP, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_DX_UNKNOWN_15, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_DX_UNKNOWN_42, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_SIGN_UNUSED_1, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_SIGN_UNUSED_2, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_CHAR_SPACE, -1, -1, FALSE, IMG_CHAR_SPACE }, { EL_CHAR_EXCLAM, -1, -1, FALSE, IMG_CHAR_EXCLAM }, { EL_CHAR_QUOTEDBL, -1, -1, FALSE, IMG_CHAR_QUOTEDBL }, { EL_CHAR_NUMBERSIGN, -1, -1, FALSE, IMG_CHAR_NUMBERSIGN }, { EL_CHAR_DOLLAR, -1, -1, FALSE, IMG_CHAR_DOLLAR }, { EL_CHAR_PERCENT, -1, -1, FALSE, IMG_CHAR_PERCENT }, { EL_CHAR_AMPERSAND, -1, -1, FALSE, IMG_CHAR_AMPERSAND }, { EL_CHAR_APOSTROPHE, -1, -1, FALSE, IMG_CHAR_APOSTROPHE }, { EL_CHAR_PARENLEFT, -1, -1, FALSE, IMG_CHAR_PARENLEFT }, { EL_CHAR_PARENRIGHT, -1, -1, FALSE, IMG_CHAR_PARENRIGHT }, { EL_CHAR_ASTERISK, -1, -1, FALSE, IMG_CHAR_ASTERISK }, { EL_CHAR_PLUS, -1, -1, FALSE, IMG_CHAR_PLUS }, { EL_CHAR_COMMA, -1, -1, FALSE, IMG_CHAR_COMMA }, { EL_CHAR_MINUS, -1, -1, FALSE, IMG_CHAR_MINUS }, { EL_CHAR_PERIOD, -1, -1, FALSE, IMG_CHAR_PERIOD }, { EL_CHAR_SLASH, -1, -1, FALSE, IMG_CHAR_SLASH }, { EL_CHAR_0, -1, -1, FALSE, IMG_CHAR_0 }, { EL_CHAR_1, -1, -1, FALSE, IMG_CHAR_1 }, { EL_CHAR_2, -1, -1, FALSE, IMG_CHAR_2 }, { EL_CHAR_3, -1, -1, FALSE, IMG_CHAR_3 }, { EL_CHAR_4, -1, -1, FALSE, IMG_CHAR_4 }, { EL_CHAR_5, -1, -1, FALSE, IMG_CHAR_5 }, { EL_CHAR_6, -1, -1, FALSE, IMG_CHAR_6 }, { EL_CHAR_7, -1, -1, FALSE, IMG_CHAR_7 }, { EL_CHAR_8, -1, -1, FALSE, IMG_CHAR_8 }, { EL_CHAR_9, -1, -1, FALSE, IMG_CHAR_9 }, { EL_CHAR_COLON, -1, -1, FALSE, IMG_CHAR_COLON }, { EL_CHAR_SEMICOLON, -1, -1, FALSE, IMG_CHAR_SEMICOLON }, { EL_CHAR_LESS, -1, -1, FALSE, IMG_CHAR_LESS }, { EL_CHAR_EQUAL, -1, -1, FALSE, IMG_CHAR_EQUAL }, { EL_CHAR_GREATER, -1, -1, FALSE, IMG_CHAR_GREATER }, { EL_CHAR_QUESTION, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_CHAR_AT, -1, -1, FALSE, IMG_CHAR_AT }, { EL_CHAR_A, -1, -1, FALSE, IMG_CHAR_A }, { EL_CHAR_B, -1, -1, FALSE, IMG_CHAR_B }, { EL_CHAR_C, -1, -1, FALSE, IMG_CHAR_C }, { EL_CHAR_D, -1, -1, FALSE, IMG_CHAR_D }, { EL_CHAR_E, -1, -1, FALSE, IMG_CHAR_E }, { EL_CHAR_F, -1, -1, FALSE, IMG_CHAR_F }, { EL_CHAR_G, -1, -1, FALSE, IMG_CHAR_G }, { EL_CHAR_H, -1, -1, FALSE, IMG_CHAR_H }, { EL_CHAR_I, -1, -1, FALSE, IMG_CHAR_I }, { EL_CHAR_J, -1, -1, FALSE, IMG_CHAR_J }, { EL_CHAR_K, -1, -1, FALSE, IMG_CHAR_K }, { EL_CHAR_L, -1, -1, FALSE, IMG_CHAR_L }, { EL_CHAR_M, -1, -1, FALSE, IMG_CHAR_M }, { EL_CHAR_N, -1, -1, FALSE, IMG_CHAR_N }, { EL_CHAR_O, -1, -1, FALSE, IMG_CHAR_O }, { EL_CHAR_P, -1, -1, FALSE, IMG_CHAR_P }, { EL_CHAR_Q, -1, -1, FALSE, IMG_CHAR_Q }, { EL_CHAR_R, -1, -1, FALSE, IMG_CHAR_R }, { EL_CHAR_S, -1, -1, FALSE, IMG_CHAR_S }, { EL_CHAR_T, -1, -1, FALSE, IMG_CHAR_T }, { EL_CHAR_U, -1, -1, FALSE, IMG_CHAR_U }, { EL_CHAR_V, -1, -1, FALSE, IMG_CHAR_V }, { EL_CHAR_W, -1, -1, FALSE, IMG_CHAR_W }, { EL_CHAR_X, -1, -1, FALSE, IMG_CHAR_X }, { EL_CHAR_Y, -1, -1, FALSE, IMG_CHAR_Y }, { EL_CHAR_Z, -1, -1, FALSE, IMG_CHAR_Z }, { EL_CHAR_BRACKETLEFT, -1, -1, FALSE, IMG_CHAR_BRACKETLEFT }, { EL_CHAR_BACKSLASH, -1, -1, FALSE, IMG_CHAR_BACKSLASH }, { EL_CHAR_BRACKETRIGHT, -1, -1, FALSE, IMG_CHAR_BRACKETRIGHT }, { EL_CHAR_ASCIICIRCUM, -1, -1, FALSE, IMG_CHAR_ASCIICIRCUM }, { EL_CHAR_UNDERSCORE, -1, -1, FALSE, IMG_CHAR_UNDERSCORE }, { EL_CHAR_COPYRIGHT, -1, -1, FALSE, IMG_CHAR_COPYRIGHT }, { EL_CHAR_AUMLAUT, -1, -1, FALSE, IMG_CHAR_AUMLAUT }, { EL_CHAR_OUMLAUT, -1, -1, FALSE, IMG_CHAR_OUMLAUT }, { EL_CHAR_UUMLAUT, -1, -1, FALSE, IMG_CHAR_UUMLAUT }, { EL_CHAR_DEGREE, -1, -1, FALSE, IMG_CHAR_DEGREE }, { EL_CHAR_TRADEMARK, -1, -1, FALSE, IMG_CHAR_TRADEMARK }, { EL_CHAR_CURSOR, -1, -1, FALSE, IMG_CHAR_CURSOR }, { EL_CHAR_BUTTON, -1, -1, FALSE, IMG_CHAR_BUTTON }, { EL_CHAR_UP, -1, -1, FALSE, IMG_CHAR_UP }, { EL_CHAR_DOWN, -1, -1, FALSE, IMG_CHAR_DOWN }, { EL_STEEL_CHAR_SPACE, -1, -1, FALSE, IMG_STEEL_CHAR_SPACE }, { EL_STEEL_CHAR_EXCLAM, -1, -1, FALSE, IMG_STEEL_CHAR_EXCLAM }, { EL_STEEL_CHAR_QUOTEDBL, -1, -1, FALSE, IMG_STEEL_CHAR_QUOTEDBL }, { EL_STEEL_CHAR_NUMBERSIGN, -1, -1, FALSE, IMG_STEEL_CHAR_NUMBERSIGN }, { EL_STEEL_CHAR_DOLLAR, -1, -1, FALSE, IMG_STEEL_CHAR_DOLLAR }, { EL_STEEL_CHAR_PERCENT, -1, -1, FALSE, IMG_STEEL_CHAR_PERCENT }, { EL_STEEL_CHAR_AMPERSAND, -1, -1, FALSE, IMG_STEEL_CHAR_AMPERSAND }, { EL_STEEL_CHAR_APOSTROPHE, -1, -1, FALSE, IMG_STEEL_CHAR_APOSTROPHE }, { EL_STEEL_CHAR_PARENLEFT, -1, -1, FALSE, IMG_STEEL_CHAR_PARENLEFT }, { EL_STEEL_CHAR_PARENRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_PARENRIGHT }, { EL_STEEL_CHAR_ASTERISK, -1, -1, FALSE, IMG_STEEL_CHAR_ASTERISK }, { EL_STEEL_CHAR_PLUS, -1, -1, FALSE, IMG_STEEL_CHAR_PLUS }, { EL_STEEL_CHAR_COMMA, -1, -1, FALSE, IMG_STEEL_CHAR_COMMA }, { EL_STEEL_CHAR_MINUS, -1, -1, FALSE, IMG_STEEL_CHAR_MINUS }, { EL_STEEL_CHAR_PERIOD, -1, -1, FALSE, IMG_STEEL_CHAR_PERIOD }, { EL_STEEL_CHAR_SLASH, -1, -1, FALSE, IMG_STEEL_CHAR_SLASH }, { EL_STEEL_CHAR_0, -1, -1, FALSE, IMG_STEEL_CHAR_0 }, { EL_STEEL_CHAR_1, -1, -1, FALSE, IMG_STEEL_CHAR_1 }, { EL_STEEL_CHAR_2, -1, -1, FALSE, IMG_STEEL_CHAR_2 }, { EL_STEEL_CHAR_3, -1, -1, FALSE, IMG_STEEL_CHAR_3 }, { EL_STEEL_CHAR_4, -1, -1, FALSE, IMG_STEEL_CHAR_4 }, { EL_STEEL_CHAR_5, -1, -1, FALSE, IMG_STEEL_CHAR_5 }, { EL_STEEL_CHAR_6, -1, -1, FALSE, IMG_STEEL_CHAR_6 }, { EL_STEEL_CHAR_7, -1, -1, FALSE, IMG_STEEL_CHAR_7 }, { EL_STEEL_CHAR_8, -1, -1, FALSE, IMG_STEEL_CHAR_8 }, { EL_STEEL_CHAR_9, -1, -1, FALSE, IMG_STEEL_CHAR_9 }, { EL_STEEL_CHAR_COLON, -1, -1, FALSE, IMG_STEEL_CHAR_COLON }, { EL_STEEL_CHAR_SEMICOLON, -1, -1, FALSE, IMG_STEEL_CHAR_SEMICOLON }, { EL_STEEL_CHAR_LESS, -1, -1, FALSE, IMG_STEEL_CHAR_LESS }, { EL_STEEL_CHAR_EQUAL, -1, -1, FALSE, IMG_STEEL_CHAR_EQUAL }, { EL_STEEL_CHAR_GREATER, -1, -1, FALSE, IMG_STEEL_CHAR_GREATER }, { EL_STEEL_CHAR_QUESTION, -1, -1, FALSE, IMG_STEEL_CHAR_QUESTION }, { EL_STEEL_CHAR_AT, -1, -1, FALSE, IMG_STEEL_CHAR_AT }, { EL_STEEL_CHAR_A, -1, -1, FALSE, IMG_STEEL_CHAR_A }, { EL_STEEL_CHAR_B, -1, -1, FALSE, IMG_STEEL_CHAR_B }, { EL_STEEL_CHAR_C, -1, -1, FALSE, IMG_STEEL_CHAR_C }, { EL_STEEL_CHAR_D, -1, -1, FALSE, IMG_STEEL_CHAR_D }, { EL_STEEL_CHAR_E, -1, -1, FALSE, IMG_STEEL_CHAR_E }, { EL_STEEL_CHAR_F, -1, -1, FALSE, IMG_STEEL_CHAR_F }, { EL_STEEL_CHAR_G, -1, -1, FALSE, IMG_STEEL_CHAR_G }, { EL_STEEL_CHAR_H, -1, -1, FALSE, IMG_STEEL_CHAR_H }, { EL_STEEL_CHAR_I, -1, -1, FALSE, IMG_STEEL_CHAR_I }, { EL_STEEL_CHAR_J, -1, -1, FALSE, IMG_STEEL_CHAR_J }, { EL_STEEL_CHAR_K, -1, -1, FALSE, IMG_STEEL_CHAR_K }, { EL_STEEL_CHAR_L, -1, -1, FALSE, IMG_STEEL_CHAR_L }, { EL_STEEL_CHAR_M, -1, -1, FALSE, IMG_STEEL_CHAR_M }, { EL_STEEL_CHAR_N, -1, -1, FALSE, IMG_STEEL_CHAR_N }, { EL_STEEL_CHAR_O, -1, -1, FALSE, IMG_STEEL_CHAR_O }, { EL_STEEL_CHAR_P, -1, -1, FALSE, IMG_STEEL_CHAR_P }, { EL_STEEL_CHAR_Q, -1, -1, FALSE, IMG_STEEL_CHAR_Q }, { EL_STEEL_CHAR_R, -1, -1, FALSE, IMG_STEEL_CHAR_R }, { EL_STEEL_CHAR_S, -1, -1, FALSE, IMG_STEEL_CHAR_S }, { EL_STEEL_CHAR_T, -1, -1, FALSE, IMG_STEEL_CHAR_T }, { EL_STEEL_CHAR_U, -1, -1, FALSE, IMG_STEEL_CHAR_U }, { EL_STEEL_CHAR_V, -1, -1, FALSE, IMG_STEEL_CHAR_V }, { EL_STEEL_CHAR_W, -1, -1, FALSE, IMG_STEEL_CHAR_W }, { EL_STEEL_CHAR_X, -1, -1, FALSE, IMG_STEEL_CHAR_X }, { EL_STEEL_CHAR_Y, -1, -1, FALSE, IMG_STEEL_CHAR_Y }, { EL_STEEL_CHAR_Z, -1, -1, FALSE, IMG_STEEL_CHAR_Z }, { EL_STEEL_CHAR_BRACKETLEFT, -1, -1, FALSE, IMG_STEEL_CHAR_BRACKETLEFT }, { EL_STEEL_CHAR_BACKSLASH, -1, -1, FALSE, IMG_STEEL_CHAR_BACKSLASH }, { EL_STEEL_CHAR_BRACKETRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_BRACKETRIGHT }, { EL_STEEL_CHAR_ASCIICIRCUM, -1, -1, FALSE, IMG_STEEL_CHAR_ASCIICIRCUM }, { EL_STEEL_CHAR_UNDERSCORE, -1, -1, FALSE, IMG_STEEL_CHAR_UNDERSCORE }, { EL_STEEL_CHAR_COPYRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_COPYRIGHT }, { EL_STEEL_CHAR_AUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_AUMLAUT }, { EL_STEEL_CHAR_OUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_OUMLAUT }, { EL_STEEL_CHAR_UUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_UUMLAUT }, { EL_STEEL_CHAR_DEGREE, -1, -1, FALSE, IMG_STEEL_CHAR_DEGREE }, { EL_STEEL_CHAR_TRADEMARK, -1, -1, FALSE, IMG_STEEL_CHAR_TRADEMARK }, { EL_STEEL_CHAR_CURSOR, -1, -1, FALSE, IMG_STEEL_CHAR_CURSOR }, { EL_STEEL_CHAR_BUTTON, -1, -1, FALSE, IMG_STEEL_CHAR_BUTTON }, { EL_STEEL_CHAR_UP, -1, -1, FALSE, IMG_STEEL_CHAR_UP }, { EL_STEEL_CHAR_DOWN, -1, -1, FALSE, IMG_STEEL_CHAR_DOWN }, { EL_CUSTOM_1, -1, -1, FALSE, IMG_CUSTOM_1 }, { EL_CUSTOM_2, -1, -1, FALSE, IMG_CUSTOM_2 }, { EL_CUSTOM_3, -1, -1, FALSE, IMG_CUSTOM_3 }, { EL_CUSTOM_4, -1, -1, FALSE, IMG_CUSTOM_4 }, { EL_CUSTOM_5, -1, -1, FALSE, IMG_CUSTOM_5 }, { EL_CUSTOM_6, -1, -1, FALSE, IMG_CUSTOM_6 }, { EL_CUSTOM_7, -1, -1, FALSE, IMG_CUSTOM_7 }, { EL_CUSTOM_8, -1, -1, FALSE, IMG_CUSTOM_8 }, { EL_CUSTOM_9, -1, -1, FALSE, IMG_CUSTOM_9 }, { EL_CUSTOM_10, -1, -1, FALSE, IMG_CUSTOM_10 }, { EL_CUSTOM_11, -1, -1, FALSE, IMG_CUSTOM_11 }, { EL_CUSTOM_12, -1, -1, FALSE, IMG_CUSTOM_12 }, { EL_CUSTOM_13, -1, -1, FALSE, IMG_CUSTOM_13 }, { EL_CUSTOM_14, -1, -1, FALSE, IMG_CUSTOM_14 }, { EL_CUSTOM_15, -1, -1, FALSE, IMG_CUSTOM_15 }, { EL_CUSTOM_16, -1, -1, FALSE, IMG_CUSTOM_16 }, { EL_CUSTOM_17, -1, -1, FALSE, IMG_CUSTOM_17 }, { EL_CUSTOM_18, -1, -1, FALSE, IMG_CUSTOM_18 }, { EL_CUSTOM_19, -1, -1, FALSE, IMG_CUSTOM_19 }, { EL_CUSTOM_20, -1, -1, FALSE, IMG_CUSTOM_20 }, { EL_CUSTOM_21, -1, -1, FALSE, IMG_CUSTOM_21 }, { EL_CUSTOM_22, -1, -1, FALSE, IMG_CUSTOM_22 }, { EL_CUSTOM_23, -1, -1, FALSE, IMG_CUSTOM_23 }, { EL_CUSTOM_24, -1, -1, FALSE, IMG_CUSTOM_24 }, { EL_CUSTOM_25, -1, -1, FALSE, IMG_CUSTOM_25 }, { EL_CUSTOM_26, -1, -1, FALSE, IMG_CUSTOM_26 }, { EL_CUSTOM_27, -1, -1, FALSE, IMG_CUSTOM_27 }, { EL_CUSTOM_28, -1, -1, FALSE, IMG_CUSTOM_28 }, { EL_CUSTOM_29, -1, -1, FALSE, IMG_CUSTOM_29 }, { EL_CUSTOM_30, -1, -1, FALSE, IMG_CUSTOM_30 }, { EL_CUSTOM_31, -1, -1, FALSE, IMG_CUSTOM_31 }, { EL_CUSTOM_32, -1, -1, FALSE, IMG_CUSTOM_32 }, { EL_CUSTOM_33, -1, -1, FALSE, IMG_CUSTOM_33 }, { EL_CUSTOM_34, -1, -1, FALSE, IMG_CUSTOM_34 }, { EL_CUSTOM_35, -1, -1, FALSE, IMG_CUSTOM_35 }, { EL_CUSTOM_36, -1, -1, FALSE, IMG_CUSTOM_36 }, { EL_CUSTOM_37, -1, -1, FALSE, IMG_CUSTOM_37 }, { EL_CUSTOM_38, -1, -1, FALSE, IMG_CUSTOM_38 }, { EL_CUSTOM_39, -1, -1, FALSE, IMG_CUSTOM_39 }, { EL_CUSTOM_40, -1, -1, FALSE, IMG_CUSTOM_40 }, { EL_CUSTOM_41, -1, -1, FALSE, IMG_CUSTOM_41 }, { EL_CUSTOM_42, -1, -1, FALSE, IMG_CUSTOM_42 }, { EL_CUSTOM_43, -1, -1, FALSE, IMG_CUSTOM_43 }, { EL_CUSTOM_44, -1, -1, FALSE, IMG_CUSTOM_44 }, { EL_CUSTOM_45, -1, -1, FALSE, IMG_CUSTOM_45 }, { EL_CUSTOM_46, -1, -1, FALSE, IMG_CUSTOM_46 }, { EL_CUSTOM_47, -1, -1, FALSE, IMG_CUSTOM_47 }, { EL_CUSTOM_48, -1, -1, FALSE, IMG_CUSTOM_48 }, { EL_CUSTOM_49, -1, -1, FALSE, IMG_CUSTOM_49 }, { EL_CUSTOM_50, -1, -1, FALSE, IMG_CUSTOM_50 }, { EL_CUSTOM_51, -1, -1, FALSE, IMG_CUSTOM_51 }, { EL_CUSTOM_52, -1, -1, FALSE, IMG_CUSTOM_52 }, { EL_CUSTOM_53, -1, -1, FALSE, IMG_CUSTOM_53 }, { EL_CUSTOM_54, -1, -1, FALSE, IMG_CUSTOM_54 }, { EL_CUSTOM_55, -1, -1, FALSE, IMG_CUSTOM_55 }, { EL_CUSTOM_56, -1, -1, FALSE, IMG_CUSTOM_56 }, { EL_CUSTOM_57, -1, -1, FALSE, IMG_CUSTOM_57 }, { EL_CUSTOM_58, -1, -1, FALSE, IMG_CUSTOM_58 }, { EL_CUSTOM_59, -1, -1, FALSE, IMG_CUSTOM_59 }, { EL_CUSTOM_60, -1, -1, FALSE, IMG_CUSTOM_60 }, { EL_CUSTOM_61, -1, -1, FALSE, IMG_CUSTOM_61 }, { EL_CUSTOM_62, -1, -1, FALSE, IMG_CUSTOM_62 }, { EL_CUSTOM_63, -1, -1, FALSE, IMG_CUSTOM_63 }, { EL_CUSTOM_64, -1, -1, FALSE, IMG_CUSTOM_64 }, { EL_CUSTOM_65, -1, -1, FALSE, IMG_CUSTOM_65 }, { EL_CUSTOM_66, -1, -1, FALSE, IMG_CUSTOM_66 }, { EL_CUSTOM_67, -1, -1, FALSE, IMG_CUSTOM_67 }, { EL_CUSTOM_68, -1, -1, FALSE, IMG_CUSTOM_68 }, { EL_CUSTOM_69, -1, -1, FALSE, IMG_CUSTOM_69 }, { EL_CUSTOM_70, -1, -1, FALSE, IMG_CUSTOM_70 }, { EL_CUSTOM_71, -1, -1, FALSE, IMG_CUSTOM_71 }, { EL_CUSTOM_72, -1, -1, FALSE, IMG_CUSTOM_72 }, { EL_CUSTOM_73, -1, -1, FALSE, IMG_CUSTOM_73 }, { EL_CUSTOM_74, -1, -1, FALSE, IMG_CUSTOM_74 }, { EL_CUSTOM_75, -1, -1, FALSE, IMG_CUSTOM_75 }, { EL_CUSTOM_76, -1, -1, FALSE, IMG_CUSTOM_76 }, { EL_CUSTOM_77, -1, -1, FALSE, IMG_CUSTOM_77 }, { EL_CUSTOM_78, -1, -1, FALSE, IMG_CUSTOM_78 }, { EL_CUSTOM_79, -1, -1, FALSE, IMG_CUSTOM_79 }, { EL_CUSTOM_80, -1, -1, FALSE, IMG_CUSTOM_80 }, { EL_CUSTOM_81, -1, -1, FALSE, IMG_CUSTOM_81 }, { EL_CUSTOM_82, -1, -1, FALSE, IMG_CUSTOM_82 }, { EL_CUSTOM_83, -1, -1, FALSE, IMG_CUSTOM_83 }, { EL_CUSTOM_84, -1, -1, FALSE, IMG_CUSTOM_84 }, { EL_CUSTOM_85, -1, -1, FALSE, IMG_CUSTOM_85 }, { EL_CUSTOM_86, -1, -1, FALSE, IMG_CUSTOM_86 }, { EL_CUSTOM_87, -1, -1, FALSE, IMG_CUSTOM_87 }, { EL_CUSTOM_88, -1, -1, FALSE, IMG_CUSTOM_88 }, { EL_CUSTOM_89, -1, -1, FALSE, IMG_CUSTOM_89 }, { EL_CUSTOM_90, -1, -1, FALSE, IMG_CUSTOM_90 }, { EL_CUSTOM_91, -1, -1, FALSE, IMG_CUSTOM_91 }, { EL_CUSTOM_92, -1, -1, FALSE, IMG_CUSTOM_92 }, { EL_CUSTOM_93, -1, -1, FALSE, IMG_CUSTOM_93 }, { EL_CUSTOM_94, -1, -1, FALSE, IMG_CUSTOM_94 }, { EL_CUSTOM_95, -1, -1, FALSE, IMG_CUSTOM_95 }, { EL_CUSTOM_96, -1, -1, FALSE, IMG_CUSTOM_96 }, { EL_CUSTOM_97, -1, -1, FALSE, IMG_CUSTOM_97 }, { EL_CUSTOM_98, -1, -1, FALSE, IMG_CUSTOM_98 }, { EL_CUSTOM_99, -1, -1, FALSE, IMG_CUSTOM_99 }, { EL_CUSTOM_100, -1, -1, FALSE, IMG_CUSTOM_100 }, { EL_CUSTOM_101, -1, -1, FALSE, IMG_CUSTOM_101 }, { EL_CUSTOM_102, -1, -1, FALSE, IMG_CUSTOM_102 }, { EL_CUSTOM_103, -1, -1, FALSE, IMG_CUSTOM_103 }, { EL_CUSTOM_104, -1, -1, FALSE, IMG_CUSTOM_104 }, { EL_CUSTOM_105, -1, -1, FALSE, IMG_CUSTOM_105 }, { EL_CUSTOM_106, -1, -1, FALSE, IMG_CUSTOM_106 }, { EL_CUSTOM_107, -1, -1, FALSE, IMG_CUSTOM_107 }, { EL_CUSTOM_108, -1, -1, FALSE, IMG_CUSTOM_108 }, { EL_CUSTOM_109, -1, -1, FALSE, IMG_CUSTOM_109 }, { EL_CUSTOM_110, -1, -1, FALSE, IMG_CUSTOM_110 }, { EL_CUSTOM_111, -1, -1, FALSE, IMG_CUSTOM_111 }, { EL_CUSTOM_112, -1, -1, FALSE, IMG_CUSTOM_112 }, { EL_CUSTOM_113, -1, -1, FALSE, IMG_CUSTOM_113 }, { EL_CUSTOM_114, -1, -1, FALSE, IMG_CUSTOM_114 }, { EL_CUSTOM_115, -1, -1, FALSE, IMG_CUSTOM_115 }, { EL_CUSTOM_116, -1, -1, FALSE, IMG_CUSTOM_116 }, { EL_CUSTOM_117, -1, -1, FALSE, IMG_CUSTOM_117 }, { EL_CUSTOM_118, -1, -1, FALSE, IMG_CUSTOM_118 }, { EL_CUSTOM_119, -1, -1, FALSE, IMG_CUSTOM_119 }, { EL_CUSTOM_120, -1, -1, FALSE, IMG_CUSTOM_120 }, { EL_CUSTOM_121, -1, -1, FALSE, IMG_CUSTOM_121 }, { EL_CUSTOM_122, -1, -1, FALSE, IMG_CUSTOM_122 }, { EL_CUSTOM_123, -1, -1, FALSE, IMG_CUSTOM_123 }, { EL_CUSTOM_124, -1, -1, FALSE, IMG_CUSTOM_124 }, { EL_CUSTOM_125, -1, -1, FALSE, IMG_CUSTOM_125 }, { EL_CUSTOM_126, -1, -1, FALSE, IMG_CUSTOM_126 }, { EL_CUSTOM_127, -1, -1, FALSE, IMG_CUSTOM_127 }, { EL_CUSTOM_128, -1, -1, FALSE, IMG_CUSTOM_128 }, { EL_CUSTOM_129, -1, -1, FALSE, IMG_CUSTOM_129 }, { EL_CUSTOM_130, -1, -1, FALSE, IMG_CUSTOM_130 }, { EL_CUSTOM_131, -1, -1, FALSE, IMG_CUSTOM_131 }, { EL_CUSTOM_132, -1, -1, FALSE, IMG_CUSTOM_132 }, { EL_CUSTOM_133, -1, -1, FALSE, IMG_CUSTOM_133 }, { EL_CUSTOM_134, -1, -1, FALSE, IMG_CUSTOM_134 }, { EL_CUSTOM_135, -1, -1, FALSE, IMG_CUSTOM_135 }, { EL_CUSTOM_136, -1, -1, FALSE, IMG_CUSTOM_136 }, { EL_CUSTOM_137, -1, -1, FALSE, IMG_CUSTOM_137 }, { EL_CUSTOM_138, -1, -1, FALSE, IMG_CUSTOM_138 }, { EL_CUSTOM_139, -1, -1, FALSE, IMG_CUSTOM_139 }, { EL_CUSTOM_140, -1, -1, FALSE, IMG_CUSTOM_140 }, { EL_CUSTOM_141, -1, -1, FALSE, IMG_CUSTOM_141 }, { EL_CUSTOM_142, -1, -1, FALSE, IMG_CUSTOM_142 }, { EL_CUSTOM_143, -1, -1, FALSE, IMG_CUSTOM_143 }, { EL_CUSTOM_144, -1, -1, FALSE, IMG_CUSTOM_144 }, { EL_CUSTOM_145, -1, -1, FALSE, IMG_CUSTOM_145 }, { EL_CUSTOM_146, -1, -1, FALSE, IMG_CUSTOM_146 }, { EL_CUSTOM_147, -1, -1, FALSE, IMG_CUSTOM_147 }, { EL_CUSTOM_148, -1, -1, FALSE, IMG_CUSTOM_148 }, { EL_CUSTOM_149, -1, -1, FALSE, IMG_CUSTOM_149 }, { EL_CUSTOM_150, -1, -1, FALSE, IMG_CUSTOM_150 }, { EL_CUSTOM_151, -1, -1, FALSE, IMG_CUSTOM_151 }, { EL_CUSTOM_152, -1, -1, FALSE, IMG_CUSTOM_152 }, { EL_CUSTOM_153, -1, -1, FALSE, IMG_CUSTOM_153 }, { EL_CUSTOM_154, -1, -1, FALSE, IMG_CUSTOM_154 }, { EL_CUSTOM_155, -1, -1, FALSE, IMG_CUSTOM_155 }, { EL_CUSTOM_156, -1, -1, FALSE, IMG_CUSTOM_156 }, { EL_CUSTOM_157, -1, -1, FALSE, IMG_CUSTOM_157 }, { EL_CUSTOM_158, -1, -1, FALSE, IMG_CUSTOM_158 }, { EL_CUSTOM_159, -1, -1, FALSE, IMG_CUSTOM_159 }, { EL_CUSTOM_160, -1, -1, FALSE, IMG_CUSTOM_160 }, { EL_CUSTOM_161, -1, -1, FALSE, IMG_CUSTOM_161 }, { EL_CUSTOM_162, -1, -1, FALSE, IMG_CUSTOM_162 }, { EL_CUSTOM_163, -1, -1, FALSE, IMG_CUSTOM_163 }, { EL_CUSTOM_164, -1, -1, FALSE, IMG_CUSTOM_164 }, { EL_CUSTOM_165, -1, -1, FALSE, IMG_CUSTOM_165 }, { EL_CUSTOM_166, -1, -1, FALSE, IMG_CUSTOM_166 }, { EL_CUSTOM_167, -1, -1, FALSE, IMG_CUSTOM_167 }, { EL_CUSTOM_168, -1, -1, FALSE, IMG_CUSTOM_168 }, { EL_CUSTOM_169, -1, -1, FALSE, IMG_CUSTOM_169 }, { EL_CUSTOM_170, -1, -1, FALSE, IMG_CUSTOM_170 }, { EL_CUSTOM_171, -1, -1, FALSE, IMG_CUSTOM_171 }, { EL_CUSTOM_172, -1, -1, FALSE, IMG_CUSTOM_172 }, { EL_CUSTOM_173, -1, -1, FALSE, IMG_CUSTOM_173 }, { EL_CUSTOM_174, -1, -1, FALSE, IMG_CUSTOM_174 }, { EL_CUSTOM_175, -1, -1, FALSE, IMG_CUSTOM_175 }, { EL_CUSTOM_176, -1, -1, FALSE, IMG_CUSTOM_176 }, { EL_CUSTOM_177, -1, -1, FALSE, IMG_CUSTOM_177 }, { EL_CUSTOM_178, -1, -1, FALSE, IMG_CUSTOM_178 }, { EL_CUSTOM_179, -1, -1, FALSE, IMG_CUSTOM_179 }, { EL_CUSTOM_180, -1, -1, FALSE, IMG_CUSTOM_180 }, { EL_CUSTOM_181, -1, -1, FALSE, IMG_CUSTOM_181 }, { EL_CUSTOM_182, -1, -1, FALSE, IMG_CUSTOM_182 }, { EL_CUSTOM_183, -1, -1, FALSE, IMG_CUSTOM_183 }, { EL_CUSTOM_184, -1, -1, FALSE, IMG_CUSTOM_184 }, { EL_CUSTOM_185, -1, -1, FALSE, IMG_CUSTOM_185 }, { EL_CUSTOM_186, -1, -1, FALSE, IMG_CUSTOM_186 }, { EL_CUSTOM_187, -1, -1, FALSE, IMG_CUSTOM_187 }, { EL_CUSTOM_188, -1, -1, FALSE, IMG_CUSTOM_188 }, { EL_CUSTOM_189, -1, -1, FALSE, IMG_CUSTOM_189 }, { EL_CUSTOM_190, -1, -1, FALSE, IMG_CUSTOM_190 }, { EL_CUSTOM_191, -1, -1, FALSE, IMG_CUSTOM_191 }, { EL_CUSTOM_192, -1, -1, FALSE, IMG_CUSTOM_192 }, { EL_CUSTOM_193, -1, -1, FALSE, IMG_CUSTOM_193 }, { EL_CUSTOM_194, -1, -1, FALSE, IMG_CUSTOM_194 }, { EL_CUSTOM_195, -1, -1, FALSE, IMG_CUSTOM_195 }, { EL_CUSTOM_196, -1, -1, FALSE, IMG_CUSTOM_196 }, { EL_CUSTOM_197, -1, -1, FALSE, IMG_CUSTOM_197 }, { EL_CUSTOM_198, -1, -1, FALSE, IMG_CUSTOM_198 }, { EL_CUSTOM_199, -1, -1, FALSE, IMG_CUSTOM_199 }, { EL_CUSTOM_200, -1, -1, FALSE, IMG_CUSTOM_200 }, { EL_CUSTOM_201, -1, -1, FALSE, IMG_CUSTOM_201 }, { EL_CUSTOM_202, -1, -1, FALSE, IMG_CUSTOM_202 }, { EL_CUSTOM_203, -1, -1, FALSE, IMG_CUSTOM_203 }, { EL_CUSTOM_204, -1, -1, FALSE, IMG_CUSTOM_204 }, { EL_CUSTOM_205, -1, -1, FALSE, IMG_CUSTOM_205 }, { EL_CUSTOM_206, -1, -1, FALSE, IMG_CUSTOM_206 }, { EL_CUSTOM_207, -1, -1, FALSE, IMG_CUSTOM_207 }, { EL_CUSTOM_208, -1, -1, FALSE, IMG_CUSTOM_208 }, { EL_CUSTOM_209, -1, -1, FALSE, IMG_CUSTOM_209 }, { EL_CUSTOM_210, -1, -1, FALSE, IMG_CUSTOM_210 }, { EL_CUSTOM_211, -1, -1, FALSE, IMG_CUSTOM_211 }, { EL_CUSTOM_212, -1, -1, FALSE, IMG_CUSTOM_212 }, { EL_CUSTOM_213, -1, -1, FALSE, IMG_CUSTOM_213 }, { EL_CUSTOM_214, -1, -1, FALSE, IMG_CUSTOM_214 }, { EL_CUSTOM_215, -1, -1, FALSE, IMG_CUSTOM_215 }, { EL_CUSTOM_216, -1, -1, FALSE, IMG_CUSTOM_216 }, { EL_CUSTOM_217, -1, -1, FALSE, IMG_CUSTOM_217 }, { EL_CUSTOM_218, -1, -1, FALSE, IMG_CUSTOM_218 }, { EL_CUSTOM_219, -1, -1, FALSE, IMG_CUSTOM_219 }, { EL_CUSTOM_220, -1, -1, FALSE, IMG_CUSTOM_220 }, { EL_CUSTOM_221, -1, -1, FALSE, IMG_CUSTOM_221 }, { EL_CUSTOM_222, -1, -1, FALSE, IMG_CUSTOM_222 }, { EL_CUSTOM_223, -1, -1, FALSE, IMG_CUSTOM_223 }, { EL_CUSTOM_224, -1, -1, FALSE, IMG_CUSTOM_224 }, { EL_CUSTOM_225, -1, -1, FALSE, IMG_CUSTOM_225 }, { EL_CUSTOM_226, -1, -1, FALSE, IMG_CUSTOM_226 }, { EL_CUSTOM_227, -1, -1, FALSE, IMG_CUSTOM_227 }, { EL_CUSTOM_228, -1, -1, FALSE, IMG_CUSTOM_228 }, { EL_CUSTOM_229, -1, -1, FALSE, IMG_CUSTOM_229 }, { EL_CUSTOM_230, -1, -1, FALSE, IMG_CUSTOM_230 }, { EL_CUSTOM_231, -1, -1, FALSE, IMG_CUSTOM_231 }, { EL_CUSTOM_232, -1, -1, FALSE, IMG_CUSTOM_232 }, { EL_CUSTOM_233, -1, -1, FALSE, IMG_CUSTOM_233 }, { EL_CUSTOM_234, -1, -1, FALSE, IMG_CUSTOM_234 }, { EL_CUSTOM_235, -1, -1, FALSE, IMG_CUSTOM_235 }, { EL_CUSTOM_236, -1, -1, FALSE, IMG_CUSTOM_236 }, { EL_CUSTOM_237, -1, -1, FALSE, IMG_CUSTOM_237 }, { EL_CUSTOM_238, -1, -1, FALSE, IMG_CUSTOM_238 }, { EL_CUSTOM_239, -1, -1, FALSE, IMG_CUSTOM_239 }, { EL_CUSTOM_240, -1, -1, FALSE, IMG_CUSTOM_240 }, { EL_CUSTOM_241, -1, -1, FALSE, IMG_CUSTOM_241 }, { EL_CUSTOM_242, -1, -1, FALSE, IMG_CUSTOM_242 }, { EL_CUSTOM_243, -1, -1, FALSE, IMG_CUSTOM_243 }, { EL_CUSTOM_244, -1, -1, FALSE, IMG_CUSTOM_244 }, { EL_CUSTOM_245, -1, -1, FALSE, IMG_CUSTOM_245 }, { EL_CUSTOM_246, -1, -1, FALSE, IMG_CUSTOM_246 }, { EL_CUSTOM_247, -1, -1, FALSE, IMG_CUSTOM_247 }, { EL_CUSTOM_248, -1, -1, FALSE, IMG_CUSTOM_248 }, { EL_CUSTOM_249, -1, -1, FALSE, IMG_CUSTOM_249 }, { EL_CUSTOM_250, -1, -1, FALSE, IMG_CUSTOM_250 }, { EL_CUSTOM_251, -1, -1, FALSE, IMG_CUSTOM_251 }, { EL_CUSTOM_252, -1, -1, FALSE, IMG_CUSTOM_252 }, { EL_CUSTOM_253, -1, -1, FALSE, IMG_CUSTOM_253 }, { EL_CUSTOM_254, -1, -1, FALSE, IMG_CUSTOM_254 }, { EL_CUSTOM_255, -1, -1, FALSE, IMG_CUSTOM_255 }, { EL_CUSTOM_256, -1, -1, FALSE, IMG_CUSTOM_256 }, { EL_GROUP_1, -1, -1, FALSE, IMG_GROUP_1 }, { EL_GROUP_2, -1, -1, FALSE, IMG_GROUP_2 }, { EL_GROUP_3, -1, -1, FALSE, IMG_GROUP_3 }, { EL_GROUP_4, -1, -1, FALSE, IMG_GROUP_4 }, { EL_GROUP_5, -1, -1, FALSE, IMG_GROUP_5 }, { EL_GROUP_6, -1, -1, FALSE, IMG_GROUP_6 }, { EL_GROUP_7, -1, -1, FALSE, IMG_GROUP_7 }, { EL_GROUP_8, -1, -1, FALSE, IMG_GROUP_8 }, { EL_GROUP_9, -1, -1, FALSE, IMG_GROUP_9 }, { EL_GROUP_10, -1, -1, FALSE, IMG_GROUP_10 }, { EL_GROUP_11, -1, -1, FALSE, IMG_GROUP_11 }, { EL_GROUP_12, -1, -1, FALSE, IMG_GROUP_12 }, { EL_GROUP_13, -1, -1, FALSE, IMG_GROUP_13 }, { EL_GROUP_14, -1, -1, FALSE, IMG_GROUP_14 }, { EL_GROUP_15, -1, -1, FALSE, IMG_GROUP_15 }, { EL_GROUP_16, -1, -1, FALSE, IMG_GROUP_16 }, { EL_GROUP_17, -1, -1, FALSE, IMG_GROUP_17 }, { EL_GROUP_18, -1, -1, FALSE, IMG_GROUP_18 }, { EL_GROUP_19, -1, -1, FALSE, IMG_GROUP_19 }, { EL_GROUP_20, -1, -1, FALSE, IMG_GROUP_20 }, { EL_GROUP_21, -1, -1, FALSE, IMG_GROUP_21 }, { EL_GROUP_22, -1, -1, FALSE, IMG_GROUP_22 }, { EL_GROUP_23, -1, -1, FALSE, IMG_GROUP_23 }, { EL_GROUP_24, -1, -1, FALSE, IMG_GROUP_24 }, { EL_GROUP_25, -1, -1, FALSE, IMG_GROUP_25 }, { EL_GROUP_26, -1, -1, FALSE, IMG_GROUP_26 }, { EL_GROUP_27, -1, -1, FALSE, IMG_GROUP_27 }, { EL_GROUP_28, -1, -1, FALSE, IMG_GROUP_28 }, { EL_GROUP_29, -1, -1, FALSE, IMG_GROUP_29 }, { EL_GROUP_30, -1, -1, FALSE, IMG_GROUP_30 }, { EL_GROUP_31, -1, -1, FALSE, IMG_GROUP_31 }, { EL_GROUP_32, -1, -1, FALSE, IMG_GROUP_32 }, { -1, -1, -1, FALSE, -1 }, }; #endif /* CONF_E2G_C */ rocksndiamonds-3.3.0.1+dfsg1/README0000644000175000017500000003415107224222000015500 0ustar dimkadimka Welcome to R O C K S ' N ' D I A M O N D S ----------------------------------- A game for Unix/X11, DOS and Windows by Holger Schemel. DOS port based on code by Guido Schulz. (c) 1995-2000 by Holger Schemel. Introduction ============ This is a nice little game with color graphics and sound for your Unix system with color X11, DOS or Windows. You need an 8-bit color display or better. It will not work on black&white systems, and maybe not on gray scale systems. If you know the game "Boulderdash" (Commodore C64) or "Emerald Mine" (Amiga) or "Supaplex" (PC), you know what "ROCKS'N'DIAMONDS" is about. Getting started =============== Just 'cd' to the directory 'rocksndiamonds-*' (Unix, Windows) or 'rocks-*' (DOS) and type 'rocksndiamonds' (Linux, Windows) or 'rocks' (DOS)! This works only on Linux, DOS and Windows systems, because the included binary was compiled for Linux (i386/glibc) (if you have the Unix package) and DOS or Windows (if you have the DOS or Windows package). If you have another Unix system like HPUX, NetBSD or Solaris, you first have to type 'make' to compile it. See the file 'INSTALL' for details. This may be needed on Linux systems, too, depending on your kernel version, your libc version, your binary format, your processor, your karma, ... (The included Linux binary was compiled on a glibc 2.x system based on a 2.2.x Linux kernel and XFree86 4.0.x libraries.) The Menues ========== You can see eight blue circles on the left side of the eight green menu texts; these are buttons to activate the menu commands by simply clicking on them with a mouse. The button will then change to red. (You can control the menues over the keyboard or joystick, too. Just use the arrow keys and the 'Return' or 'Enter' key or, if you use a joystick, the appropriate direction and the fire button.) The menu 'name' / 'team' ------------------------ When you start the game the first time, your login name will appear in the 'NAME:' field. If you want to use a different name for playing, for example a funny player name or a name for cheating, you can click on the button and enter a new name. This menu will show the text 'team' instead of 'name' if you activated the team (local multiplayer) mode in the setup menu. See below. The menu 'level' ----------------- Choose any level from the current level series you want. The former 'handicap' limitation in choosing levels has been removed because of beeing annoying. If the level number is red, you have choosen a 'ready' level series (which is read-only and cannot be modified by the level editor); if it is yellow you have choosen a 'user' level series (which is writable and can be changed by the builf-in level editor). See below for using the level editor. To choose new level series, click on the button on the left and choose the new level series. Scroll the page up and down with the blue arrow buttons if there are more level series than would fit on the screen. Hall of fame ------------ Click on this button to see a list of the best players of this level. Click again to go back to the main menu. Level creator ------------- This brings you to the level editor, if you have switched to a 'yellow' (writable) level series. Info screen ----------- This screen shows you all elements which appear in the game and presents you the background music loops which you can listen to while playing the levels (not available on all systems). Start game ---------- This will start the game. The game will be automatically recorded 'on tape' if you have choosen this from the setup menu (see below). If you haven't choosen auto-recording level, but want to record this certain game, press the 'record' button on the level tape recorder to start game and recording. Setup ----- To change some things in the game, use the setup menu. You can enable/disable "Sound" (enables/disables _all_ sounds in the game), "Sound loops" (only useful on Linux systems), "Game music" (can always be enabled on very fast systems [exception: you don't like it], on slower systems it will take some percent of CPU time which will slow things down a bit) and "Toons", which will forbid/ permit the little animated toons. Forget about the setup options "Buffered Gfx" and "Fading" -- they have no effect at the moment and will probably disappear in future versions of the game. (Double-buffering is now always activated, because systems are fast enough now compared to 1995, when the last version of the game was released. Especially soft-scrolling needs the double-buffering. About fading from one screen to another with silly effects: Most players will probably deactivate it after a few minutes (see also "quick doors").) Enable "scroll delay" to avoid scrolling at each step, giving you an area where you can walk without scrolling until you get near enough to the screen border. Enable "soft scroll" for soft-scrolling. Looks nice, but may need a relatively fast graphics card. Systems from 1998 and later should be fast enough for enabling soft-scrolling. Enable "quick doors" if you are unpatient when switching between the several game screens where the doors have to be opened or closed. You will almost surely enable this if you design your own levels and therefore often switch between game and editor screens. Set "auto-record" to "on" if you want to automatically record each game by the built-in level tape recorder. For configuration of input devices like keyboard and joysticks, choose the sub-menu "input devices". "Exit" quits the setup menu without saving the changes, "Save and exit" will save and then return to the main menu. Input Devices (sub-menu of the setup menu) ------------------------------------------ "Player" lets you choose one of the four players. "Device" lets you choose the input device you want for this player; you can choose between the keyboard and one of the maximal four supported joysticks. (Normally you won't have more than two joysticks, but the Linux joystick driver supports more than two joysticks.) "Customize" / "Calibrate" lets you calibrate a joystick or customize the keyboard keys used for moving left, right, up and down, "snapping" fields without moving towards them and placing bombs. Just press the key you want to use for the specified action or press Return or Enter to stay with the already configured values. "Exit" brings you back to the setup screen. Quit ---- Exit the game. How To Play The Game ==================== When the game has started, you can see the playfield on the left side and a control field on the right side. The control field contains the following elements: Level indicator Tells you which level you are playing. Emeralds Shows you how many emeralds you still need to win the current level. Dynamite Shows you how many dynamite bombs you have. Keys Shows you which keys you have in your inventory. Score Shows the current score. In some levels there are some extra items giving extra score points. Time The seconds you have still left to play the level. Stop/Pause/Play Game controls to stop the game, pause it and go on playing. If the tape recorder is recording your game, it is stopping/pausing/playing as well. Music buttons The three music buttons can be used to control the background music loop, the 'looping' sounds and all other sounds. The little red light shows you if it is enabled or disabled. About the game itself: Of course you know Boulderdash, so you will know how to play the game. :) If not: You can move your playing figure with the configured keys (which will normally and by default be the arrow keys) or with a joystick. To 'snap' a field near you without moving to it, you can use the left fire button on your joystick (hold it down, move the stick to 'snap' the field, release the button) or the key you have configured for this action (by default one of the left modifier keys like 'Shift' or 'Control'). To place a piece of dynamite, use the right fire button on your joystick or use the key you have configured for this (by default one of the right modifier keys, but you can change all this to what you like). After placing the dynamite, better see to move away from this field...). Just try the levels from the 'tutorial' level serie to see what most of the elements do or have a look at the info screen! The Level Editor ================ To create your own levels, it's a good idea to start with your personal level series, which has been created automatically the first time you started the game (together with some configuration files). These personal files are stored in '~/.rocksndiamonds' on Unix systems and in 'userdata' in the current playing directory (which normally is the game directory) on DOS/Windows systems. The levels that come with the game are normally read-only, to avoid problems on multi user systems, but you can set them to 'writable' in the file 'levelinfo.conf' ('lvlinfo.cnf' on DOS systems) in each level directory. To edit a level, you can use all three mouse buttons to draw in the level window. Click into the elements field with one of the three buttons to remap it to the new element. Use the scrollbars, arrow buttons or cursor keys to scroll around in the level. Use the drawing functions by selecting them from the toolbox field or pressing the corresponding key (the key shortcuts for each gadget are displayed in the status line at the bottom of the window when the mouse pointer is over the gadget). About the drawing functions: If you know the good old "Deluxe Paint" from the Amiga, you will have no problems with the drawing functions -- even the key shortcuts are mostly the same. If not, just try them out and you will see what happens. ;-) Some notes: Most drawing functions have different behaviour when different mouse buttons are pressed in the drawing area; normally, the left mouse button is the 'foreground button' and the middle and right buttons are some sort of 'background buttons', often with relation to the chosen element mappings on this buttons. The '?' button brings you to the 'Element settings' page, where you can see some information about the element and how many of them are included in the current level. The contents of elements with content (some amoeba and the Yam Yam (also know as cruncher) can have content) can be edited by 'sticking' the page with the corresponding button on their page. Yam Yam's can have up to eight content areas. The 'undo' button gives you the chance to undo up to 10 drawing operations. The 'info' button brings you to the 'Level/Editor settings' page. The 'save' button asks you to save the current level. The 'clear' button clears the drawing area without asking. The 'test' button lets you play your new level directly from the editor. The 'exit' button asks you to exit the editor (if there are unsaved changes). In the 'Editor settings' section, you can give your level a new name and type in your name which will be displayed as the level's author. (On Unix systems, your login name will be taken as default.) Then you can modify the level playfield size there, the available time (set this to zero to get unlimited time for this level), the score you get for each 10 seconds time that are left when reaching the exit, and last but not least you can enter the number of emeralds the player has to collect before the exit door opens. Another new button is the 'double speed' button that lets the player move twice as fast as normally from start; the effect is the same as collecting a speed pill during the game. In the 'Editor settings' section, you can make some modifications to the behaviour of the 'random element placement' button (the dice): Choose if the number you can enter means how many percent of the whole level are filled with the element chosen as the random element, or if it should mean the exact number of elements to be placed in the level field. With the 'restrict' button on the left side you can force the random function not to overwrite level elements other than the element chosen in the content field on the right side. The Tape Recorder ================= You can use the tape recorder to record games and play tapes of previously played games. Just use them like a normal video recorder. Recording a game on tape: ------------------------- If you have enabled "auto-record", every game will automatically be recorded, so you just have to press "start game". Pressing the 'record' button on the tape recorder will start game and record it in any case. Saving a game tape: ------------------- To save a tape to the tape file corresponding to the level (that means that you can only save one tape file for each level), just press the 'eject' button (the very left button). Then you will be prompted if you really want to replace the old tape (if an old tape exists). Playing a tape: --------------- Just press 'play' and then either 'play' or 'pause'. While recording or playing, you can press 'pause' to stop the recording or the playing of the tape and continue by pressing 'pause' again. You can use either the tape recorder buttons or the game control buttons for this purpose. If you want to continue a previously recorded game, press 'pause' while playing, then 'record' to switch from 'paused playing' to 'paused recording' and then continue the game by pressing 'record' or 'pause'. If you want to fast-forward the tape to get faster to the point where you want to continue playing, press 'play' again while already playing, therefore activating 'fast forward' playing mode. Press again the 'play' button to enter a special playing mode: 'pause before end' will stop a few seconds before the end of the tape (which will in most cases stop a few seconds before you get killed in the previous playing recorded on that tape) -- after the automatic stop (which enters the 'pause' mode) you can continue the game as described above. And Now Have Fun! ================= Have fun playing the game, building new levels and breaking all high scores! :-) If you have designed new levels, mail them to me to include them in the next version (which will be released much earlier than again after three years like this version... ;-) If you have any comments, problems, suggestions, donations, flames, send them to info@artsoft.org or Snail Mail to Holger Schemel Detmolder Strasse 189 33604 Bielefeld GERMANY Have fun, Holger rocksndiamonds-3.3.0.1+dfsg1/docs/0000755000175000017500000000000011403523060015550 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/docs/elements/0000755000175000017500000000000011332305647017376 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_right.txt0000644000175000017500000000025110350102307024324 0ustar dimkadimkaNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_exit_closed.txt0000644000175000017500000000020010204217060023117 0ustar dimkadimkaYou can enter and win with a Supaplex exit even if there are unlit lightbulbs or unsaved penguins. All you need is enough gems. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/black_orb.txt0000644000175000017500000000025510204224153022044 0ustar dimkadimkaBlack Orb Bombs are floating explosives. They cannot be set off by anything other than another explosion, but once set off, a chain of them will explode at lightning speed! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/expandable_wall_any.txt0000644000175000017500000000025710204221604024117 0ustar dimkadimkaUnlike other growing walls, this wall will never "die off" because of other walls. It will spread wherever there is adjacent space, following even the most complicated paths. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_port.txt0000644000175000017500000000007310204216631021614 0ustar dimkadimkaPorts allow one way passage, as long as the path is clear. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_1.txt0000644000175000017500000000044010204222507021744 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_landmine.txt0000644000175000017500000000026010554522210022362 0ustar dimkadimkaIf you run into a land mine, you die. This type of land mine can be removed by snapping. Otherwise, it's a normal, destructible wall that just happens to look kinda like dirt. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/shield_deadly.txt0000644000175000017500000000060310204217621022717 0ustar dimkadimkaThis not only makes the player invincible, but also allows him to kill enemies just by pressing against them. Extra deadly shields will add more time without wasting any time already acquired. Picking up a deadly shield when you already have a normal shield (or vice versa) will not waste the normal shield; the player will use the normal shield when the deadly shield runs out. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/trigger_ce_value.txt0000644000175000017500000000040710427133573023447 0ustar dimkadimkaThis can be used in custom element programming to refer to the CE value of the element that triggered the change being processed, but interpreted as an element itself (if the CE value was set to an element earlier). Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon.txt0000644000175000017500000000017410350100617021554 0ustar dimkadimkaBalloons can be pushed by the player. Their more useful properties are only available in conjection with the wind switches. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_gate_white.txt0000644000175000017500000000021510554521713022722 0ustar dimkadimkaYou may only walk over a white gate if you have collected a white key. For each time to pass a white gate, you need to collect a white key. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_crystal.txt0000644000175000017500000000016210204214342022622 0ustar dimkadimkaThis wall contains a crystal which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_butterfly.txt0000644000175000017500000000043410204224641022614 0ustar dimkadimkaButterflies always try to follow the right side of a wall or other elements. Touching them is deadly. They will explode in 9 BD style diamonds if smashed by a rock or BD style diamond. If dynabombed, they will become one BD style diamond. Other explosions simply destroy them. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/steel_exit_closed.txt0000644000175000017500000000037310552151265023636 0ustar dimkadimkaThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. This exit is made of steel and is indestructible. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_2_gray.txt0000644000175000017500000000015410204221332022303 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_wet.txt0000644000175000017500000000042510204225204022226 0ustar dimkadimkaDripping amoeba will grow in drops, and will not die even if surrounded. Amoeba will kill any bugs, flies, or spaceships that touch it. The amoeba growth value is the same for all types of amoeba. Amoeba will take between 0 and [25/(1-value)] seconds to attempt to grow. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/spaceship.txt0000644000175000017500000000024010204216361022101 0ustar dimkadimkaSpaceships always try to follow the left side of a wall or other elements. Touching them is deadly. Spaceships will not explode when caught in explosions. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_gate_white_gray.txt0000644000175000017500000000015410427133724023746 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/envelope.txt0000644000175000017500000000020010204222017021726 0ustar dimkadimkaEnvelopes can be configured to contain a text message for the player. All envelopes of the same color contain the same message. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_8.txt0000644000175000017500000000044010204222507022116 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_key_2.txt0000644000175000017500000000012110204222137021610 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/unknown.txt0000644000175000017500000000002110427126557021634 0ustar dimkadimkaUnknown element. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/robot_wheel.txt0000644000175000017500000000055010204220044022430 0ustar dimkadimkaActivating the magic wheel attracts the robots for a short time and keeps them away from the player. When it stops running, the robots will again turn towards the player. The magic wheel can be activated again after it stopped running. You can also activate other magic wheels while one is spinning; the robots will go towards the latest active wheel. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/quicksand_full.txt0000644000175000017500000000016110204220164023124 0ustar dimkadimkaThis quicksand already contains a rock which can slide through it and leave it if there is empty space below it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/landmine.txt0000644000175000017500000000017510554522137021731 0ustar dimkadimkaIf you run into a land mine, you die. Otherwise, it's a normal, destructible wall that just happens to look kinda like dirt. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_disk_red.txt0000644000175000017500000000004210204217172022411 0ustar dimkadimkaRed disks are just like dynamite. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_key_8.txt0000644000175000017500000000012110204222144021757 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_slippery.txt0000644000175000017500000000014010204213572023010 0ustar dimkadimkaAs expected, objects slip off the round top of this wall. Otherwise, it's just an average wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dark_yamyam.txt0000644000175000017500000000022310204223407022420 0ustar dimkadimkaThe Dark Yam Yam doesn't contain anything, but it can devour just about anything, including dirt, gems, amoeba, enemies... and especially players! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid_pool_bottom.txt0000644000175000017500000000012010204225351023433 0ustar dimkadimkaAcid pool walls are equivalent to steel walls, except some of them are rounded. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bug.txt0000644000175000017500000000030610204224064020701 0ustar dimkadimkaBugs always try to follow the right side of a wall or other elements. Touching them is deadly. Bugs will explode into a diamond surrounded by 8 emeralds, even when caught in other explosions! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_yellow.txt0000644000175000017500000000010510204216677024026 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/trigger_player.txt0000644000175000017500000000023710427132674023162 0ustar dimkadimkaThis can be used in custom element programming to refer to the player who triggered the change being processed. Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_3.txt0000644000175000017500000000010110204221325021254 0ustar dimkadimkaYou may only walk over a colored door if you have the right key. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_murphy.txt0000644000175000017500000000016110204216651022154 0ustar dimkadimkaMurphy is the hero of Supaplex. Note that other than his default settings, Murphy behaves exactly like Rockford. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/conveyor_belt.txt0000644000175000017500000000034310204223711022775 0ustar dimkadimkaConveyor belts will move around any object that can fall. The edges of the belts aren't round, they just make your belt nicer. Each colored switch controls all of that color conveyor belt. Belts can be made of multiple colors. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dynamite.txt0000644000175000017500000000024110204222604021732 0ustar dimkadimkaCollect the dynamite and use it later to blow up walls (which might contain gems), enemies or other things. Dynamite caught in an explosion will explode itself! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_exit_open.txt0000644000175000017500000000053210554474735022624 0ustar dimkadimkaThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit disappears when the player is passing through it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_zonk.txt0000644000175000017500000000020310204216503021602 0ustar dimkadimkaThe Zonk is the Supaplex equivalent of the rock. Note that it can be pushed quicker than rocks, resulting in some clever tricks... rocksndiamonds-3.3.0.1+dfsg1/docs/elements/self.txt0000644000175000017500000000036310465152233021067 0ustar dimkadimkaThis is a placeholder for the custom element you are just editing. If an element should change to itself, you can use this "reference element" instead of the real element. If you copy your custom element, this elements still refers to itself. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_firefly.txt0000644000175000017500000000025410204224520022230 0ustar dimkadimkaFireflies always try to follow the left side of a wall or other elements. Touching them is deadly. Fireflies can be smashed by BD style diamonds in addition to rocks. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/biomaze.txt0000644000175000017500000000031210204224216021546 0ustar dimkadimkaThe Biomaze is a variant of the Game of Life that tends to make crazy mazes. The players don't count as cells with Biomaze. Watch those corners; it may take annoyingly long for the corners to clear up. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/key_4.txt0000644000175000017500000000025510204221051021133 0ustar dimkadimkaYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_magic_wall.txt0000644000175000017500000000063610554530724022712 0ustar dimkadimkaThis is a (DC style) magic wall. It gets activated for a limited time by rocks or gems that fall on it. Objects falling though it will be changed to other objects. After it has stopped running, it cannot be activated again. The duration is expressed in seconds. A duration of zero will let the wall run forever. All regular magic walls run together; however, BD style magic walls have a separate counter. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_emerald_purple.txt0000644000175000017500000000017110204214216024141 0ustar dimkadimkaThis wall contains a purple emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_red.txt0000644000175000017500000000010510204216703023253 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sokoban_field_player.txt0000644000175000017500000000033310204217332024277 0ustar dimkadimkaThis is the player standing on a sokoban field. If a level contains *only* sokoban elements (those in the sokoban section, steel walls, and empty space), it will be completed as soon the sokoban puzzle is solved. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_chip_top.txt0000644000175000017500000000005710204217210022431 0ustar dimkadimkaThis is a normal, destructable, slippery wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/pacman.txt0000644000175000017500000000013610204220447021365 0ustar dimkadimkaPacman moves like a Yam Yam, but doesn't contain anything. However, it is able to eat amoeba. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_3_gray.txt0000644000175000017500000000015410204221321022302 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_blue.txt0000644000175000017500000000010510204216714023432 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_port_any.txt0000644000175000017500000000005410204216615022464 0ustar dimkadimkaYou can enter this port from ANY direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/steel_exit_open.txt0000644000175000017500000000052010552151254023316 0ustar dimkadimkaThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit is made of steel and is indestructible. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_3.txt0000644000175000017500000000010510204216732023637 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/custom.txt0000644000175000017500000000024710204223435021443 0ustar dimkadimkaCustom elements can be defined to do a ton of things, more than this humble space can describe. Just be aware that the code doesn't care from level to level in a set. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_grass.txt0000644000175000017500000000004410427131006022066 0ustar dimkadimkaGrass behaves just exactly as sand. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_green.txt0000644000175000017500000000010510204216706023604 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/invisible_wall.txt0000644000175000017500000000022410204221142023120 0ustar dimkadimkaAn invisible wall behaves exactly like a normal wall, but is invisible. It can be made visible for a short time by activating the light switch. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/arrow_left.txt0000644000175000017500000000012410204225144022266 0ustar dimkadimkaThis acts as an average wall. Although it looks round, objects do not slide off it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/timegate_closed.txt0000644000175000017500000000005110204215562023254 0ustar dimkadimkaTime gates only open for a limited time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_bd_diamond.txt0000644000175000017500000000017510204214414023225 0ustar dimkadimkaThis wall contains a (BD style) diamond which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_pearl.txt0000644000175000017500000000016010204214100022232 0ustar dimkadimkaThis wall contains a pearl which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_gravity_on_port.txt0000644000175000017500000000014411332305625024061 0ustar dimkadimkaThese ports look like ordinary ports in-game, but when you go through them, gravity is switched on. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_android.txt0000644000175000017500000000022310427130607022374 0ustar dimkadimkaThe android has some special properties. Unless other elements, it can move diagonally. Additionally, it can clone other game elements it touches. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_diamond.txt0000644000175000017500000000014210204224531022201 0ustar dimkadimkaBD style levels require a certain amount of these diamonds to be collected to complete the level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_5.txt0000644000175000017500000000044010204222507022113 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_chip_left.txt0000644000175000017500000000005710204217216022567 0ustar dimkadimkaThis is a normal, destructable, slippery wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/time_orb_empty.txt0000644000175000017500000000007410204215647023153 0ustar dimkadimkaAn empty time orb behaves like a nut that can't be cracked. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_steel_exit_closed.txt0000644000175000017500000000037310554474635024332 0ustar dimkadimkaThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. This exit is made of steel and is indestructible. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall.txt0000644000175000017500000000007210204214500021055 0ustar dimkadimkaThis is an average wall. It can't stand up to explosions. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emerald.txt0000644000175000017500000000017610204222075021542 0ustar dimkadimkaYour basic gem. Collect enough of these to open the exit. Rockfords give off 9 of the appropriate colored gems when they die. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_magic_wall.txt0000644000175000017500000000057010204224454022676 0ustar dimkadimkaThis is a (BD style) magic wall. It gets activated for about 10 seconds by rocks or gems that fall on it. Rocks that fall through it become BD style diamonds, and gems that fall through it become BD style rocks. After it has stopped running, it cannot be activated again. All BD magic walls run on the same timer; however, regular magic walls run on a seperate timer. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/trigger_element.txt0000644000175000017500000000024110427132717023310 0ustar dimkadimkaThis can be used in custom element programming to refer to the element that triggered the change being processed. Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_disk_yellow.txt0000644000175000017500000000025010204217166023156 0ustar dimkadimkaYellow disks can be pushed around in any direction, and do not fall. They won't explode until a terminal is pressed, unless they are caught in an explosion themselves. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/light_switch.active.txt0000644000175000017500000000010710204220744024066 0ustar dimkadimkaAn active light switch will last for 10 seconds when the level starts. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_infotron.txt0000644000175000017500000000005010204216671022465 0ustar dimkadimkaInfotrons are the emeralds of Supaplex. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_electron.txt0000644000175000017500000000022010204217107022434 0ustar dimkadimkaThe electron produces 9 infotrons when smashed, and is only deadly if you collide with it. It follows the *left* wall, just like the snik snak. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_port_horizontal.txt0000644000175000017500000000003210204216605024061 0ustar dimkadimkaThis port goes both ways. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_steel_exit_open.txt0000644000175000017500000000060510554474756024024 0ustar dimkadimkaThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit is made of steel and is indestructible. It disappears when the player is passing through it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_emerald_yellow.txt0000644000175000017500000000017110204214002024136 0ustar dimkadimkaThis wall contains a yellow emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_4.txt0000644000175000017500000000010510204216724023641 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_chip_single.txt0000644000175000017500000000005710204217212023112 0ustar dimkadimkaThis is a normal, destructable, slippery wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_any.txt0000644000175000017500000000061110350102077024002 0ustar dimkadimkaPressing this switch in a certain direction will cause all balloons and custom elements that react on wind in this level to constantly move in that direction if possible until another wind switch is pressed. The balloons may still be pushed in any direction, including against their automatic movement direction, but they will try to move in the appropriate wind direction whenever they can. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid_pool_topright.txt0000644000175000017500000000012010204225337023773 0ustar dimkadimkaAcid pool walls are equivalent to steel walls, except some of them are rounded. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/nut.txt0000644000175000017500000000012110204220476020730 0ustar dimkadimkaThis nut contains an emerald. To get it, crack the nut by dropping a rock on it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_disk_orange.txt0000644000175000017500000000010410204217202023103 0ustar dimkadimkaOrange disks are like stable bombs, only they can be pushed faster. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/quicksand_fast_full.txt0000644000175000017500000000016110554542207024156 0ustar dimkadimkaThis quicksand already contains a rock which can slide through it and leave it if there is empty space below it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/invisible_steelwall.txt0000644000175000017500000000024110204221164024160 0ustar dimkadimkaAn invisible steel wall behaves exactly like a normal steel wall, but is invisible. It can be made visible for a short time by activating the light switch. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/robot.txt0000644000175000017500000000034010204220130021235 0ustar dimkadimkaRobots try to follow the player everywhere, taking the direct route. They're not very bright. Touching them for a short time (running side by side to them, for example) is not deadly, but don't let them run into the player! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/satellite.txt0000644000175000017500000000060110204217655022120 0ustar dimkadimkaSatellites will follow the player as best they can, and the only way to outrun them is with double speed. Satellites are harmless, and they can be pushed, but in multiples or with strategically placed walls, they can easily trap the player. When crushed or caught in an explosion, satellites will explode. Satellites can be used as a sort of moving platform when gravity is on. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_up.txt0000644000175000017500000000025110350102307023633 0ustar dimkadimkaNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/frankie.txt0000644000175000017500000000015610552151054021552 0ustar dimkadimkaThis is an average wall (that somehow reminds of Frankie Goes To Hollywood). It can't stand up to explosions. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_1.txt0000644000175000017500000000010510204216737023642 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_to_diamond.txt0000644000175000017500000000012110427134571023552 0ustar dimkadimkaThe "amoeba_to_diamond" element is a runtime element and should be removed here. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/key_2.txt0000644000175000017500000000025510204221102021126 0ustar dimkadimkaYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_sniksnak.txt0000644000175000017500000000011710204217143022447 0ustar dimkadimkaSnik snaks are basically spaceships, except you must collide with them to die. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_magic_ball.txt0000644000175000017500000000054310427131514023031 0ustar dimkadimkaThe magic ball can create new elements when activated by the magic ball switch. It is possible to use up to eight magic balls which create different elements by using the eight content areas. Instead of creating all elements from the content area, it is also possible to let the magic ball create only one element randomly selected from the content area. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_buggy_base.txt0000644000175000017500000000010610204217232022732 0ustar dimkadimkaTouching the buggy base when the electricity is arcing is bad news... rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_2_gray.txt0000644000175000017500000000062410204222426022773 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_emerald.txt0000644000175000017500000000016310204214253022554 0ustar dimkadimkaThis wall contains an emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/player_1.txt0000644000175000017500000000017410204220275021643 0ustar dimkadimkaThis is the player. You'll probably want to have one of these each level. If you have more than one, only one will be used. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_key_7.txt0000644000175000017500000000012110204222144021756 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/lamp.txt0000644000175000017500000000022210204221001021036 0ustar dimkadimkaLightbulbs need to be turned on by touching them before the exit will open. Watch out! If they're crushed by a rock, you won't be able to escape! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_6.txt0000644000175000017500000000044010204222507022114 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sokoban_object.txt0000644000175000017500000000025210204217275023114 0ustar dimkadimkaThese lightbulbs can be pushed around. The goal is to fill all the Sokoban fields at once. Only then will the exit open, assuming all other conditions have been met too. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/light_switch.txt0000644000175000017500000000024310204220736022616 0ustar dimkadimkaTouching a light switch will make all invisible things visible for 10 seconds. The invisible things will still be easy to tell apart from visible things, however. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/rock.txt0000644000175000017500000000024110204217767021074 0ustar dimkadimkaRocks are round, heavy, they fall, and they smash stuff. They don't smash anything unless being already in motion first. The player can push one rock at a time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/unused.txt0000644000175000017500000000002010427126640021430 0ustar dimkadimkaUnused element. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/diamond.txt0000644000175000017500000000011610204223372021537 0ustar dimkadimkaDiamonds are worth 3 gems, but unlike emeralds, they can be crushed by rocks. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_2.txt0000644000175000017500000000044010204222445021746 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/player_2.txt0000644000175000017500000000002210204220253021630 0ustar dimkadimkaThis is player 2. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/exit_open.txt0000644000175000017500000000043510204221720022115 0ustar dimkadimkaThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_dry.txt0000644000175000017500000000052310204225312022224 0ustar dimkadimkaThis is regular amoeba. If, when it attempt to grow, it is blocked in all directions by something other than the player, it will die. Amoeba will kill any bugs, flies, or spaceships that touch it. The amoeba growth value is the same for all types of amoeba. Amoeba will take between 0 and [25/(1-value)] seconds to attempt to grow. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/arrow_up.txt0000644000175000017500000000012410204225133021756 0ustar dimkadimkaThis acts as an average wall. Although it looks round, objects do not slide off it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_gate_fake_gray.txt0000644000175000017500000000025510554523254023540 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. This door is special in that there is no key at all to open it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_down.txt0000644000175000017500000000025110350102307024156 0ustar dimkadimkaNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_amoeba.txt0000644000175000017500000000055310204224753022026 0ustar dimkadimkaThe BD style amoeba has some special properties: When it is completely surrounded, it instantly turns into the specified content. But if this cannot be achieved in a certain amount of time, this amoeba instantly turns to BD boulders instead. BD amoeba is the only amoeba that can be smothered by the player. All amoeba types must share the same settings. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_1.txt0000644000175000017500000000010110204221346021255 0ustar dimkadimkaYou may only walk over a colored door if you have the right key. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/extra_time.txt0000644000175000017500000000015610204221457022273 0ustar dimkadimkaYou pick it up, it gives you 10 more units of time. It has no effect in an untimed level (other than points). rocksndiamonds-3.3.0.1+dfsg1/docs/elements/trap.txt0000644000175000017500000000023010204214716021071 0ustar dimkadimkaDigging this when the trap is open is fatal. Otherwise, it's just ordinary dirt. Snapping it when the trap is open will not kill the player, just fail. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bomb.txt0000644000175000017500000000020310204224120021030 0ustar dimkadimkaBombs can be blown up either by throwing them down or by dropping a rock on them. Bombs caught in an explosion explode themselves. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_exit_closed.txt0000644000175000017500000000031010554474526023124 0ustar dimkadimkaThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/yamyam.txt0000644000175000017500000000062310443635656021445 0ustar dimkadimkaThe Yam Yam is one of the most exciting creatures. When it explodes (by dropping a rock on it, for example), it can turn to nine new elements. Further exploding Yam Yams can turn to other elements, up to eight different sets of new elements. Sometimes the last emerald you are looking for to finish the level is hidden in a Yam Yam! But be careful: Yam Yams will eat all diamonds in their way! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/pearl.txt0000644000175000017500000000026610204220436021233 0ustar dimkadimkaA pearl is worth 5 emeralds, but it's very fragile. Not only can it be crushed by rocks, but if it falls and lands on something, it'll break! At least you won't get crushed by it... rocksndiamonds-3.3.0.1+dfsg1/docs/elements/speed_pill.txt0000644000175000017500000000013110204216324022240 0ustar dimkadimkaTaking this pill will double the player's speed. Additional pills are only worth points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sand.txt0000644000175000017500000000025010204217701021047 0ustar dimkadimkaSand blocks pretty much everything except the player. The player digs through the sand, leaving behind empty space. Sand often makes up the vast majority of the level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/quicksand_fast_empty.txt0000644000175000017500000000031210554542210024342 0ustar dimkadimkaA rock that is pushed or thrown on the quicksand sinks into it, passes it and again leaves it if there is empty space below it. Amoeba can grow into it, but other elements and the player can't pass it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/magic_wall.txt0000644000175000017500000000063610204220677022237 0ustar dimkadimkaThis is a (EM style) magic wall. It gets activated for a limited time by rocks or gems that fall on it. Objects falling though it will be changed to other objects. After it has stopped running, it cannot be activated again. The duration is expressed in seconds. A duration of zero will let the wall run forever. All regular magic walls run together; however, BD style magic walls have a separate counter. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_magnifier.txt0000644000175000017500000000015510172537744022733 0ustar dimkadimkaThe magnifier can be used to make fake grass visible and show the real color of gray doors for a short time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_key_5.txt0000644000175000017500000000012110204222144021754 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_gravity_off_port.txt0000644000175000017500000000014511332305647024224 0ustar dimkadimkaThese ports look like ordinary ports in-game, but when you go through them, gravity is switched off. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_rock.txt0000644000175000017500000000016010443634462021541 0ustar dimkadimkaThis is a BD style rock. It's not much different from a regular rock, but it can be jump-pushed by snapping it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/expandable_wall_horizontal.txt0000644000175000017500000000031510204221550025514 0ustar dimkadimkaThis wall will grow on either side that is open. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_8_gray.txt0000644000175000017500000000062410204222471023144 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_3_gray.txt0000644000175000017500000000062410204222362022773 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/char_space.txt0000644000175000017500000000033210204224000022201 0ustar dimkadimkaThe space character is tricky. It's basically like an invisible normal wall, but it won't light up when a light switch is flicked on. Watch out for these in the editor; they can often be confused for empty space. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dx_supabomb.txt0000644000175000017500000000007610204223260022430 0ustar dimkadimkaThe stable bomb won't roll or have other objects roll off it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/mole.txt0000644000175000017500000000040310204220537021057 0ustar dimkadimkaThe mole moves like a Yam Yam, except it doesn't pause before changing direction. The mole will not harm the player, but it can trap him. The mole leaves behind dirt wherever it goes, and it can dig through amoeba. If crushed, it will produce 9 red emeralds. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_fake_grass.txt0000644000175000017500000000023010427134364023063 0ustar dimkadimkaThe fake grass looks like normal grass, but but cannot be digged. If the magnifier has been collected, the fake grass becomes visible for a short time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid_pool_bottomleft.txt0000644000175000017500000000012010204225347024313 0ustar dimkadimkaAcid pool walls are equivalent to steel walls, except some of them are rounded. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_spring_bumper.txt0000644000175000017500000000012610427131712023630 0ustar dimkadimkaWhen a moving spring hits a spring bumper, it is reflected to the opposite direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/switchgate_switch.txt0000644000175000017500000000023010427130276023653 0ustar dimkadimkaThis is the switch for switching the switch gates. When you switch the switch that controls the switching of the switch gates... okay, I'll stop. :-) rocksndiamonds-3.3.0.1+dfsg1/docs/elements/bd_wall.txt0000644000175000017500000000026210204224241021526 0ustar dimkadimkaThis is the BD style wall. Unlike most other walls, falling objects slip off this wall, although it does not look rounded or crumbled. It can be destroyed by explosions. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid_pool_topleft.txt0000644000175000017500000000012010204225343023605 0ustar dimkadimkaAcid pool walls are equivalent to steel walls, except some of them are rounded. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_5_gray.txt0000644000175000017500000000062410204222471023141 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/exit_closed.txt0000644000175000017500000000031010204221776022430 0ustar dimkadimkaThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/current_ce_score.txt0000644000175000017500000000034510427133551023462 0ustar dimkadimkaThis can be used in custom element programming to refer to the CE score of the current element, but interpreted as an element itself (if the CE score was set to an element earlier). Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_dripper.txt0000644000175000017500000000022110443635063022423 0ustar dimkadimkaThis element can create new amoeba drops and is otherwise invisible. If the lenses have been collected, the dripper is visible for a short time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/char.txt0000644000175000017500000000010510204224037021036 0ustar dimkadimkaLetter walls are like normal walls, except they can spell out words. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_drop.txt0000644000175000017500000000016710204225322022377 0ustar dimkadimkaAn amoeba drop will become a dripping amoeba when it lands. It would be wise to stay out from underneath these things. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_port_vertical.txt0000644000175000017500000000003210204216601023475 0ustar dimkadimkaThis port goes both ways. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/quicksand_empty.txt0000644000175000017500000000031210204220225023314 0ustar dimkadimkaA rock that is pushed or thrown on the quicksand sinks into it, passes it and again leaves it if there is empty space below it. Amoeba can grow into it, but other elements and the player can't pass it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_6_gray.txt0000644000175000017500000000062410204222471023142 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_4_gray.txt0000644000175000017500000000062410204222250022770 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_4.txt0000644000175000017500000000010110204221313021252 0ustar dimkadimkaYou may only walk over a colored door if you have the right key. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/stoneblock.txt0000644000175000017500000000007210204216221022263 0ustar dimkadimkaThis is an average wall. It can't stand up to explosions. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_chip_bottom.txt0000644000175000017500000000005710204217223023137 0ustar dimkadimkaThis is a normal, destructable, slippery wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/empty_space.txt0000644000175000017500000000010410204222027022426 0ustar dimkadimkaJust empty space. Everything can walk, move or fall through it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/expandable_wall_vertical.txt0000644000175000017500000000032710204221504025136 0ustar dimkadimkaThis wall will grow on the top and bottom if unobstructed. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dynabomb_increase_number.txt0000644000175000017500000000074210204223243025142 0ustar dimkadimkaDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pick-up will increase the number of Dynabombs the player can put on the field at one time. This number starts at zero, so the player must pick up one of these to use Dynabombs. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_5.txt0000644000175000017500000000010510204216722023640 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_magic_ball_switch.txt0000644000175000017500000000007710427131552024416 0ustar dimkadimkaUse the magic ball switch to enable or disable the magic ball. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/steelwall.txt0000644000175000017500000000010510204216251022114 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_1_gray.txt0000644000175000017500000000015410204221344022305 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/arrow_down.txt0000644000175000017500000000012410204225150022300 0ustar dimkadimkaThis acts as an average wall. Although it looks round, objects do not slide off it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/time_orb_full.txt0000644000175000017500000000031510204215637022754 0ustar dimkadimkaPressing against a time orb gives you ten extra units of time. Look out, however... in an untimed level, a time orb will give you 10 seconds/steps to complete the level! Orbs can fall and hurt the player. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/crystal.txt0000644000175000017500000000010110204223550021575 0ustar dimkadimkaCrystals are indestructable and are worth a whopping 8 emeralds! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_left.txt0000644000175000017500000000025110350102307024141 0ustar dimkadimkaNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/prev_ce.txt0000644000175000017500000000026710465152326021567 0ustar dimkadimkaIf you use this reference element, it will be replaced by the custom element that is at an earlier position in the element list (with the distance as shown by the reference element). rocksndiamonds-3.3.0.1+dfsg1/docs/elements/trigger_ce_score.txt0000644000175000017500000000040710427133604023441 0ustar dimkadimkaThis can be used in custom element programming to refer to the CE score of the element that triggered the change being processed, but interpreted as an element itself (if the CE score was set to an element earlier). Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_fake_acid.txt0000644000175000017500000000007710427132402022644 0ustar dimkadimkaThe fake acid looks like acid, but is walkable for the player. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dynabomb_increase_size.txt0000644000175000017500000000064110204223021024614 0ustar dimkadimkaDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pickup increases the length of the explosion. At first, the explosion only reaches one square in each direction. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_lenses.txt0000644000175000017500000000013410172540017022243 0ustar dimkadimkaThe lenses can be used to make the invisible wall and the dripper visible for a short time. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/player_3.txt0000644000175000017500000000002210204220244021631 0ustar dimkadimkaThis is player 3. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_7.txt0000644000175000017500000000044010204222507022115 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dragon.txt0000644000175000017500000000047410204223363021405 0ustar dimkadimkaThe fearsome dragon is completely harmless to the player; even their firey breath won't faze him. Dragons wander about aimlessly and will breathe fire if they aren't trapped, producing effects similar to explosions. Getting them to do something useful can be quite a challenge in a space bigger than 4 or 5 squares. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/from_level_template.txt0000644000175000017500000000035511322425203024155 0ustar dimkadimkaThis is a special element that can be used in levels using a level template. Every element of this kind in the playfield will be replaced with the element from the (otherwise unused) playfield of the level template at the same position. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dc_key_white.txt0000644000175000017500000000035310554522025022572 0ustar dimkadimkaYou need a white key to pass through a white gate. For each time to pass a white gate, you need to collect another white key. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_key_3.txt0000644000175000017500000000012110204222132021604 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/shield_normal.txt0000644000175000017500000000024410204217550022747 0ustar dimkadimkaPicking this up will give the player 10 seconds of invulnerability. Additional shields will add 10 more seconds, and will not waste seconds the player already has. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_terminal.txt0000644000175000017500000000016410204216516022446 0ustar dimkadimkaPress a terminal, and all the yellow disks on the level will explode! Otherwise, it's a normal wall all over again. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_4.txt0000644000175000017500000000044010204222327021747 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/game_of_life.txt0000644000175000017500000000057310204221442022523 0ustar dimkadimkaThese walls behave like the well-known "Conway's Game of Life". They behave like normal walls; however, they may appear or disappear every half-second according to these rules: Cells that are surrounded by 2 or 3 cells are the only cells that survive. Space or dirt that is surrounded by exactly 3 cells grows into new cells. The player(s) is (are) counted as cells! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_plant.txt0000644000175000017500000000007610427132047022100 0ustar dimkadimkaThe plant is deadly to the player when he is running into it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/next_ce.txt0000644000175000017500000000026410465152344021566 0ustar dimkadimkaIf you use this reference element, it will be replaced by the custom element that is at a later position in the element list (with the distance as shown by the reference element). rocksndiamonds-3.3.0.1+dfsg1/docs/elements/invisible_sand.txt0000644000175000017500000000021710204221170023111 0ustar dimkadimkaInvisible sand behaves exactly like normal sand, but is invisible. It can be made visible for a short time by activating the light switch. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/tube.txt0000644000175000017500000000017610204214531021066 0ustar dimkadimkaA tube is just something to crawl around in and get lost. Things outside the tube can't affect things inside, and vice versa. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dynamite.active.txt0000644000175000017500000000010310204222641023202 0ustar dimkadimkaAlready burning dynamite will explode in a few seconds. Stay away! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_chip_right.txt0000644000175000017500000000005710204217214022750 0ustar dimkadimkaThis is a normal, destructable, slippery wall. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_3.txt0000644000175000017500000000044010204222402021740 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/conveyor_belt_switch.txt0000644000175000017500000000032510204223623024360 0ustar dimkadimkaPressing against this switch turns conveyor belts on and off. If it starts off, it will toggle from off to left to off to right. Switches (and therefore their belts) may also start turned on to the right or left. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_6.txt0000644000175000017500000000010510204216717023645 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid_pool_bottomright.txt0000644000175000017500000000012010204225345024474 0ustar dimkadimkaAcid pool walls are equivalent to steel walls, except some of them are rounded. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/key_3.txt0000644000175000017500000000025510204221071021134 0ustar dimkadimkaYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sokoban_field_empty.txt0000644000175000017500000000052710204217466024156 0ustar dimkadimkaThis is an empty sokoban field. Only the player and sokoban objects can pass onto these fields. Watch out, the fields will be destroyed by explosions! Note that spare fields will prevent the exit from opening, but spare objects won't. Also, sometimes it is necessary to push sokoban objects off of fields to make room for other things. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/steelwall_slippery.txt0000644000175000017500000000004710204216232024047 0ustar dimkadimkaThis is a steel wall that is slippery. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/spring.txt0000644000175000017500000000021510204216270021425 0ustar dimkadimkaOnce you push a spring, it will keep on going in that direction until it falls or hits a wall. It isn't slippery, and will crush the player. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_emerald_red.txt0000644000175000017500000000016610204214046023411 0ustar dimkadimkaThis wall contains a red emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/key_1.txt0000644000175000017500000000025510204221113021127 0ustar dimkadimkaYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/switchgate.txt0000644000175000017500000000025210204216113022262 0ustar dimkadimkaSwitch gates can be passed through like ports or doors when they are open. When a switch gate switch is switched (switch!), *all* switch gates on the level toggle state. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_full.txt0000644000175000017500000000021610204225270022372 0ustar dimkadimkaWhen this amoeba is completely surrounded, it gradually turns into the specified content. All amoeba types must share the same settings. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/group.txt0000644000175000017500000000045610204221262021263 0ustar dimkadimkaGroup elements are perhaps best described as groups *of* elements. When the level starts, they will be replaced with the elements in the group from left to right, and top to bottom, in a manner chosen in the element. Most useful is the random option; this can make your levels be different every time! rocksndiamonds-3.3.0.1+dfsg1/docs/elements/steel_char.txt0000644000175000017500000000012110550557532022245 0ustar dimkadimkaSteel letter walls are like normal steel walls, except they can spell out words. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sokoban_field_full.txt0000644000175000017500000000046410204217412023751 0ustar dimkadimkaThis is a sokoban field that already has a sokoban object. Note that it's safe to blow up a full sokoban field without affecting your ability to open the exit. Also, if the exit is already open, it will never close up. However, disrupting the puzzle in any other way will mess up your chances to win. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_4_gray.txt0000644000175000017500000000015410204221306022306 0ustar dimkadimkaGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/timegate_open.txt0000644000175000017500000000007210204215545022750 0ustar dimkadimkaAn open time gate will close as soon as the level starts. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_base.txt0000644000175000017500000000014110204217243021536 0ustar dimkadimkaThe base is the Supaplex equivalent of dirt. Bases will block Dark Yam Yams, but not amoeba. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_gate_7_gray.txt0000644000175000017500000000062410204222471023143 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/lamp.active.txt0000644000175000017500000000015210204221024022317 0ustar dimkadimkaAlready on lightbulbs can be safely shattered with rocks, without ruining your ability to exit the level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/acid.txt0000644000175000017500000000041310204225421021021 0ustar dimkadimkaThings that fall into acid will be destroyed. If the player touches acid from the bottom or sides, he will die (although acid tends to look ugly if not enclosed in a pool). Most animate objects have a checkbox that determines whether or not they will move into acid. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sign.txt0000644000175000017500000000004510552150577021101 0ustar dimkadimkaJust a steel wall with a sign on it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/any_element.txt0000644000175000017500000000011410465152405022431 0ustar dimkadimkaThis is a reference element that matches all (standard or custom) elements. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/pig.txt0000644000175000017500000000032410204220333020676 0ustar dimkadimkaThe pig follows a wall, but it will switch from side to side or even corner to corner if it is in a small corridor. The pig will steal any gems it gets its hands on. You can walk over the pig if it's not moving. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/amoeba_dead.txt0000644000175000017500000000022110204225333022321 0ustar dimkadimkaDead ameoba won't grow, but it still retains its enemy-killing powers. It is often used as a wall that needs to be cleared by bugs, pacmen, etc. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_gravity_port.txt0000644000175000017500000000015310204217033023355 0ustar dimkadimkaThese ports look like ordinary ports in-game, but when you go through them, gravity is toggled on and off. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/balloon_switch_none.txt0000644000175000017500000000025210350102202024141 0ustar dimkadimkaPressing this switch will turn the wind off, stopping all moving balloons or other elements that are affected by wind (like custom elements that move in wind direction). rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_key_4.txt0000644000175000017500000000012110204222124021606 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/wall_diamond.txt0000644000175000017500000000016210204214303022551 0ustar dimkadimkaThis wall contains a diamond which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/gate_2.txt0000644000175000017500000000010110204221334021253 0ustar dimkadimkaYou may only walk over a colored door if you have the right key. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_base_2.txt0000644000175000017500000000010510204216734023640 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/expandable_wall.txt0000644000175000017500000000054210204221657023255 0ustar dimkadimkaThis wall will grow on either side that is open. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. This particular growing wall is the only one that is visibly different to the player from a normal wall, at least under the default graphics. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/penguin.txt0000644000175000017500000000051610204220374021574 0ustar dimkadimkaPenguins follow the player as best they can. If they are next to an open exit, they will leave the level. All the penguins *must* exit before the player exits, or the player will not win the level. If a penguin is smashed, it'll produce one purple gem, but the level will then be unsolvable. Penguins can collect gems for the player. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/emc_key_6.txt0000644000175000017500000000012110204222144021755 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/arrow_right.txt0000644000175000017500000000012410204225137022453 0ustar dimkadimkaThis acts as an average wall. Although it looks round, objects do not slide off it. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/player_4.txt0000644000175000017500000000002210204220241021627 0ustar dimkadimkaThis is player 4. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/current_ce_value.txt0000644000175000017500000000034510427133560023463 0ustar dimkadimkaThis can be used in custom element programming to refer to the CE value of the current element, but interpreted as an element itself (if the CE value was set to an element earlier). Don't use this element directly in your level. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_gate_1_gray.txt0000644000175000017500000000062410204222471022772 0ustar dimkadimkaEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/timegate_switch.txt0000644000175000017500000000020410204215531023300 0ustar dimkadimkaAs long as a single time gate switch is spinning, all time gates will be open. Each switch spins for a certain time when touched. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/em_key_1.txt0000644000175000017500000000012110204222144021605 0ustar dimkadimkaEmerald Mine style keys are identical to regular keys. They just look different. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/sp_hardware_gray.txt0000644000175000017500000000010510204216712023443 0ustar dimkadimkaAn indestructable, flat wall. Nothing's getting through this sucker. rocksndiamonds-3.3.0.1+dfsg1/docs/elements/dynabomb_increase_power.txt0000644000175000017500000000071110204223156025005 0ustar dimkadimkaDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pickup allows Dynabomb explosions to destroy brick walls, rather than stopping at the first wall. Picking up 2 of these will only get you extra points. rocksndiamonds-3.3.0.1+dfsg1/ChangeLog0000644000175000017500000030210111403522571016375 0ustar dimkadimka2010-06-08 * version 3.3.0.1 released 2010-06-08 * added configurable key shortcuts for snap+direction player actions (probably most useful for recording tool-assisted speedrun (TAS) tapes using the single-step mode of the tape recorder) 2010-05-28 * version number set to 3.3.0.1 2010-05-25 * version 3.3.0.0 released 2010-05-22 * fixed missing memory allocation in SP engine when saving engine data for non-SP game engine snapshots (which also stores SP engine part) 2010-05-21 * fixed problem with scrolling in native EM engine in multi-user mode (this bug was just introduced with the experimental viewport stuff) * fixed animation of splashing acid in EM engine with classic artwork * fixed animation of cracking nut in EM engine with classic artwork * fixed (implemented) single step mode in native EM and SP engines * fixed "latest_engine" flag in classic levels (moved to single sets) * updated SDL library DLLs for Windows to the latest release versions (this fixed some mysterious crashes of the game on Windows systems) * replaced EM and SP set in classic level set with native level files * finally added a newly written "CREDITS" file to the game package * removed sampled music loops from classic music set 2010-04-20 * changed native Emerald Mine engine to support different viewport sizes 2010-04-19 * changed native Supaplex engine to support different viewport sizes 2010-04-07 * added initial, experimental support for different viewport properties (with "viewports" being menu/playfield area and doors; currently the size of the menu/playfield area and door positions can be redefined) 2010-04-02 * added initial, experimental support for different window sizes 2010-03-27 * added support for native Sokoban solution files in pure 'udlrUDLR' format with extension ".sln" instead of ".tape" for solution tapes 2010-03-26 * added image config suffix ".class" to be able to define classes of crumbled elements which are then separated against each others when drawing crumbled borders (class names can freely be defined) (Example: "sand.CRUMBLED.class: sand" and "emc_grass.CRUMBLED.class: emc_grass" results in sand and emc_grass being crumbled separately, even if directly adjacent on the playfield.) * added image config suffix ".style" to use two new features for crumbled graphics: - "accurate_borders": try to draw correctly crumbled corners (which means that a row of crumbled elements does not have two crumbled corners for each element in the row, but only at the "real" corners at the start and the end of the row of elements) - "inner_corners": also draw inner corners in concave constructions of several crumbled elements -- this is currently a big kludge: the number of frames for crumbled graphic must be "2", with the first frame as usual (crumbled graphic), while the second frame contains the graphic with inner (crumbled) corners for the crumbled graphic (These two features are mainly intended for bevelled walls, not for diggable elements like sand; "inner_corners" only works reliably for static walls, not for in-game dynamically changing walls using CEs.) 2010-03-16 * finished code cleanup of native Supaplex game engine 2010-03-14 * started code cleanup of native Supaplex game engine 2010-03-13 * integrated playing sound effects into native Supaplex game engine 2010-03-10 * added configurable key shortcuts for the tape recorder buttons 2010-03-09 * added (hidden) function to save native Supaplex levels with tape as native *.sp file containing level with demo (saved with a file name similar to native R'n'D levels, but with ".sp" extension instead of ".level"); to use this functionality, enter ":save-native-level" or ":snl" from the main menu with the native Supaplex level loaded and the appropriate tape loaded to the tape recorder * fixed potential crash bug caused by illegal array access in engine snapshot loading and saving code * changed setting permissions of score files to be world-writable if the program is not installed and running setgid to allow the program to modify existing score files when run as a different user (which allows cheating, of course, as the score files are not protected against modification in this case) * added (commented out) suggestions for RO_GAME_DIR and RW_GAME_DIR to the top level Makefile for Debian / Ubuntu installations * added saving read-only levels from editor into personal level set (thanks to Bela Lubkin for the above four patches) 2010-03-03 * added updating of game values on the panel to Supaplex game engine 2010-02-23 * finished integrating R'n'D graphics engine into Supaplex game engine (although some animations do not support full customizability yet) 2010-02-22 * done integrating R'n'D graphics engine into file "Infotron.c" * done integrating R'n'D graphics engine into file "OrangeDisk.c" 2010-02-19 * integrated engine snapshot functionality into Supaplex game engine 2010-02-16 * fixed bug in native Supaplex engine that broke several demo solutions * fixed bug with re-initializing already existing elements in function RelocatePlayer() in src/game.c (causing problems with Sokoban fields counted a second time, making the currently playing level unsolvable) * done integrating R'n'D graphics engine into file "SnikSnaks.c" * done integrating R'n'D graphics engine into file "Electrons.c" * done integrating R'n'D graphics engine into file "Zonk.c" 2010-02-14 * done integrating R'n'D graphics engine into file "Murphy.c" * done integrating R'n'D graphics engine into file "BugsTerminals.c" 2010-02-07 * started integrating R'n'D graphics engine into Supaplex game engine 2010-02-02 * added small kludge that allows transparent pushing animation over non-black background (by using "game.use_masked_pushing: true") * added editor flag to Sokoban field/object elements to automatically finish solved Sokoban style levels (even if they contain non-Sokoban elements, which prevents auto-enabling this feature for such levels) 2010-01-10 * added new element "from_level_template" which is replaced by element from level template at same playfield position when loaded (currently not accessible from level editor, but only used for special Sokoban level conversion when using "special_flags: load_xsb_to_ces") * added special behaviour for "special_flags: load_xsb_to_ces": global settings of individual level files are overwritten by template level (except playfield size, level name, level author and template flag) 2010-01-07 * added handling of gravity ports when converting Supaplex style R'n'D levels to native Supaplex levels for playing with Supaplex engine 2010-01-06 * fixed bug in Supaplex engine regarding initial screen scroll position 2009-12-17 * fixed EMC style pushing animations in the R'n'D graphics engine (when using ".2nd_movement_tile" for animations having start and end tile) * for this to work (look) properly for two-tile pushing animations with non-black (i.e. opaque) background, the pushing graphics drawing order was changed to first draw the pushed element, then the player (maybe this should be controlled by an ".anim_mode" flag yet to be added) * two-tile animations for moving or pushing should have 7 frames for normal speed, 15 frames for half speed etc. to display correct frames * two-tile animations are also displayed correctly with different speed settings for the player (for pushing animations) or moving elements 2009-12-16 * added searching for template level (file "template.level") not only inside the level set directory, but also in above level directories; this makes is possible to use the same single template level file (placed in a level group directory) for many level sub-directories 2009-12-10 * fixed bug with steel exit being destructible during opening phase * added token "special_flags" to "levelinfo.conf" (currently with the only recognized value "load_xsb_to_ces", doing the same as the flag "-Dload_xsb_to_ces" on the command line, but as a permanent flag for converting all elements in native (XSB) Sokoban level files to CEs) 2009-12-08 * fixed some problems with Supaplex engine when compiling for Windows 2009-12-05 * added special mode to convert elements of Sokoban XSB levels to CEs by adding "-Dload_xsb_to_ces" to the command line starting the game (also adding a dependency to a template level file "template.level") 2009-12-01 * added reading native Sokoban levels and level packages (XSB files) 2009-11-25 * fixed bugs in (auto)scrolling behaviour when passing ports or when wrapping around the playfield through "holes" in the playfield border 2009-11-24 * changed internal playfield bitmap handling from playfield sized bitmap to screen sized bitmap (visible scrolling area), therefore speeding up graphics operations (by eliminating bitmap updates in invisible areas) and removing playfield size limitations due to increasing bitmap size for larger playfield sizes (while the new implementation always uses a fixed playfield bitmap size for arbitrary internal playfield sizes) 2009-11-12 * fixed bug with single step mode (there were some cases where the game did not automatically return to pause mode, e.g. when trying to push things that cannot be pushed or when trying to run against a wall) 2009-11-01 * added support for loading Supaplex levels in MPX level file format 2009-10-31 * fixed SP engine to set "game over" not before lead out counter done 2009-10-30 * fixed (potential) compile error when using GCC option "-std=gnu99" (thanks to Tom "spot" Callaway) 2009-10-28 * fixed array allocation in native Supaplex engine to correctly handle preceding scratch buffers (needed because of missing border checking) * fixed playfield initialization to correctly add raw header bytes as subsequent scratch buffer (needed because of missing border checking) 2009-10-24 * most important parts of native Supaplex engine integration working: - native Supaplex levels can be played in native Supaplex engine - native Supaplex level/demo files ("*.sp" files) can be re-played - all 111 classic original Supaplex levels automatically solvable - native Supaplex engine can be selected and used from level editor - logic of re-playing Supaplex demos migrated to R'n'D tape logic 2009-09-25 * fixed another translation problem from VisualBasic to C (where "int" should be "short") causing unsolvable demos with bugs and terminals ("bugs" being related to the Supaplex "buggy base" element here ;-) ) 2009-09-23 * fixed bug when reading Supaplex single level files (preventing loader from seeking to level position like in Supaplex level package files) 2009-08-01 * first classic Supaplex level running and solved by solution/demo tape 2009-06-20 * started with integration of native Supaplex engine, using source code of Megaplex from Frank Schindler, based on original Supaplex engine 2009-06-16 * version number set to 3.2.6.2 2009-06-15 * version 3.2.6.1 released 2009-05-31 * fixed bug with element_info[e].gfx_element not being initialized in early game stage, causing native graphics in EMC level sets to be mapped completely to EL_EMPTY (causing a blank screen when playing) (this only happened when starting the program with an EMC set with native graphics, but not when switching to such a set at runtime) 2009-03-30 * deactivated blit-to-same-surface workaround again (see 2009-03-24) and using self-compiled, patched SDL.dll that solves this problem (interim solution until release of SDL 1.2.14 that should fix this) 2009-03-26 * extended backwards compatibility mode to allow already fixed bug with change actions (see "2008-02-05") for existing levels (especially the Zelda and Zelda II levels and other cool stuff by Alan Bond like FMV) 2009-03-24 * reactivated workaround to prevent program crashes due to blitting to the same SDL surface that apparently only occurs on Windows systems (this is no final solution; this problem needs further investigation) 2008-11-05 * version number set to 3.2.6.1 2008-11-04 * version 3.2.6.0 released 2008-10-11 * fixed behaviour of player option "no centering when relocating" which was incorrect when disabled and relocation target inside visible area and "no scrolling when relocating" enabled at the same time 2008-10-06 * fixed problems with re-mapping players on playfield to input devices: previously, players found on the level playfield were changed to the players connected to input devices (for example, player 3 in the level was changed to player 1 (using artwork of player 3, to be able to use a player with a different color)); this had the disadvantage that CE conditions using player elements did not work (because the players in the level definition are different to those effectively used in-game); the new system uses the same player elements as defined in the level playfield and re-maps the input devices of connected players to the corresponding player elements when playing the level (in the above example, player 3 now really exists in the game and is moved using the events from input device 1); level tapes still store the events from input devices 1 to 4, which are then re-mapped to players accordingly when re-playing the tape (just as it is done when playing the level) 2008-09-29 * fixed bug with player relocation while the player switches an element 2008-09-24 * fixed bug with EM/DC style exit and EM/DC style steel exit which was not walkable (and did not let the player enter) when in process of opening, but not fully open yet (which can cause the player not being able to enter the exit in EM/DC style levels in time) 2008-08-02 * fixed some bugs regarding the new level/CE random seed reset options 2008-07-14 * moved "level settings" and "editor settings" to two tabbed screens in level editor to gain space for additional level property settings * added level setting to start a level with always the same random seed * added CE action "set random seed" to re-initialize random seed in game (this is the only CE action that gets executed before the CE changes, which is needed to use the newly set random seed during the CE change) 2008-06-16 * fixed redraw problem of special editor door when playing from editor 2008-06-16 * fixed initialization of gfx_element for level sketch image creation 2008-06-15 * added switch for EM style dynamite "[ ] explodes with chain reaction" (with default set to "on" for existing levels, but "off" for all new levels), as EM style dynamite does not chain-explode in original EM 2008-02-05 * added optional initial inventory for players (pre-collected elements) * added change page actions "set player inventory" and "set CE artwork" * added recognition of "player" parameter on change pages when player actions are defined, but no trigger player in corresponding condition (this resulted in actions that only affected the first player before) * fixed bug with change actions being executed for newly created custom elements resulting from custom element changes, when the intention was only to check for change actions for the previous custom element 2008-02-03 * changed design and size of element drawing area in level editor * added "element used as action parameter" to element change actions 2008-01-27 * added possibility to reanimate player immediately after his death (for example, by "change to when explosion of ") 2008-01-25 * fixed bug with "gray" white door not being uncovered by magnifier * added score for collecting (any) key to the white key config page 2008-01-22 * added condition "deadly when " for custom elements that behaves a bit like the existing "deadly when ", but with the following differences: - it only kills players or friends when it was moving before it hits - it does not kill players or friends that try to run into it 2008-01-21 * fixed the following change conditions where a player element is used as the "element that is triggering the custom element change": - touching - hitting - explosion of - move of (the last two conditions already worked partially, but only for the first player, and not for the "Murphy" player when using "move of") 2008-01-20 * fixed crash bug caused by accessing invalid element (with value -1) in UpdateGameControlValues() * fixed graphical bug when using two-tile movement animations with EMC game engine without explicitly using native EMC graphics engine 2007-10-31 * fixed bug in new "can dig" feature (see below) so that an unsuccessful try to push something (due to push delay) does not cause a dig action 2007-10-29 * fixed bug with reference elements used as trigger elements on custom element change pages not being recognized * fixed bug with reference elements not being removed from the playfield * added engine functionality that allows custom elements that "can dig" other elements not only to do so when moving by themselves, but also when being pushed by the player (therefore adding the functionality to push one element over another element, replacing it with the new one) 2007-10-23 * added command line function to write level sketch images to directory 2007-10-20 * merged override and auto-override options into new override options with a new data type than can take the values "no", "yes" and "auto" 2007-10-18 * fixed growing steel wall to also leave behind steel wall instead of normal, destructible wall * fixed handling of rocks falling through stacks of quicksand with different speed (before, the rocks just got stuck in the quicksand) 2007-10-09 * fixed nasty bug with auto-override and normal override not working on program startup (especially when current level set has custom artwork) 2007-10-05 * version 3.2.5 released as special edition "R'n'D jue" 2007-10-05 * fixed X11 crash bug when blitting masked title screens over background 2007-10-04 * changed build system to support special editions (like "R'n'D jue") * added (hardcoded) loading graphics for "R'n'D jue" special edition * fixed X11 crash bug when scaling images with width/height less than 32 2007-09-27 * added "background.PLAYING" (only visible as two-pixel border in game) * added default level set for first start of special R'n'D version * changed door animations for editor always behaving like "quick doors" 2007-09-26 * added new custom artwork setup option "auto-override non-CE sets" for automatic artwork override that is only used for level sets without custom element artwork (as it does not make much sense to override any artwork that redefines custom element artwork for sets using CEs) * fixed default artwork for "special" R'n'D versions always using the "classic" artwork as the base if base artwork is not explicitly defined in "levelinfo.conf", regardless of different default artwork used by the special R'n'D version -- this is needed because any such custom artwork is designed using the "classic" artwork definitions as the base (including menu definitions and screen positions etc., which would otherwise be taken from the different special default artwork) 2007-09-17 * fixed drawing of animated "quicksand.filling" and "quicksand.emptying" for both EMC and R'n'D graphics engine (heavy workarounds needed due to massively broken handling of quicksand in R'n'D game engine) * fixed off-limits access to array in DrawLevelFieldCrumbledSandExt() * fixed crash bug (hopefully) when scrolling with cursor keys in editor 2007-09-16 * fixed small bug in toon drawing (introduced when fixing the crash bug) 2007-09-15 * added graphics definition "game.panel.highscore" to display the current levels current high score in the game panel 2007-09-13 * version number set to 3.2.5 2007-09-13 * version 3.2.4 released 2007-09-13 * fixed crash bug in toon drawing functions for large step offset values 2007-09-12 * fixed some problems with displaying game panel when quick-loading tape 2007-09-07 * fixed (experimental only) redrawing of every tile per frame (even if unneeded) for the extended (R'n'D based) EMC graphics engine * added optimization to only calculate element count for panel display if really needed (that is, if element count values defined on panel) * fixed problem with special editor door redraw when entering main menu 2007-09-03 * fixed bug with displaying background for title messages on info screen * some code cleanup for the extended (R'n'D based) EMC graphics engine 2007-09-01 * fixed bug with CE action "move player" always resulting in player 4 if there was a CE action with no trigger player (because the player element was calculated by using log_2() from trigger player bits with the value PLAYER_BITS_ANY) -- this is now fixed by also storing the triggering player bit mask and handling all players in "move player" * fixed bug when defined artwork cannot be found for artwork that has default artwork cloned from other artwork (without default filename) * added several fixes to the extended (R'n'D based) EMC graphics engine 2007-08-26 * fixed broken editor copy and paste for custom elements between levels 2007-08-25 * title messages are now also searched in graphics artwork directory; those found in graphics directory have precendence over those found in level directory -- this handles title messages stored in graphics directories as part of the artwork set, just like title images; this makes sense, as corresponding special font definitions for messages are usually defined in the same graphics artwork directory, and also because title images and title messages that are combined in a level set introduction should usually not be separated when the level set is used with a different artwork set (e.g. using "override graphics") * fixed problem with door borders on main screen by first drawing doors and then the corresponding border masks, but not vice versa * fixed problem with artwork config entries using the value "[DEFAULT]"; this does not what one might expect, but sets the value to an invalid value -- solution: simply ignore such entries, which results in this value keeping its previous (real) default value (in general, entries that should use their default value should just not be defined here) * fixed problem with wrong fading area size from main menu to setup menu 2007-08-22 * fixed problem with broken crumbled graphics after level set changes when using R'n'D custom artwork with level sets using the EMC engine 2007-05-07 * fixed invisible "joysticks deactivated ..." text on setup input screen 2007-04-27 * added use of hashes created from static lists (element tokens, image config, font tokens) to speed up lookup of configuration parameters * fixed bug where element and graphic config token lookup was mixed up 2007-04-26 * added "busy" animation when initializing program and loading artwork * added initialization profiling for program startup (debugging only) 2007-04-25 * fixed(?) very strange bug apparently triggered by memset() when code was cross-compiled with MinGW cross-compiler for Windows XP platform (this only happened when using SDL.dll also self-compiled with MinGW) 2007-04-19 * added graphics engine directive "border.draw_masked_when_fading" that enables/disables drawing of border mask over screen that is just faded 2007-04-18 * fixed small problem with separate fading definition for game screen 2007-04-14 * added additional configuration directives for setup screen draw offset menu.draw_xoffset.SETUP[XXX] and menu.draw_yoffset.SETUP[XXX] with XXX in GAME, EDITOR, GRAPHICS, SOUND, ARTWORK, INPUT, SHORTCUTS_1, SHORTCUTS_2, CHOOSE_ARTWORK, CHOOSE_OTHER (where "CHOOSE_ARTWORK" is used to define draw offset on custom artwork selection screens and "CHOOSE_OTHER" is used on all other list style selection screens, like choosing game speed or screen mode for fullscreen mode) * added additional configuration directives to define main menu buttons: - menu.button_name and menu.button_name.active - menu.button_levels and menu.button_levels.active - menu.button_scores and menu.button_scores.active - menu.button_editor and menu.button_editor.active - menu.button_info and menu.button_info.active - menu.button_game and menu.button_game.active - menu.button_setup and menu.button_setup.active - menu.button_quit and menu.button_quit.active * added eight pure decoration graphic definitions for the game panel 2007-04-08 * added support for accessing native Diamond Caves II level packages * fixed displaying of game panel values for Emerald Mine game engine * fixed displaying end-of-level time and score values on new game panel 2007-04-07 * added game panel control to display arbitrary elements on game panel * added game panel control to display custom element score (globally unique for identical custom elements) either as value or as element * added ".draw_masked" and ".draw_order" to game panel control drawing 2007-04-05 * fixed some general bugs with handling of ".active" elements and fonts 2007-04-04 * cleanup of game panel elements (some elements were not really needed) * added displaying of gravity state (on/off) as new game panel control * added animation for game panel elements (similar to game elements) 2007-04-03 * added new pseudo game mode "PANEL" to define panel fonts and graphics - panel fonts now use ".PANEL" suffix instead of ".PLAYING" suffix - panel graphics now use ".PANEL" suffix instead of ".DOOR" suffix (else graphics would have to use ".PLAYING", which would be confusing) * fixed bug when fading out to game screen with border mask defined 2007-04-02 * added attribute ".tile_size" for element style game panel controls 2007-04-01 * added key as additional valid key to use for confirm requester 2007-03-31 * improved menu fading, adding separate fading definitions for entering and leaving a "content" screen (in general), and optional definitions for the special "content" screens SCORES, EDITOR, INFO and PLAYING 2007-03-30 * added (currently invisible) setup option to define scroll delay value * fixed small bug in priority handling when auto-detecting level start position in levels without player element (but player from CE etc.) * added option "game.forced_scroll_delay_value" to override user choice of scroll delay value for certain level sets with "graphicsinfo.conf" * replaced setup option "scroll delay: on/off" by new setup option that directly allows selecting the desired scroll delay value from 0 to 8 2007-03-28 * added displaying of most game panel control elements (not animated) 2007-03-26 * added new configuration directives to display additional game engine values on the game control panel, like the following examples: - game.panel.time_hh/time_mm/time_ss - level time in HH/MM/SS format - game.panel.penguins - number of penguins to rescue - game.panel.level_name - level name of current level 2007-03-24 * added support for preview tile sizes "1" and "2" (1x1 and 2x2 pixels) 2007-03-23 * added new player option "no centering when relocating" for "invisible" teleportations to level areas that look exactly the same, giving the illusion that the player did not relocate at all (this was the default since 3.2.3, but caused visual problems with room creation in "Zelda") * added new menu fading effect "melt", shamelessly stolen from "DOOM" 2007-03-21 * improved menu fading, adding separate fading definitions for entering and leaving a menu and for fading between menu and "content" screens * fixed small bug with recognizing also ".font_xyz" style definitions 2007-03-20 * improved menu fading, adding separate fading definitions for fading between menu screens and fading between menu and "destination" screens 2007-03-19 * titlemessage_initial_x and titlemessage_x set to "[DEFAULT]" in static configuration (set from "[titlemessage_initial]" and "[titlemessage]") * fading settings of "[titlemessage_initial]" and "[titlemessage]" set to "[DEFAULT]" in static configuration (set from "[title_initial]" and "[title]") * improved title fading, allowing fading animation types "none", "fade" and "crossfade" (including cross-fading of last title to main menu) 2007-03-18 * added configurability of graphics, sounds and music for title screens, which are separated into initial title screens (only shown once at program startup) and title screens shown for a given level set; these title screens can be composed of up to five title images and up to five title text messages (each drawn using an optional background image), also using background music and/or sounds; aspects like background images, sounds and music of title screens can either be defined generally (valid for all title screens) or specifically (and therefore differently for each title screen) using these directives: to define a background image, sound or music file for all screens: - background.TITLE_INITIAL (for all title screens for game startup) - background.TITLE (for all title screens for level sets) to define a background image, sound or music file for a single screen: - background.titlescreen_initial_x (with x in 1,2,3,4,5) - background.titlescreen_x (with x in 1,2,3,4,5) - background.titlemessage_initial_x (with x in 1,2,3,4,5) - background.titlemessage_x (with x in 1,2,3,4,5) to define the title screen images: - titlescreen_initial_x (with x in 1,2,3,4,5) - titlescreen_x (with x in 1,2,3,4,5) to define the title text messages, place text files into the level set directory that have the following file names: - titlemessage_initial_x.txt (with x in 1,2,3,4,5) - titlemessage_x.txt (with x in 1,2,3,4,5) to define the properties of the text messages, either use directives that affect all text messages: - [titlemessage_initial]. - [titlemessage]. or use directives that affect single text messages: - titlemessage_initial_x. (with x in 1,2,3,4,5) - titlemessage_x. (with x in 1,2,3,4,5) valid values for are the same as for readme. below; use ".sort_priority" (default: 0) to define an arbitrary order for title images and title messages (which can therefore be mixed) 2007-03-14 * added full configurability of "readme.txt" screen appearance: - readme.x: - readme.y: - readme.width: - readme.height: - readme.chars: - readme.lines: - readme.align: left,center,right (default: center) - readme.top: top,middle,bottom (default: top) - readme.font: font name - readme.autowrap: true,false (default: true) - readme.centered: true,false (default: false) - readme.parse_comments: true,false (default: true) - readme.sort_priority: (not used here, but only for title screens) when "readme.chars" and/or "readme.lines" is set to "-1" (this is the default), they are automatically determined from "readme.width" and "readme.height" accordingly; when they are not "-1", they have precedence over "readme.width" and "readme.height" * added internal ad-hoc config settings for displaying text files like title messages or "readme.txt" style level set info files: - .font: font name (default: readme.font) - .autowrap: true,false (default: readme.autowrap) - .centered: true,false (default: readme.centered) - .parse_comments: true,false (default: readme.parse_comments) (the leading '.' and the separating ':' are mandatory here); to use these ad-hoc settings, they have to be written inside a comment, like "# .autowrap: false" or "# .centered: true"; these settings then override the above global settings (they can even be used more than once, like "# .centered: true", then some text that should be drawn centered, then "# .centered: false" to go back to non-centered text; important note: after using "# .parse_comments: false", or when using "readme.parse_comments: false", detecting and parsing comments inside the file is disabled and comments are just printed like normal text; also be aware that all automatic text size calculations are done with the font defined in "readme.font", while using different fonts using "# .font: " inside the text file may cause unexpected results 2007-03-08 * changed some numerical limits in the level editor from 255 to 999 2007-03-07 * added option "system.sdl_videodriver" to select SDL video driver * added output of SDL video and audio driver to "version info" page 2007-03-06 * added group element drawing to IntelliDraw drawing functions * fixed animation resetting problem again (last try broke Snake Bite) * fixed diagonal scrolling in screen scrolling (last try broke Pac Man) 2007-03-01 * added new (special) "include: " directive that works in all configuration files (like "graphicsinfo.conf") and that has the same effect as if that directive would be replaced with the content of the specified file (this can be useful to split large configuration files into several smaller ones and include them from one main file, or to store configuration settings that always stay the same into a separate file, while including it and only add those parts that really change) 2007-02-24 * fixed minor bug (screen redraw of player tiles) in EMC graphics engine 2007-02-23 * fixed bug in "InitMovingField()" where treating an integer array as boolean caused wrong resetting of animations while elements are moving * fixed problem with resetting animations when starting element change 2007-02-08 * added sort priority for order of title screens and title messages 2007-02-07 * changed end of game again: do not wait for the user to press a key anymore, but directly ask/confirm tape saving and go to hall of fame * re-enabled quitting of lost game by pressing space or return again * added blanking of mouse pointer when displaying title screens * added remaining menu draw offset definitions for info sub-screens 2007-02-05 * added setup option to select game speed (from very slow to very fast) * improved handling of title text messages (initial and for level set) 2007-02-03 * added new options "auto-wrap" and "centered" for DC2 style envelopes 2007-01-31 * fixed displaying and typing of player name when it is centered * added special characters to be allowed for player name (not only A-Z) 2007-01-25 * fixed blit in ScrollLevel() to same bitmap to not overlap anymore (newer versions of the SDL library seem to not like this anymore) 2007-01-23 * added code for configuration directives for control of game panel 2007-01-21 * fixed small cosmetical bug with underlining property tabs in editor 2007-01-20 * fixed small drawing bug in X11FadeRectangle * added new elements for newly supported Diamond Caves II levels: - EM/DC style exits that disappear after passing - white key and gate (one white key needed for each white gate) - fake gate (there is no key to open/pass this kind of gate!) - extended magic wall which also handles pearls and crystals - fast quicksand 2007-01-14 * changed maximum value for endless loop detection to a higher value (some levels really used very deep recursion without being endless) 2007-01-13 * added new elements for newly supported Diamond Caves II levels: - growing steel walls - snappable land mine 2007-01-08 * added new elements for newly supported Diamond Caves II levels: - steel text elements 2007-01-06 * added level file loader for native Diamond Caves II levels 2007-01-05 * version number set to 3.2.4 2007-01-05 * version 3.2.3 released 2007-01-04 * fixed malloc/free bug when updating EMC artwork entries in level list * added workaround (warning and request to quit the current game) when changing elements cause endless recursion loop (which would otherwise freeze the game, causing a crash-like program exit on some systems) 2006-12-16 * fixed nasty string overflow bug when entering too long envelope text 2006-12-05 * added feedback sounds for menu navigation "menu.item.activating" and "menu.item.selecting" (for highlighting and executing menu entries) 2006-12-03 * improved "no scrolling when relocating" to also consider scroll delay (meaning that the player is not automatically centered in this case; this makes it possible to "invisibly" relocate the player to a region of the level playfield which looks the same as the old level region) * fixed bug with not recognizing "main.input.name.align" when active 2006-12-02 * fixed bug with displaying masked borders over title screens when screen fading is disabled 2006-11-25 * fixed infinite loop / crash bug when killing the player while having a CE with the setting "kill player X when explosion of " * added special editor graphic for "char_space" to distinguish it from "empty_space" when editing a level (in-game graphics still the same) 2006-11-21 * fixed nasty bug with initialization only done for the first player 2006-11-19 * small change to handle loading empty element/content list micro chunks 2006-11-03 * uploaded pre-release (test) version 3.2.3-0 binary and source code 2006-11-01 * some optimizations on startup speed by reducing initial text output 2006-10-30 * added caching of custom artwork information for faster startup times 2006-10-29 * fixed graphical bug when using fewer menu entries on level selection screen than usual (with "menu.list_size.LEVELS" directive) * fixed crash bug (Windows/SDL only) caused by BlitBitmap blitting from the backbuffer to the backbuffer by error (with identical rectangle) 2006-10-28 * fixed bug when displaying titlescreen with size less than element tile * fixed bug that caused elements with "change when digging " event to change for _every_ digged element, not only those specified in * fixed bug that caused impact style collision when dropping element one tile over the player that can both fall down and smash players * fixed bug that caused impact style collision when element changed to falling/smashing element over the player immediately after movement 2006-10-24 * fixed bug that allowed making engine snapshots from the level editor 2006-10-22 * fixed bugs with player name and current level positions on main screen 2006-10-20 * added configuration directives for control of title screens: - "title.fade_delay" for fading time - "title.post_delay" for pause between screens (when not crossfading) - "title.auto_delay" to automatically continue after some time these settings can each be overridden by specifying them with titles: - "titlescreen_initial_{1-5}.{fade_delay,post_delay,auto_delay}" - "titlescreen_{1-5}.{fade_delay,post_delay,auto_delay}" fading mode can also be specified: - "titlescreen_initial_{1-5}.anim_mode: {fade,crossfade} - "titlescreen_{1-5}.anim_mode: {fade,crossfade} default is using normal fading for menues and initial title screens, while using cross-fading for level set title screens * fixed bug with background not drawn in Hall of Fame after game was won 2006-10-18 * added configuration directives for the remaining main menu items 2006-10-17 * added additional configuration directives for info screen draw offset: menu.draw_{x,y}offset.INFO[{ELEMENTS,MUSIC,CREDITS,PROGRAM,LEVELSET}] * added additional configuration directives for preview info text * limited mouse wheel sensitive screen area to scrollable screen area 2006-10-16 * added highlighted menu text entries to menu navigation when selected 2006-10-14 * fixed bug that prevented player from correctly being created in the top left corner by a custom element change in a level without player * fixed bug that prevented player from being killed when indestructible, non-walkable element is placed on player position by extended change * added configurable menu button, text and input positions to main menu 2006-10-13 * added page fading effects for remaining info sub-screens * fixed small bug that caused some delays when answering door request 2006-10-12 * added directives "border.draw_masked.*" for menu/playfield area and door areas to display overlapping/masked borders from "global.border" 2006-10-09 * fixed bug with CE with move speed "not moving" not being animated * when changing player artwork by CE action, reset animation frame 2006-10-03 * fixed bug with not unmapping main menu screen gadgets on other screens * fixed bug with un-pausing a paused game by releasing still pressed key * fixed bug with not redrawing screen when toggling to/from fullscreen mode while fast reloading tape (without redrawing playfield contents) * fixed bug with quick-saving tape snapshot despite answering with "no" 2006-08-30 * version number set to 3.2.3 2006-08-29 * version 3.2.2 released 2006-08-29 * fixed bug with redrawing screen in fullscreen mode after quick tape reloading when using the EMC game engine * changed token names from "last_ce_[1-8]" to "prev_ce_[1-8]" 2006-08-28 * fixed bug in GameWon() when level contains no exit (like in Sokoban) 2006-08-23 * added engine snapshot functionality for instant tape reloading (this only works for the last tape saved using "quick save", and does not work across program restarts, because it completely works in memory) 2006-08-21 * version number set to 3.2.2 2006-08-20 * version 3.2.1 released 2006-08-20 * fixed nasty bugs with handling error message file on Mac OS X systems 2006-08-19 * general code cleanup (removing many annoying "#if 0" blocks etc.) 2006-08-18 * fixed bug that caused broken tapes when manually appending to tapes using the "pause before death" functionality, followed by recording * added setup option to disable fading of screens for faster testing 2006-08-16 * code cleanup of new fading functions 2006-08-15 * changed behaviour after solved game -- do not immediately stop engine * added some more smooth screen fadings (game start, hall of fame etc.) 2006-08-14 * fixed bug with displaying pushed CE with value/score/delay anim_mode 2006-08-12 * added configurable level preview position, tile size and dimensions * added configurable game panel value positions (gems, time, score etc.) 2006-08-10 * fixed small bug with time displayed incorrectly when collecting CEs 2006-08-07 * fixed bug with bumpy scrolling with EM engine in double player mode 2006-08-05 * added compatibility code to fix "Snake Bite" style levels that were broken due to a bugfix regarding EL_SOKOBAN_FIELD_PLAYER in 3.2.0 2006-08-04 * fixed bug with scrollbars inside editor when using the Windows mouse enhancement tool "True X-Mouse" (which injects key events to the event queue to insert selected stuff into the Windows clipboard, which gets confused with the "Insert" key for jumping to the last editor cascade block in the element list) * added Rocks'n'Diamonds icon for use as window icon to SDL version * added key shortcut "Alt + Enter" to toggle fullscreen mode at any time 2006-08-01 * added selection of preferred fullscreen mode to setup / graphics menu (useful if default mode 800 x 600 does not match screen aspect ratio) 2006-07-30 * improved down-scaling of images for better editor and preview graphics * changed user data directory for Mac OS X from Unix style to new place 2006-07-26 * improved level number selection in main menu and player selection in setup menu (input devices section) by using standard button gadgets * added support for mouse scroll wheel (caused buggy behaviour before) * added support for scrolling horizontal scrollbars with mouse wheel by holding "Shift" key pressed while scrolling the wheel * added support for single step mouse wheel scrolling by holding "Alt" key pressed while scrolling the wheel (can be combined with "Shift") * changed output file "stderr.txt" on Windows platform now always to be created in the R'n'D sub-directory of the personal documents directory * added Windows message box to direct to "stderr.txt" after error aborts 2006-07-25 * improved general scrollbar handling (when jump-scrolling scrollbars) 2006-07-23 * changed scrollbars to always show last line as first after scrolling (that means jumping n - 1 screen lines instead of n screen lines) 2006-07-22 * fixed level versions of EMC level loader (from V4 to V1, V2 and V3) * fixed level time for EMC levels for V2 engine (V2 and V5 levels) * fixed special handling of vertically stacked acid becoming fake acid 2006-07-16 * fixed bug (very special case) with CE_SCORE_GETS_ZERO, which can affect multiple instances of the same CE, although this kind of change condition usually only affects one single custom element 2006-07-16 * version number set to 3.2.1 2006-07-16 * version 3.2.0 released 2006-06-23 * reorganized level editor element list a bit to match engines better 2006-06-21 * fixed newly introduced bug with wrongly initializing clipboard element 2006-06-19 * fixed bug with displaying visible/invisible level border in editor 2006-06-14 * reorganized some elements in the level editor element list 2006-06-06 * fixed bug with displaying any player as "yellow" when moving into acid * fixed bug with displaying running player when player stopped at border 2006-06-03 * fixed bug with player exploding when moving into acid * fixed bug with level settings being reset in editor and when playing (some compatibility settings being set not only after level loading) * fixed crash bug when number of custom graphic frames was set to zero * fixed bug with teleporting player on walkable tile not working anymore * added partial compatibility support for pre-release-only "CONF" chunk (to make Alan Bond's "color cycle" demo work again :-) ) 2006-05-30 * fixed some bugs when displaying title screens from info screen menu * fixed bug which caused EMC doors #5 to #8 to be passable without keys 2006-05-20 * changed file major version to 3 to reflect level file format changes * uploaded pre-release (test) version 3.2.0-8 binary and source code 2006-05-19 * added new chunk "NAME" to level file format for level name settings * added new chunk "NOTE" to level file format for envelope settings * changed name of chunk "CONF" to "ELEM" (for normal element settings) * updated magic(5) file to recognize changed and new level file chunks * removed change events "change when CE value/score changes" as unneeded 2006-05-17 * changed gravity (which only affects the player) from level property to player property (only makes a difference in multi-player levels) * added change events "change when CE value/score changes" * added change events "change when CE value/score changes of " 2006-05-16 * added new chunk "INFO" to level file format for global level settings * added all element settings from "HEAD" chunk to "CONF" chunk * added all global level settings from "HEAD" chunk to "INFO" chunk 2006-05-09 * changed level file format by adding two new chunks "CUSX" (for custom elements, replacing the previous "CUS4" chunk) and "GRPX" (for group elements, replacing the previous "GRP1" chunk); these new IFF style chunks use the new and flexible "micro chunks inside chunks" technique already used with the new "CONF" chunk (for normal element properties) which makes it possible to easily extend the existing level format (instead of using fixed-length chunks like before, which are either too big due to reserved bytes for future use, or too small when those reserved bytes have all been used and even more data should be stored, requiring the replacement by new and larger chunks just like it went with "CUS1" to "CUS4"); this whole problem now does not exist anymore 2006-05-06 * added credits pages to the "credits" section that were really missing * added some missing element descriptions to the level editor * added down position of switchgate switch to the level editor and allowed the use of both switch positions at the same time * changed use of "Insert" and "Delete" keys to navigate element list in level editor to start of previous or next cascading block of elements 2006-05-05 * added the possibility to view the title screen to the info screen menu * fixed some minor bugs with viewing title screens 2006-05-02 * fixed bug with title (cross)fading in/out when using fullscreen mode 2006-04-30 * fixed bug that forced re-defining of menu settings in local graphics config file which are already defined in existing base config file * fixed small bug that caused door sounds playing when music is enabled 2006-04-29 * added the possibility to define up to five title screens for each level set that are displayed after loading using (cross)fading in/out (this was added to display the various start images of the EMC sets) 2006-04-28 * added "CE score gets zero [of]" to custom element trigger conditions * added setup option to display element token name in level editor 2006-04-19 * added compatibility code for Juergen Bonhagen's menu artwork settings 2006-04-15 * fixed bug with displaying wrong animation frame 0 after CE changes * fixed bug with creating invisible elements when light switch is on 2006-04-06 * added selection between ECS and AGA graphics for EMC levels to setup 2006-04-04 * adjusted font handling for various narrow EMC style fonts 2006-04-03 * changed EM engine behaviour back to re-allow initial rolling springs 2006-04-02 * fixed handling of over-large selectboxes (less error-prone now) * fixed bug when creating GE with walkable element under the player 2006-04-01 * added use of "Insert" and "Delete" keys to navigate element list in level editor to start of custom elements or start of group elements * added virtual elements to access CE value and CE score of elements: - "CE value of triggering element" - "CE score of triggering element" - "CE value of current element" - "CE score of current element" 2006-03-30 * fixed "grass" to "sand" in older EM levels (up to file version V4) 2006-03-29 * changed behaviour of network games with internal errors (because of different client frame counters) from immediately terminating R'n'D to displaying an error message requester and stopping only the game (also to prevent impression of crashes under non command-line runs) * fixed playing network games with the EMC engine (did not work before) * fixed bug with not scrolling the screen in multi-player mode with the focus on player 1 when all players are moving in different directions * fixed bug with keeping pointer to gadget even after its deallocation * fixed bug with allowing "focus on all players" in network games * fixed bug with player focus when playing tapes from network games 2006-03-22 * uploaded pre-release (test) version 3.2.0-7 binary and source code 2006-03-19 * code cleanup for game action control for R'n'D and EMC game engine 2006-03-18 * fixed bug in multi-player movement with focus on both players * added option to control only the focussed player with all input 2006-03-14 * added player focus switching to level tape recording and re-playing 2006-03-13 * fixed some bugs in player focus switching in EMC and RND game engine 2006-03-11 * added special Supaplex animations for Murphy digging and snapping * added special Supaplex animations for Murphy being bored and sleeping 2006-03-10 * added four new yam yams with explicit start direction for EMC engine * fixed bug in src/libgame/text.c with printing text outside the window 2006-03-09 * fixed small bug in EMC level loader (copyright sign in EM II levels) 2006-03-08 * added delayed ignition of EM style dynamite when used in R'n'D engine * added limited movement range to EMC engine when focus on all players 2006-03-06 * fixed bug with missing (zero) score values for native Supaplex levels 2006-03-05 * added "continuous snapping" (snapping many elements while holding the snap key pressed, without releasing the snap key after each element) as a new player setting for more compatibility with the classic games 2006-03-04 * finished scrolling for "focus on all players" in EMC graphics engine 2006-02-28 * level sets with "levels: 0" are ignored for levels, but not artwork * fixed bug when scanning empty level group directories (endless loop) 2006-02-26 * fixed bug with explosion graphic for player using "Murphy" graphic * fixed bug with explosion graphic if player leaves explosion in time * changed some descriptive text in setup menu to use medium-width font * added key shortcut settings for switching player focus to setup menu 2006-02-25 * fixed bug with random value initialization when recording tapes * fixed bug with playing single player tapes when team mode activated 2006-02-22 * fixed little bug when trying to switch to player that does not exist 2006-02-19 * added player switching (visual and quick) to R'n'D and EM game engine * added setup option to select visual or quick in-game player switching 2006-02-16 * added use of "Home" and "End" keys to handle element list in editor 2006-02-15 * fixed bug with adding score when playing tape with EMC game engine * added steel wall border for levels using EMC engine without border * finally fixed delayed scrolling in EMC engine also for small levels 2006-02-12 * fixed potential crash bug in WarnBuggyBase() (missing boundary check) 2006-02-11 * fixed bug with CE change order in TestIfElementTouchesCustomElement() * fixed bug when displaying info element without action, but direction 2006-02-09 * fixed minor graphical problems with springs smashing and slurping (when using R'n'D style graphics instead of EMC style graphics) 2006-02-07 * added scroll delay (as configured in setup) to EMC graphics engine 2006-02-06 * improved screen redraw for EMC graphics engine (faster and smoother) * when not scrolling, do not redraw the whole playfield if not needed 2006-02-03 * added multi-player mode for EMC game engine (with up to four players) 2006-01-28 * added android (can clone elements) from EMC engine to R'n'D engine 2006-01-14 * added spring bumper (reflects spring) from EMC engine to R'n'D engine 2006-01-11 * added selectbox for initial player speed to player settings in editor 2006-01-11 * version 3.1.2 created that is basically version 3.1.1, but with a major bug fixed that prevented editing your own private levels * version 3.1.2 released 2006-01-09 * added magic ball (creates elements) from EMC engine to R'n'D engine 2006-01-07 * uploaded fixed pre-release version 3.2.0-6 binary and source code 2006-01-07 * fixed bug when using "CE can leave behind " * added new change condition "(after/when) creation of " * added new change condition "(after/when) digging " * fixed bug accessing invalid gadget that caused crashes under Windows * deactivated new possibility for multiple CE changes per frame 2006-01-04 * uploaded pre-release (test) version 3.2.0-6 binary and source code 2006-01-02 * added animation types "ce_value" and "ce_score" to graphicsinfo.conf * fixed bug with not keeping CE value for moving CEs with only action * changed CE action selectboxes in editor to be only reset when needed 2006-01-01 * added option "use artwork from element" for custom player artwork * added option "use explosion from element" for player explosions 2005-12-30 * added cascaded element lists in the level editor * added persistence for cascaded element lists by "editorcascade.conf" * added dynamic element list with all elements used in current level * added possibility for multiple CE changes per frame (experimental) 2005-12-28 * uploaded pre-release (test) version 3.2.0-5 binary and source code 2005-12-27 * changed "score for each 10 seconds/steps left" to "1 second/step" * added own score for collecting "extra time" instead of sharing it * added change events "switched by player" and "player switches " * added change events "snapped by player" and "player snaps " * added "set player artwork: " to CE action options * added change event "move of " 2005-12-22 * added "set player shield: off / normal / deadly" to CE action options * added new player option "use level start element" in level editor to set the correct focus at level start to elements from which the player is created later (this did not work before for cascaded CE changes resulting in creation of the player; it is now also possible to create the player from a yam yam which is smashed at level start) 2005-12-20 * added "set player speed: frozen (not moving)" to CE action options * added "move player: l/r/u/d/trigger/-trigger" to CE action options 2005-12-17 * added new player option "block snap field" (enabled by default) to make it possible to show a snapping animation like in Emerald Mine 2005-12-16 * added dynamic selectboxes to custom element action settings in editor * added "CE value" counter for custom elements (instead of "CE count") * added option to use the last "CE value" after custom element change * added option to use the "CE value" of other elements in CE actions * fixed odd behaviour when pressing time orb in levels w/o time limit * added checkbox "use time orb bug" for older levels that use this bug 2005-12-15 * added missing configuration settings for the following elements: - EL_TIMEGATE_SWITCH (time of open time gate) - EL_LIGHT_SWITCH_ACTIVE (time of light switched on) - EL_SHIELD_NORMAL (time of shield duration) - EL_SHIELD_DEADLY (time of shield duration) - EL_EXTRA_TIME (time added to level time) - EL_TIME_ORB_FULL (time added to level time) 2005-12-14 * added "wind direction" as a movement pattern for custom elements * added initial wind direction for balloon / custom elements to editor * added functionality for EL_BALLOON_SWITCH_NONE to R'n'D game engine 2005-12-13 * added parameters for "game of life" and "biomaze" elements to editor 2005-12-12 * added level file chunk "CONF" for generic level and element settings 2005-12-11 * uploaded pre-release (test) version 3.2.0-4 binary and source code 2005-12-11 * skip empty level sets (with "levels: 0"; may be artwork base sets) * added sound action ".page[1]" to ".page[32]" for each CE change page 2005-12-10 * added image config suffix ".clone_from" to copy whole image settings * fixed bug with invalid ("undefined") CE settings in old level files 2005-12-05 * fixed graphical bug with smashing elements falling faster than player 2005-12-03 * fixed major bug which prevented private levels from being edited * fixed bug with precedence of general and special font definitions 2005-12-02 * fixed graphical bug with player animation when player moves slowly 2005-11-29 * uploaded pre-release (test) version 3.2.0-3 binary and source code 2005-11-28 * fixed bug which prevented "global.num_toons: 0" from working 2005-11-27 * major code cleanup (removed all these annoying "#if 0" blocks) 2005-11-26 * added custom element actions for CE change page in level editor 2005-11-19 * fixed music initialization bug in init.c (thanks to David Binderman) * fixed mouse wheel "button" bug in editor (thanks to Tomi Belan) (this bug must probably be fixed at other places, too) 2005-10-16 * fixed buggy '#include "SDL.h"' statements in src/libgame/sdl.h (should be '#include ' instead) 2005-08-20 * fixed bug which prevented "walkable from no direction" from working (due to compatibility code overwriting this setting after loading) 2005-08-15 * fixed bug on Mac OS X (use of reserved name "Random") in EM engine 2005-08-07 * version number temporarily set to 3.1.1 (intermediate bugfix release) * version 3.1.1 released 2005-08-07 * changed some va_arg() arguments from 'long' to 'int', fixing problems on 64-bit architecture systems with LP64 data model 2005-08-06 * fixed bug with bombs not exploding when hitting the last level line (introduced after the release of 3.1.0) 2005-08-06 * added support for dumping small-sized level sketches from editor 2005-07-24 * added recognition of "trigger element" for "change digged element to" (this is not really what the "trigger element" was made for, but its use may seem obvious for leaving back digged elements unchanged) 2005-07-23 * fixed multiple warnings about failed joystick device initialization 2005-06-27 * fixed bug with dynamite dropped on top of just dropped custom element (collect dynamite, collect CE, drop CE => dynamite was also dropped); dynamite can still be dropped, but drop key must be released before 2005-06-27 * fixed bug with wrong start directory when started from file browser (due to this bug, R'n'D could not be started from KDE's Konqueror) 2005-06-26 * fixed bug causing "change when impact" on player not working * fixed wrong priority of "hitting something" over "hitting " * fixed wrong priority of "hit by something" over "hit by " 2005-06-14 * fixed graphical bug which caused the player (being Murphy) to show collecting animations although the element was collected by penguin 2005-06-08 * fixed two bugs causing wrong door background graphics in system.c (in functions "SetBackgroundBitmap()" and "DrawingOnBackground()") 2005-06-06 * fixed graphic bug with exploding bomb and R'n'D graphics in EM engine * added "no direction" to "walkable/passable from" selectbox options 2005-06-05 * enhanced tape autoplay to accept "autoplay [ ...]" format * in tape autoplay, not only report broken, but also missing tapes 2005-05-31 * uploaded pre-release (test) version 3.2.0-2 binary and source code 2005-05-27 * fixed small bug with "linear" animation not working for active lamp 2005-05-24 * fixed bug with moving up despite gravity due to "block last field" * fixed small bug with wrong draw offset when typing name in main menu * when reading user names from "passwd", ignore data after first comma * when creating new "levelinfo.conf", only write some selected entries 2005-04-28 * fixed displaying "imported from/by" on preview with empty string * fixed ignoring draw offset for fonts used for level preview texts 2005-04-24 * fixed a delay problem with SDL and too many mouse motion events * added setup option "skip levels" and level skipping functionality 2005-03-19 * added move speed "not moving" for non-moving CEs, but with direction 2005-03-06 * fixed mapping of obsolete element token names in "editorsetup.conf" * fixed bug with sound "acid.splashing" treated as a loop sound * fixed some little sound bugs in native EM engine 2005-02-20 * fixed small bug when dragging scrollbars to end positions 2005-02-14 * added editor element descriptions written by Aaron Davidson 2005-02-02 * improved fallback handling when configured artwork is not available (now using default artwork instead of exiting when files not found) 2005-02-01 * fixed bug on level selection screen when dragging scrollbar 2005-01-19 * fixed bug which caused broken tapes when appending to EM engine tapes 2005-01-17 * uploaded pre-release (test) version 3.2.0-1 binary and source code 2005-01-17 * added code to replace changed artwork config tokens with other tokens (needed for backwards compatibility, so that older tokens still work) 2005-01-16 * added native R'n'D graphics for some new EMC elements in EM engine 2005-01-15 * fixed some bugs in the EM engine integration code * changed EM engine code to allow diagonal movement * changed EM engine code to allow use of separate snap and drop keys 2005-01-03 * fixed some redraw bugs when using EM engine 2005-01-02 * fixed bug with not converting RND levels which are set to use native engine to native level structure when loading 2005-01-01 * uploaded pre-release (test) version 3.2.0-0 binary and source code 2005-01-01 * version number set to 3.2.0 2004-12-30 * level data now reset to defaults after attempt to load invalid file 2004-11-13 * added use of "editorsetup.conf" for different level sets 2004-10-26 * added auto-detection for various types of Emerald Mine level files 2004-10-17 * fixed bug with scrollbars getting too small when list is very large 2004-10-09 * fixed bug with 3+3 (cross) sized explosion not making explosion sound 2004-10-04 * added most level editor configuration gadgets for new EMC elements 2004-10-01 * added more element and graphic definitions for new EMC elements 2004-09-27 * modified native EM engine to use integrated R'n'D sound system 2004-09-21 * added SDL support to graphics functions in native EM engine (by always using generic libgame interface functions) 2004-09-20 * fixed bug in frame synchronization in native EM engine 2004-09-18 * added code to convert levels between R'n'D and native EM engine 2004-08-23 * new Emerald Mine engine can now play levels selected in main menu 2004-08-16 * fixed big memory leak in function "CreateBitmapWithSmallBitmaps()" (which creates scaled down graphics for level editor and preview); there's still a memory leak somewhere in the artwork handling code * added "scale image up" functionality to X11 version of zoom function 2004-08-14 * first attempts to integrate new, native Emerald Mine Club engine 2004-08-07 * fixed bug in gadget code which caused reset of CEs in level editor (example: pressing 'b' [grab brush] on CE config page erased values) (solution: check if gadgets in ClickOnGadget() are really mapped) * improved level change detection in editor (settings now also checked) * fixed bug with "can move into acid" and "don't collide with" state 2004-07-29 * fixed maze runner style CEs to use the configured move delay value 2004-06-27 * added Aaron Davidson's tutorial level set to the "Tutorials" section 2004-06-20 * fixed engine change that broke 3.0.8 levels like "Walpurgis Gardens" * fixed the above fix because it broke level set "machine" (*sigh*) * fixed random element placement in level editor to work as expected * fixed undefined graphic of runtime element "EL_AMOEBA_TO_DIAMOND" 2004-06-15 * re-recorded tape for BD2K3, level 010 (broken due to bugfix) 2004-06-13 * fixed bug (missing array boundary check) which caused broken tapes * fixed bug (when loading level template) which caused broken levels * fixed bug with new block last field code when using non-yellow player 2004-06-12 * fixed bug when pressing "stop, pause, stop, play" on tape recorder * internal change of how the player blocks the last field when moving * fixed blocking delay of last field for EM and SP style block delay * fixed bug where the player had to wait for the usual move delay after unsuccessfully trying to move, when he directly could move after that * the last two changes should make original Supaplex level 93 solvable * improved use of random number generator to make it less predictable * fixed behaviour of slippery SP elements to let slip left, then right 2004-06-11 * fixed bug with wrong door state after trying to quickload empty tape * fixed waste of static memory usage of the binary, making it smaller * fixed very little graphical bug in Supaplex explosion 2004-06-07 * version number set to 3.1.1 2004-06-07 * version 3.1.0 released 2004-06-07 * fixed bug with crash when writing user levelinfo.conf the first time 2004-06-06 * added option "convert LEVELDIR [NR]" to command line batch commands * re-converted Supaplex levels to apply latest engine fixes * changed "use graphic/sound of element" to "use graphic of element" due to compatibility problems with some levels ("bug machine" etc.) 2004-05-23 * fixed bug with CE change replacing player with same or other player 2004-05-16 * fixed bug with opaque font in envelope with background graphic when background graphic is not transparent itself 2004-05-12 * added "gravity on" and "gravity off" ports for Supaplex compatibility * corrected original Supaplex level loading code to use these new ports * also corrected Supaplex loader to auto-count infotrons if set to zero 2004-05-10 * fixed bug with missing initialization of "modified" flag for GEs 2004-05-09 * fixed bug that caused endless recursion loop when relocating player * fixed tape recorder bug in "step mode" when using "pause before end" * fixed tape recorder bug when changing from "warp forward" mode 2004-05-08 * fixed bug with "when touching" for pushed elements at last position 2004-05-05 * fixed bug that caused two activated toolbox buttons in level editor * fixed bug with exploding dynabomb under player due to other explosion 2004-05-02 * fixed bug with creating walkable custom element under player (again) * fixed bug with not copying explosion type when copying CEs in editor * fixed graphical bug when drawing player in setup menu (input devices) * fixed graphical bug when the player is pushing an accessible element * fixed bug with classic switchable elements triggering CE changes * fixed bug with entering/leaving walkable element in RelocatePlayer() * fixed crash bug when CE leaves behind the trigger player element 2004-04-30 * fixed bug with broken tubes after placing/exploding dynamite in them * fixed bug with exploding dynamite under player due to other explosion * fixed bug with not resetting push delay under certain circumstances 2004-04-27 * added option "handicap" for "levelinfo.conf" (thanks to Niko Böhm) * added network multiplayer code for Windows (thanks to Niko Böhm) 2004-04-25 * added option "reachable despite gravity" for gravity movement * changed gravity movement of most classic walkable and passable elements back to "not reachable" (for compatibility reasons) 2004-04-24 * fixed (removed) "indestructible" / "can explode" dependency in editor * fixed (removed) "accessible inside" / "protected" dependency * fixed (removed) "step mode" / "shield time" dependency 2004-04-23 * fixed dynabombs exploding now into anything diggable * fixed Supaplex style gravity movement into buggy base now impossible * added pressing key "space" as valid action to select menu options 2004-04-20 * added "replace when walkable" to relocate player to walkable element * added "enter"/"leave" event for elements affected by relocation * fixed "direct"/"indirect" change order also for "when change" event * fixed graphical bug when pushing things from elements walkable inside 2004-04-18 * fixed graphic bug when player is snapping while moving in old levels * fixed bug when a moving custom element leaves a player element behind * fixed bug with mole not disappearing when moving into acid pool * fixed bug with incomplete path setting when using "--basepath" option * moving CE can now leave walkable elements behind under the player * when relocating, player can be set on walkable element now * fixed another gravity movement bug 2004-04-12 * uploaded pre-release (test) version 3.1.0-2 binary and source code 2004-04-10 * added "collectible" and "removable" to extended replacement types (where "removable" replaces "diggable" and "collectible" elements) * added "collectible & throwable" (to throw element to the next field) * fixed bug with CEs digging elements that are just about to explode * changed mouse cursor now always being visible when game is paused 2004-04-09 * added possibility to push/press accessible elements from a side that is not accessible * fixed bug with not setting actual date when appending to tape 2004-04-07 * fixed bug with incorrectly initialized custom element editor graphics 2004-04-04 * corrected set "Contributions_1995-2000/rnd_kjell_kristiansson": - number of levels corrected from 18 to 17 in "levelinfo.conf" 2004-03-31 * fixed bug with destroyed robot wheel still attracting robots forever * fixed bug with time gate switch deactivating after robot wheel time (while the time gate itself is not affected by this misbehaviour) * changed behaviour of BD style amoeba to always get blocked by player (before it was different when there were non-BD elements in level) * fixed bug with player destroying indestructable elements with shield 2004-03-26 * added option to make growing elements grow into anything diggable (for the various amoeba types, biomaze and "game of life") 2004-03-24 * fixed bug with movable elements not moving after left behind by CEs * changed gravity movement to anything diggable, not only sand/base * optionally allowing passing to walkable element, not only empty space * added option "can pass to walkable element" for players * finally fixed gravity movement (hopefully) 2004-03-23 * fixed bug with movable elements not moving anymore after falling down 2004-03-22 * fixed another bug with custom elements digging and leaving elements * fixed bug with "along left/right side" and automatic start direction * trigger elements now also displayed when "more custom" deactivated * fixed bug with clipboard element initialized when loading new level * added option "drop delay" to set delay before dropping next element 2004-03-21 * uploaded pre-release (test) version 3.1.0-1 binary and source code 2004-03-20 * added copy and paste functions for custom change pages * enhanced graphical display and functionality of tape recorder * fixed bug with custom elements digging and leaving elements 2004-03-19 * added move speed faster than "very fast" for custom elements * fixed bug with 3+3 style explosions and missing border content * fixed little bug when copying custom elements in the editor * enhanced custom element changes by more side trigger actions 2004-03-16 * added option "no scrolling when relocating" for instant teleporting * uploaded pre-release (test) version 3.1.0-0 binary and source code 2004-03-15 * added trigger element and trigger player to use as target elements * added copy and paste functions for custom and group elements 2004-03-14 * fixed graphical bug when displaying explosion animations * fixed bug when appending to tapes, resulting in broken tapes * re-recorded a few tapes broken by fixing gravity checking bug 2004-03-13 * "can move into acid" property now for all elements independently * "can fall into acid" property for player stored in same bitfield now * added option for deadliness of Supaplex 'sniksnak' and 'electron' * version number set to 3.1.0 (finally!) 2004-03-09 * changed tape recording to only record input, not programmed actions 2004-03-08 * fixed totally broken (every 8th frame skipped) step-by-step recording * fixed bug with requester not displayed when quick-loading interrupted * added option "can fall into acid (with gravity)" for players * fixed bug with player not falling when snapping down with gravity 2004-03-07 * fixed bug which messed up key config when using keypad number keys 2004-03-03 * fixed bug which allowed moving upwards even when gravity was active * fixed bug with missing error handling when dumping levels or tapes 2004-03-02 * added different colored editor graphics for Supaplex gravity tubes 2004-03-01 * fixed bug that allowed solvable tapes for unsolvable levels 2004-02-28 * use unlimited number of droppable elements when "count" set to zero * added option to use step limit instead of time limit for level 2004-02-27 * added player and change page as trigger for custom element change 2004-02-24 * fixed bug with exploding amoeba (explosion 3x3 instead of 1x1) 2004-02-22 * fixed bug with dark yamyam changing to acid when moving over acid * fixed handling of levels with more than 999 seconds level time (example: level 76 of "Denmine") 2004-02-21 * "spring push bug" reintroduced as configurable element property * fixed bug with missing properties for "mole" * fixed bug that showed up when fixing the above "mole" properties bug * added option "can move into acid" for all movable elements * fixed graphical bug for elements moving into acid * changed event handling to handle all pending events before going on 2004-02-17 * fixed bug which caused all CE change pages to be ignored which had the same change event, but used a different element side (reported by Simon Forsberg) * fixed bug which caused elements that can move and fall and that are transported by a conveyor belt to continue moving into that direction after leaving the conveyor belt, regardless of their own movement type; only elements which can not move are transported now (reported by Simon Forsberg) * fixed bug which could cause an array overflow in RelocatePlayer() (reported by Niko Böhm) * changed Emerald Mine style "passable / over" elements to "protected" (fixing unsolvable level 10 of "Bondmine 9" with bug beside gate) * added new option to select from which side a "walkable/passable" element can be entered 2004-02-16 * added explosion and ignition delay for elements that can explode 2004-02-05 * fixed bug which caused player not being protected against enemies when a CE was "walkable / inside" and was not "indestructible" * added "walkable/passable" fields to be "protected/unprotected" against enemies, even if not accessible "inside" but "over/under" 2004-02-04 * corrected move pattern to 32 bit and initial move direction to 8 bit 2004-02-03 * added second custom element base configuration page 2004-02-02 * added some special EMC mappings to Emerald Mine level loader (also covering previously unknown element in level 0 of "Bondmine 8") 2004-01-30 * added option to block last field when player is moving (for Supaplex) * adjusted push delay of Supaplex elements * removed delays for envelopes etc. when replaying with maximum speed * fixed bug when dropping element on a field that just changed to empty 2004-01-29 * fixed bug: infotrons can now smash yellow disks * fixed bug: when gravity active, port above player can now be entered * removed "one white dot" mouse pointer which irritated some people 2004-01-26 * added "choice type" for group element selection 2004-01-25 * fixed bug with initial invulnerability of non-yellow player 2004-01-23 * added level loader for loading native Supaplex packed levels (including multi-part levels like the "splvls99" levels) 2004-01-19 * fixed bug which allowed creating emeralds by escaping explosions 2004-01-18 * custom elements can change (limited) or leave (unlimited) elements * finally added multiple matches using group elements * added shortcut to dump brush (type ":DB" in editor) for use in forum 2004-01-17 * added new start movement type "previous" for continued CE movement * added new start movement type "random" for random CE movement start 2004-01-17 * added new element "sokoban_field_player" needed for Sokoban levels (thanks to Ed Booker for pointing this out!) 2004-01-15 * added elements that can be digged or left behind by custom elements 2004-01-12 * added group elements for multiple matches and random element creation 2004-01-11 * fixed some graphical errors displayed in old levels 2004-01-10 * fixed wrong double speed movement after passing closing gates 2004-01-03 * added level loader for loading native Emerald Mine levels 2004-01-02 * changes for "shooting" style CE movement 2004-01-01 * Happy New Year! ;-) 2003-12-27 * changed default snap/drop keys from left/right Shift to Control keys 2003-12-27 * fixed bug with dead player getting reanimated from custom element 2003-12-14 * fixed bug with wrong penguin graphics (when entering exit) 2003-12-14 * fixed bug with wrong "Murphy" graphics (when digging etc.) 2003-12-14 * version number set to 3.0.9 2003-12-14 * version 3.0.8 released 2003-12-13 * added function checked_free() 2003-12-13 * fixed bug with double nut cracking sound (by eliminating "default element action sound" assignment in init.c) 2003-12-10 * fixed crash when no music info files are available 2003-12-07 * fixed boring and sleeping sounds 2003-12-05 * added "maze runner" and "maze hunter" movement types * added extended collision conditions for custom elements 2003-12-03 * added warnings for undefined token values in artwork config files 2003-12-02 * added menu entry for level set information to the info screen 2003-12-02 * fixed bug with wrong default impact sound for colored emeralds 2003-11-30 * added several sub-screens for the info screen * menu text now also clickable (not only blue/red sphere left of it) 2003-11-25 * added configurable "bored" and "sleeping" animations for the player * added "awakening" sound for player when waking up after sleeping 2003-11-22 * added "copy" and "exchange" functions for custom elements to editor 2003-11-21 * added configurable element animations for info screen 2003-11-20 * added configurable music credits for info screen 2003-11-19 * finally fixed tape recording when player is created from CE change 2003-11-18 * added "editorsetup.conf" for editor element list configuration 2003-11-16 * added "musicinfo.conf" for menu and level music configuration 2003-11-14 * fixed a very nasty bug in dragon turning code in TurnRoundExt() (that only showed up on Linux, but not on Windows systems) 2003-11-13 * fixed turning movement of butterflies and fireflies (no frame reset) * enhanced sniksnak turning movement (two steps instead of only one) 2003-11-10 * version number set to 3.0.8 2003-11-10 * version 3.0.7 released 2003-11-09 * fixed reset of player animation frame when, for example, walking, digging or collecting share the same animation * fixed CE with "deadly when touching" exploding when touching amoeba 2003-11-08 * fixed tape recording when player is created from CE element change 2003-11-04 * introduced "turning..." action graphic for elements with move delay (non-CE: bug, spaceship, sniksnak, mole, pacman, yamyam) * added turning animations for bug, spaceship and sniksnak 2003-11-03 * prevent "extended" changed elements from delay change in same frame 2003-11-02 * fixed bug when pushing element that can move away to the side (like pushing falling elements, but now with moving elements) 2003-11-01 * finally fixed serious bug in code for delayed element pushing (again) 2003-10-19 * unavailable setup options now marked as "n/a" instead of "off" * new boolean directive "latest_engine" for "levelinfo.conf": when set to "true", levels are always played with the latest game engine, which is desired for levels that are imported from other games; all other levels are played with the engine version stored in level file (which is normally the engine version the level was created with) 2003-10-18 * fixed serious bug in code for delayed element pushing * fixed little bug in animation frame selection for pushed elements * speed-up of reading config file for verbose output 2003-10-08 * added configuration option for opening and closing Supaplex exit * added configuration option for moving up/down animation for Murphy * fixed incorrectly displayed animation for attacking dragon * fixed bug with not setting initial gravity for each new game * fixed bug with teleportation of player by custom element change * fixed bug with player not getting smashed by rock sometimes 2003-10-06 * version number set to 3.0.7 2003-10-06 * version 3.0.6 released 2003-10-05 * added support for MP3 music for SDL version through SMPEG library 2003-10-03 * fixed bug when initializing font graphic structure * fixed bug with animation mode "pingpong" when using only 1 frame * fixed bug with extended change target introduced in 3.0.5 * fixed bug where passing over moving element doubles player speed * fixed bug with elements continuing to move into push direction * fixed bug with duplicated player when dropping bomb with shield on * added "switching" event for custom elements ("pressing" only once) * fixed switching bug (resetting flag when not switching but not idle) 2003-09-29 * fixed element tokens for certain file elements with ".active" etc. 2003-09-29 * version number set to 3.0.6 2003-09-29 * version 3.0.5 released 2003-09-28 * now four envelope elements available * font, background, animation and sound for envelope now configurable * main menu doors opening/closing animation type now configurable 2003-09-27 * active/inactive sides configurable for custom element changes * new movement type "move when pushed" available for custom elements 2003-09-20 * fixed bug in multiple config pages loader code that caused crashes 2003-09-13 * enhanced (remaining low-resolution) Supaplex graphics 2003-09-13 * version number set to 3.0.5 2003-09-13 * version 3.0.4 released 2003-09-12 src/tools.c * fixed bug in custom definition of crumbled element graphics 2003-09-11 src/files.c * fixed bug in multiple config pages code that caused crashes 2003-09-08 * version number set to 3.0.4 2003-09-08 * version 3.0.3 released 2003-09-07 * added music to Supaplex classic level set 2003-09-07 src/libgame/misc.c * added support for loading various music formats through SDL_mixer 2003-09-06 (various source files) * fixed several nasty bugs that may have caused crashes on some systems * added envelope content which gets displayed when collecting envelope * added multiple change event pages for custom elements 2003-08-24 src/game.c * fixed problem with player animation when snapping and moving 2003-08-23 src/screens.c, src/cartoons.c, src/libgame/toons.c * fixed problem with flickering when drawing toon animations 2003-08-23 src/libgame/sdl.c * fixed problem with setting mouse cursor in SDL version in fullscreen 2003-08-23 src/game.c * fixed bug (missing array boundary check) which could crash the game 2003-08-23 * version number set to 3.0.3 2003-08-22 * version 3.0.2 released 2003-08-21 src/game.c * fixed bug with creating inaccessible elements at player position 2003-08-20 src/init.c * fixed bug with not finding current level artwork directory 2003-08-20 src/files.c * fixed bug with choosing wrong engine version when playing tapes * fixed bug with messing up custom element properties in 3.0.0 levels 2003-08-18 * version number set to 3.0.2 2003-08-18 * version 3.0.1 released 2003-08-17 (no source files affected) * changed all "classic" PCX image files with 16 colors or less to 256 color (8 bit) storage format, because the Allegro game library cannot handle PCX files with less than 256 colors (contributed graphics are not affected and might look wrong in the DOS version) 2003-08-16 src/init.c * fixed bug which (for example) crashed the level editor when defining "dynamite.EDITOR: [NONE]", because graphics may not be undefined (only set to default) -- invalid graphics now set to default graphic 2003-08-16 src/init.c * fixed graphical bug of player digging/collecting/snapping element when no corresponding graphic/animation is defined for this action, resulting in player being drawn as EL_EMPTY (which should only be done to elements being collected, but not to the player) 2003-08-16 src/game.c * fixed small graphical bug of player not totally moving into exit 2003-08-16 src/libgame/setup.c * fixed bug with wrong MS-DOS 8.3 filename conversion 2003-08-16 src/tools.c * fixed bug with invisible mouse cursor when pressing ESC while playing 2003-08-16 (various source files) * added another 128 custom elements (disabled in editor by default) 2003-08-16 src/editor.c * fixed NULL string bug causing Solaris to crash in sprintf() 2003-08-16 src/screen.c * fixed drawing over scrollbar on level selection with custom fonts 2003-08-15 src/game.c * cleanup of simple sounds / loop sounds / music settings 2003-08-08 (various source files) * added custom element property for dropping collected elements 2003-08-08 src/conf_gfx.c * fixed bug with missing graphic for active red disk bomb 2003-08-07 src/files.c, src/editor.c src/game.c, src/main.h * extended variable "level.gravity" to "level.initial_gravity" and "game.current_gravity" to prevent level setting from being changed by playing the level (keeping the runtime value after playing) * fixed graphics bug when digging element that has 'crumbled' graphic definition, but not 'diggable' graphic definition 2003-08-06 * version number set to 3.0.1 2003-08-05 * version 3.0.0 released 2003-08-05 * various bug fixes; among others: - fixed bug with pushing spring over empty space - fixed bug with leaving tube while placing dynamite - fixed bug with explosion of smashed penguins - allow Murphy player graphic in levels with non-Supaplex elements 2003-04-07 * various changes * I have forgotten to document changes for some time 2002-12-31 * pre-release version 2.2.0rc1 released 2002-08-25 * version number set to 2.1.2 2002-08-13 * version 2.1.1 released 2002-08-10 * version number set to 2.1.1 2002-08-05 * version 2.1.0 released 2002-05-19 * version number set to 2.1.0 2002-04-03 to 2002-05-19 (various source files) * graphics, sounds and music now fully configurable * bug fixed that prevented walking through tubes when gravity on 2002-04-02 src/events.c, src/editor.c * Make Escape key less aggressive when playing or when editing level. This can be configured as an option in the setup menu. (Default is "less aggressive" which means "ask user if something can be lost" when pressing the Escape key.) 2002-04-02 src/screen.c * Added "graphics setup" screen. 2002-04-01 src/screen.c * Changed "choose level" setup screen stuff to be more generic (to make it easier to add more "choose from generic tree" setup screens). 2002-04-01 src/config.c, src/timestamp.h * Added source files "src/config.[ch]" and "src/timestamp.h" (which automatically gets created by "src/Makefile" and contains an actual compile-time timestamp to identify development versions of the game). 2002-03-31 src/tape.c, src/events.c * Added quick game/tape save/load functions to tape stuff which can be invoked by a keyboard shortcut. Default: "F1" saves game/tape, "F2" loads previously recorded tape and directly goes into recording mode from the end of the tape (therefore appending to the tape). 2002-03-31 src/tape.c * Added "index mark" function to tape recorder. When playing or recording, "eject" button changes to "index" button. Setting index mark is not yet implemented, but pressing index button when playing allows very quick advancing to end of tape (when normal playing), very fast forward mode (when playing with normal fast forward) or very fast reaching of "pause before end of tape" (when playing with "pause before end" playing mode). 2002-03-30 src/cartoons.c * Moved some stuff from cartoons.c to the new "src/libgame/toons.c". 2002-03-29 src/screen.c * Changed setup screen stuff to be more generic (to make it easier to add more setup screens). 2002-03-23 src/main.c, src/main.h * Various changes due to the introduction of the new libgame files "setup.c" and "joystick.c". 2002-03-23 src/files.c * Generic parts of "src/files.c" (mainly setup and level directory stuff) moved to new libgame file "src/libgame/setup.c". 2002-03-23 src/joystick.c * File "src/joystick.c" moved to libgame source tree, with correspondig changes. 2002-03-22 src/screens.c * "HandleChooseLevel()": Another bug in level series navigation fixed. (Wrong level series information displayed when entering main group.) 2002-03-22 src/editor.c * Slight change to support new gadget event "GD_EVENT_INFO_LEAVING". 2002-03-22 src/editor.c * Changed behaviour of "Escape" key in level editor to be more intuitive: When in "Element Properties" or "Level Info" mode, return to "Drawing Mode" instead of leaving the level editor. 2002-03-21 src/game.c, src/editor.c, src/files.c * 2.0.1 introduced the corrected "Emerald Mine" style behaviour of gems (emeralds, diamonds, ...) slipping down from normal wall, steel wall and growing wall (as in E.M.C. style levels). Although the behaviour of contributed and private levels wasn't changed (due to the use of "level.game_version"; see previous entry), editing those levels will (of course) change the behaviour accordingly. This change seems a bit too hard after thinking about it, because the EM style behaviour is not the "expected" behaviour (gems would normally only slip down from "rounded" walls). Therefore this was now changed to an element property for gem style elements, with the default setting "off" (which means: no special EM style behaviour). To fix older converted levels, this flag is set to "on" for pre-2.0 levels that are neither contributed nor private levels. 2002-03-20 src/files.h * Corrected settings for "level.game_version" depending of level type. (Contributed and private levels always get played with game engine version they were created with, while converted levels always get played with the most recent version of the game engine, to let new corrections of the emulation behaviour take effect.) 2002-03-20 src/main.h * Added "#include ". This seems to be needed by "tape.c" for compiling the SDL version on some systems. Thanks to the several people who pointed this out. 2002-03-19 * Version number set to 2.0.2. 2002-03-19 * Version 2.0.1 released. 2002-03-18 src/screens.c * "HandleChooseLevel()": Small bug in level series navigation fixed. 2002-03-18 src/files.c [src/libgame/misc.c] * Moved some common functions from src/files.c to src/libgame/misc.c. 2002-03-18 src/files.c [src/libgame/misc.c] * Changed permissions for new directories and saved files (especially score files) according to suggestions of Debian users and mantainers. Thanks to Drew Parsons for the patch. 2002-03-17 src/files.c * Changed "{Load|Save}{Level|Tape}()" to IFF style file format: Replaced "cookie" header string ("ROCKSNDIAMONDS_...\n") with real IFF style header "RND1....XXXX" (where "XXXX" is "CAVE" for levels and "TAPE" for tapes). Old "cookie" style format is still supported for reading. New level and tape files are written in new format. * New IFF chunk "VERS" contains version numbers for file and game (where "game version" is the version of the program that wrote the file, and "file version" is a version number to distinguish files with different format, for example after adding new features). 2002-03-15 src/screen.c * "DrawHallOfFame()": "FadeSounds()" when entering the hall of fame. (Before, you heard a mixture of the in-game music and the hall-of-fame music.) 2002-03-14 src/events.c * Function "DumpTape()" (files.c) now available by pressing 't' from main menu (when in DEBUG mode). 2002-03-14 src/game.c * "GameWon()": When game was won playing a tape, now there is no delay raising the score and no corresponding sound is played. 2002-03-14 src/files.c * Changed "LoadTape()" for real chunk support and also adjusted "SaveTape()" accordingly. 2002-03-14 src/game.c, src/tape.c, src/files.c * Important changes to tape format: The old tape format stored all actions with a real effect with a corresponding delay between the stored actions. This had some major disadvantages (for example, push delays had to be ignored, pressing a button for some seconds mutated to several single button presses because of the non-action delays between two action frames etc.). The new tape format just stupidly records all device actions and replays them later. I really don't know why I haven't solved it that way before?! Old-style tapes (with tape file version less than 2.0) get converted to the new format on-the-fly when loading and can therefore still be played; only some minor parts of the old-style tape handling code was needed. (A perfect conversion is not possible, because there is information missing about the device actions between two action frames.) 2002-03-14 src/files.c * New function "DumpTape()" to dump the contents of the current tape in a human readable format. 2002-03-14 src/game.c * Small tape bug fixed: When automatically advancing to next level after a game was won, the tape from the previous level still was loaded as a tape for the new level. 2002-03-14 src/tape.c * Small graphical bug fixed: When pressing ""Record" or "Play" on tape, cartoons did not get completely removed because StopAnimation() was not called. 2002-03-13 src/files.c * Changed "LoadLevel()" and "SaveLevel()" to add new chunk "CNT2". Fixed bug of "CONT" and "BODY" (chunk size was set to 8-bit element size even when using 16-bit elements). Added new chunk "CNT2" for 16-bit amoeba content (previously written in 8-bit field in "HEAD" chunk even when content was 16-bit element). "CNT2" should now be able to store content for arbitrary elements (up to eight blocks of 3 x 3 element arrays). All "CNT2" elements will always be stored as 16-bit elements. "CONT" (with 8/16-bit elements) now obsolete. 2002-03-13 src/files.c * Changed "LoadLevel()" for real chunk support. 2002-03-12 src/game.c * Fixed problem (introduced after 2.0.0 release) with penguins not getting killed by enemies 2002-02-24 src/game.c, src/main.h * Added "player->is_moving"; now "player->last_move_dir" does not contain any information if the player is just moving at the moment or not. Before, "player->last_move_dir" was misused for this purpose for the robot stuff (robots don't kill players when they are moving). But setting "player->last_move_dir" to MV_NO_MOVING broke tapes when walking through pipes! ("IS_MOVING()" uses "MovPos[][]", but this fails when it is 0 in a continuous movement. This fact is ignored for friends and enemies, though.) rocksndiamonds-3.3.0.1+dfsg1/CREDITS0000644000175000017500000000415311375077122015656 0ustar dimkadimka Rocks'n'Diamonds contains a lot of inspiration, ideas, code and contributions by many people and projects, which are listed here in no particular order. If somebody should be added to this list of credits, please let me know! ------------------------------------------------------------------------------- Special thanks to Peter Liepa for creating "Boulder Dash" that started it all! Special thanks to Klaus Heinz and Volker Wertich for creating "Emerald Mine", which took this kind of game to a new level! Special thanks to Michael Stopp and Philip Jespersen for creating "Supaplex"! Special thanks to Hiroyuki Imabayashi for creating "Sokoban"! Special thanks to Alan Bond and Jürgen Bonhagen for the continuous creation of outstanding level sets! Thanks to Peter Elzner for ideas and inspiration by Diamond Caves. Thanks to Steffest for ideas and inspiration by DX-Boulderdash. Thanks to Guido Schulz for the initial MS-DOS port of the game. The native Emerald mine engine was derived from Emerald Mine for X11 which was developed by David Tritscher as a very compatible Emerald Mine clone. Thanks a lot for this contribution! The native Supaplex engine is based on MegaPlex by Frank Schindler, which is based on the Supaplex Speed Fix by Herman Perk, which is based on the original Supaplex game by Michael Stopp and Philip Jespersen. Thanks a lot for this contribution! Thanks to Karl Hörnell for some additional toon graphics taken from "Iceblox": The penguin, the mole, the pig and the dragon. Thanks to the composers of the included music modules: "mod.apoplexy" by bee hunter/jazz, "mod.chiptune" by 4-mat/anarchy and "mod.cream_of_the_earth" by romeoknight. Thanks to Christopher Clark for the hash functions. The random number generator was taken from the GNU C library. The networking code was derived from xtris. Thanks! Thanks to Francesco Carta for the comprehensive Rocks'n'Diamonds manual. Thanks to Niko Böhm for the Rocks'n'Diamonds documentation wiki. Thanks to Simon Forsberg for being the moderator of the R'n'D forum. And not to forget: Many thanks to all those who contributed levels to this game since 1995! rocksndiamonds-3.3.0.1+dfsg1/INSTALL0000644000175000017500000000704107224164664015674 0ustar dimkadimka Installation instructions for Rocks'n'Diamonds ============================================== Compilation ----------- If your system supports Linux/i386/ELF/glibc executables (Linux package) or if you run DOS/Windows (DOS package), you can directly use the included precompiled binary. If you use a different system, just recompile the game: If you use Linux with gcc or DOS or Windows 3.x with djgpp, just try 'make' which should work without problems. If you use SUN/Solaris with gcc and GNU make, try 'make solaris'. To build the game with SDL support (needed for fullscreen and MOD support), type "make sdl". You need at least SDL version 1.1.x and the additional SDL libraries SDL_image and SDL_mixer. To get a recent version of the SDL library, see http://www.libsdl.org. If the above doesn't work, edit the Makefile in the top level directory. If it doesn't work either, edit the Makefile in the 'src' subdirectory. If you had to modify any Makefile to compile it, please drop me a note about it to 'info@artsoft.org'. Thanks! Customization ------------- The following configuration options in the top level Makefile help you to customize the game to your system and your environment: CC Choose your favorite ANSI C compiler. Default is 'gcc'. PLATFORM Choose your platform, if auto detection fails. Auto detection should work for Linux and DOS (just type 'make'), on SUN/Solaris systems 'make solaris' should work. Other systems may need additional editing of 'src/Makefile' to set some additional compiler options. X11_PATH Specify the path to your X11 installation. Include files and libraries are searched for at $(X11_PATH)/include and $(X11_PATH)/lib, if you set this variables. If you don't set this variable, your compiler must be able to find X11 by itself, which works fine for Linux, for example. GAME_DIR Specify the directory where the program looks for all the graphics, sounds, levels and high scores. If you leave this commented out, the current directory ('.') is used, which lets you use the game without installing it somewhere in your system (although you have to 'cd' to the game directory each time you want to play it). JOYSTICK Uncomment this line if your system does not support game port hardware like joysticks (and has therefore no joystick include file). Currently the game should work with joysticks on Linux and FreeBSD. SOUNDS Uncomment this line if your system does not support audio hardware. Currently the game should work with sound support on Linux, FreeBSD, SUN/Solaris, HP-UX and most Unix system that support '/dev/dsp' or '/dev/audio' devices. SCORE_ENTRIES Choose if you want to allow many entries in the high score table for one player or exactly one entry. Systems with a lot of users maybe want to limit high score entries to only one entry for each player (and therefore set 'SCORE_ENTRIES' to 'ONE_PER_NAME') where systems used by only one person maybe want to use the default of 'MANY_PER_NAME' which is automatically choosen if you leave everything commented out. Modifications of the Makefile in the directory 'src' are normally not needed. If the game fails to compile out of the box, you may have to modify some of the system variables there to get it to compile. SYSTEM May need to be set to some system dependend values. INCL, LIBS Maybe some more directories for include files and libraries have to be added to this variables depending on your system. If you have any comments, additions or modifications to the Makefile(s), please send me mail: 'info@artsoft.org'. Thanks! rocksndiamonds-3.3.0.1+dfsg1/scores/0000755000175000017500000000000011403523057016124 5ustar dimkadimkarocksndiamonds-3.3.0.1+dfsg1/rocksndiamonds.10000644000175000017500000002234607224222121017727 0ustar dimkadimka.TH ROCKSNDIAMONDS 1L "20 November 1995" .SH NAME Rocks'n'Diamonds \- A game for Unix/X11 .SH INTRODUCTION This is a nice little game with color graphics and sound for your Unix system with color X11. You need an 8-Bit color display or better. It is not recommended on black&white systems, and maybe not on gray scale systems. If you know the game "Boulderdash" (Commodore C64) or "Emerald Mine" (Amiga), you know what "ROCKS'N'DIAMONDS" is about. .SH The Menues You can see eight blue circles on the left side of the eight green menu texts; these are buttons to activate the menu commands by simply clicking on them with the left mouse button. The button will then change to red. (You can control the menues over the keyboard or joystick, too. Just use the arrow keys and the 'Return' or 'Enter' key or, if you use a joystick, the appropriate direction and the fire button.) .SH The menu 'name' When you start the game the first time, your login name will appear in the 'NAME:' field. If you want to use a different name for playing, for example a funny player name or a name for cheating, you can click on the button and enter a new name. If you choose a certain special name, you will be in a cheat mode where you can choose all levels without playing the lower levels before... :) .SH The menue 'level' If you have played some levels of this game, you can choose the already played levels at any time, but you cannot choose the higher levels. This means, you can choose levels from level 0 to the highest level that you have ever won. This is known as your 'handicap'. If the level number is red, you have choosen a 'ready' level, if it is yellow, you have choosen a 'user' level, which is blank and can be edited by yourself with the built-in level editor (see below). To choose new level series, click on the button on the left and choose the new level serie. .SH Hall of fame Click on this button to see a list of the best players of this level. Click again to go back to the main menu. .SH Level creator This brings you to the level editor, if you have switched to a 'yellow' level, which are empty and can be filled by yourself. See below. .SH Info screen This screen shows you all elements which appear in the game and presents you the background music loops which you can listen to while playing the levels (only available on Linux and FreeBSD systems). .SH Start game This will start the game. .SH Setup To change some things in the game, use the setup menu. You can enable/disable "Sound" (enables/disables _all_ sounds in the game), "Sound loops" (only allowed on Linux and FreeBSD systems with VoxWare[tm] sound driver; don't worry if you never heard of it -- it's the name of the standard Linux sound driver), "Game music" (can always be enabled on very fast systems [exception: you don't like it], on slower systems it will take some percent of CPU time which will slow things down a bit) and "Toons", which will forbid/ permit the little animated toons. "Buffered Gfx" can be set to "off" on slower systems, "Fading" gives a nice fading effect when displaying new screens, but unfortunately I haven't found a system which is fast enough to display it so far. (Maybe this works better on highly accelerated X servers.) Better set this to "off" if you have a normal system... Set "auto-record" to "on" if you want to automatically record each game to tape. If you have a Linux or FreeBSD system with a joystick, you can choose the "1st" or the "2nd" joystick port and use "Cal. Joystick" to calibrate it. Use "Save and exit" after calibration to save it for later playing sessions. "Exit" quits the setup menu without saving the changes, "Save and exit" will save and then return to the main menu. .SH Quit Exit the game. .SH How To Play The Game When the game has started, you can see the playfield on the left side and a control field on the right side. The control field contains the following elements: .TP .B Level indicator Tells you which level you are playing. .TP .B Emeralds Shows you how many emeralds you still need to win the current level. .TP .B Dynamite1 Shows you how many dynamite bombs you have. .TP .B Keys Shows you which keys you have in your inventory. .TP .B Score Shows the current score. In some levels there are some extra items giving extra score points. .TP .B Time The seconds you have still left to play the level. .TP .B Stop/Pause/Play Game controls to stop the game, pause it and go on playing. If the tape recorder is recording your game, it is stopping/pausing/playing as well. .TP .B Music buttons The three music buttons can be used to control the background music loop, the 'looping' sounds and all other sounds. The little red light shows you if it is enabled or disabled. On slower systems (and a 486DX33 with Soundblaster _is_ a slower system) it increases the game speed to turn off background music. You can completely turn off all sound effects in the setup menu, although it is much more fun to have them enabled when it doesn't eats up to much speed. (A little note: The sound server currently needs about 10% CPU time on my 486DX/33/SBPro system when playing background music. I wonder if this would get better with a better soundcard, like Gravis Ultrasound, or if only pure CPU power helps in this case...) .SH About the game itself Of course you know Boulderdash, so you will know how to play the game. :) If not: You can move your playing figure (the smiley) with the arrow keys or with the joystick (if you have no joystick and even no arrow keys on your keyboard, you can use the keys 'i', 'j', 'k' and 'm' for the directions. To 'snap' a field near you without moving to it, you can use the left fire button on your joystick (hold it down, move the stick to 'snap' the field, release the button) or the keys 'e', 's', 'd' and 'x'. To place a piece of dynamite, use the right fire button on your joystick or use the 'b' key (and, after placing the dynamite, better see to move away from this field...). Just try the levels from the 'tutorial' level serie to see what most of the elements do or have a look at the info screen! Note: It is *highly recommended* to use a joystick for playing this game! It is possible to play it with the keyboard, but it is *much more fun* to play with a joystick, and some levels are very difficult to solve with the keyboard. So, the best platform for this game is a Linux or a FreeBSD system (which gives you background music, too). .SH The Level Editor To build your own levels, just choose a 'yellow', empty level. If you cannot find any 'yellow' levels, choose a different level serie or choose the higher level numbers (if you have a small 'handicap' number, the higher levels will be skipped to reach the 'empty' levels. Another way is to create your own level series. Just add a line to the file 'levels/ROCKS.levelinfo' with the following entries: .br - the name of the level directory (create this directory under 'levels') .br - the name of the level serie (don't use any whitespaces within the name) .br - the 'ready' (red) levels (start with zero) .br - the 'empty' (yellow) levels (set this to some number of blank levels) .br To edit a level, you can use all three mouse buttons to draw in the level window. Click into the elements field with one of the three buttons to remap it to the new element. Use the arrow widgets to scroll around in the level. Use the 'flood fill' field to init exactly ony flood fill operation in the level field (you will be prompted). Click on 'control window' to switch to the control window. In the control window you can modify different parameters like the size of the level playfield, the name of the level, the scores for different elements and something like that. The four 3x3 field on the upper left can be edited like the level field and indicate the 'contents' of smashed crunchers (just try it out with some crunchers in one of your own levels). 'Undo & Exit' leaves the level editor, throwing away all the changes you have done to the level. 'Save & Exit' leveas the level editor and saves the new level (the old one will be deleted). .SH The Tape Recorder You can use the tape recorder to record games and play tapes of previously played games. Just use them like a normal video recorder. .TP .B Recording a game on tape: Just press the 'record' button (the one with the red point on it) and either press 'Start Game' or press on 'record' or 'pause' to end the pause mode and start playing and recording. If you have set "auto record" in the setup menu to "on", you just have to press 'Start Game' as usual. .TP .B Saving a game tape: To save a tape to the tape file corresponding to the level (that means that you can only save one tape file for each level), just press the 'eject' button (the very left button). Then you will be prompted if you really want to replace the old tape (if an old tape exists). .TP .B Playing a tape: Just press 'play' and then either 'play' or 'pause'. While recording or playing, you can press 'pause' to stop the recording or the playing of the tape and continue by pressing 'pause' again. You can use either the tape recorder buttons or the game control buttons for this purpose. .SH And Now Have Fun! Have fun playing the game, building new levels and breaking all high scores! ;) .SH AUTHOR If you have any comments, problems, suggestions, donations, flames, send them to info@artsoft.org Have fun! rocksndiamonds-3.3.0.1+dfsg1/Makefile0000644000175000017500000001236611403523057016276 0ustar dimkadimka# ============================================================================= # Rocks'n'Diamonds Makefile # ----------------------------------------------------------------------------- # (c) 1995-2007 Holger Schemel # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- # command name of your favorite ANSI C compiler # (this must be set to "cc" for some systems) CC = gcc # command name of GNU make on your system # (this must be set to "gmake" for some systems) MAKE = make # path to X11 on your system X11_PATH = /usr/X11R6 # directory for read-only game data (like graphics, sounds, levels) # default is '.' to be able to run program without installation # RO_GAME_DIR = /usr/games # use the following setting for Debian / Ubuntu installations: # RO_GAME_DIR = /usr/share/games/rocksndiamonds # directory for writable game data (like highscore files) # default is '.' to be able to run program without installation # RW_GAME_DIR = /var/games # use the following setting for Debian / Ubuntu installations: # RW_GAME_DIR = /var/games/rocksndiamonds # uncomment if system has no joystick include file # JOYSTICK = -DNO_JOYSTICK # choose if more than one global score file entry for one player is allowed # (default: MANY_PER_NAME) # uncomment to install game in multi-user environment # SCORE_ENTRIES = ONE_PER_NAME # uncomment to install game in single-user environment (default) # SCORE_ENTRIES = MANY_PER_NAME # paths for cross-compiling (only needed for non-native MS-DOS and Win32 build) CROSS_PATH_MSDOS = /usr/local/cross-msdos/i386-msdosdjgpp CROSS_PATH_WIN32 = /usr/local/cross-tools/i386-mingw32msvc # compile special edition of R'n'D instead of the normal (classic) version # SPECIAL_EDITION = rnd_jue # ----------------------------------------------------------------------------- # there should be no need to change anything below # ----------------------------------------------------------------------------- .EXPORT_ALL_VARIABLES: SRC_DIR = src MAKE_CMD = $(MAKE) -C $(SRC_DIR) # DEFAULT_TARGET = x11 DEFAULT_TARGET = sdl # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET) x11: @$(MAKE_CMD) TARGET=x11 sdl: @$(MAKE_CMD) TARGET=sdl solaris: @$(MAKE_CMD) PLATFORM=solaris TARGET=x11 solaris-sdl: @$(MAKE_CMD) PLATFORM=solaris TARGET=sdl mac: @$(MAKE_CMD) PLATFORM=macosx mac-static: @$(MAKE_CMD) PLATFORM=macosx TARGET=sdl-static msdos: @$(MAKE_CMD) PLATFORM=msdos os2: @$(MAKE_CMD) PLATFORM=os2 cross-msdos: @PATH=$(CROSS_PATH_MSDOS)/bin:${PATH} $(MAKE_CMD) PLATFORM=cross-msdos cross-win32: @PATH=$(CROSS_PATH_WIN32)/bin:${PATH} $(MAKE_CMD) PLATFORM=cross-win32 clean: @$(MAKE_CMD) clean # ----------------------------------------------------------------------------- # development, test, distribution build and packaging targets # ----------------------------------------------------------------------------- auto-conf: @$(MAKE_CMD) auto-conf run: all @$(MAKE_CMD) run gdb: all @$(MAKE_CMD) gdb valgrind: all @$(MAKE_CMD) valgrind enginetest: all ./Scripts/make_enginetest.sh enginetestcustom: all ./Scripts/make_enginetest.sh custom enginetestfast: all ./Scripts/make_enginetest.sh fast enginetestnew: all ./Scripts/make_enginetest.sh new leveltest: all ./Scripts/make_enginetest.sh leveltest levelsketch_images: all ./Scripts/make_levelsketch_images.sh backup: ./Scripts/make_backup.sh src tar backup-net-copy: ./Scripts/make_backup.sh src scp backup-net: backup backup-net-copy backup_lev: ./Scripts/make_backup.sh lev backup_gfx: ./Scripts/make_backup.sh gfx # prerelease: # ./Scripts/make_prerelease.sh jue: @$(MAKE) SPECIAL_EDITION=rnd_jue all jue-win: @$(MAKE) SPECIAL_EDITION=rnd_jue cross-win32 dist-clean: @$(MAKE_CMD) dist-clean dist-build-unix: @BUILD_DIST=TRUE $(MAKE) x11 dist-build-msdos: @BUILD_DIST=TRUE $(MAKE) cross-msdos dist-build-win32: @BUILD_DIST=TRUE $(MAKE) cross-win32 dist-build-macosx: # (this is done by "dist-package-macosx" target) dist-package-unix: ./Scripts/make_dist.sh unix . dist-package-msdos: ./Scripts/make_dist.sh dos . dist-package-win32: ./Scripts/make_dist.sh win . dist-package-macosx: ./Scripts/make_dist.sh mac . $(MAKE) dist-upload-unix: ./Scripts/make_dist.sh unix . upload dist-upload-msdos: ./Scripts/make_dist.sh dos . upload dist-upload-win32: ./Scripts/make_dist.sh win . upload dist-upload-macosx: ./Scripts/make_dist.sh mac . upload dist-build-all: $(MAKE) clean $(MAKE) dist-build-unix ; $(MAKE) dist-clean $(MAKE) dist-build-win32 ; $(MAKE) dist-clean # $(MAKE) dist-build-msdos ; $(MAKE) dist-clean dist-package-all: $(MAKE) dist-package-unix $(MAKE) dist-package-win32 $(MAKE) dist-package-macosx # $(MAKE) dist-package-msdos dist-upload-all: $(MAKE) dist-upload-unix $(MAKE) dist-upload-win32 $(MAKE) dist-upload-macosx # $(MAKE) dist-upload-msdos dist-all: dist-build-all dist-package-all upload-all: dist-upload-all tags: $(MAKE_CMD) tags depend dep: $(MAKE_CMD) depend rocksndiamonds-3.3.0.1+dfsg1/COPYING0000444000175000017500000004307605022066500015664 0ustar dimkadimka GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.