+Release Version 2.1.0 [05 AUG 2002]
+-----------------------------------
+ - native Mac OS X port (finally!)
+ - graphics, sounds and music now fully configurable
+ - added support for TrueColor PCX graphics files
+ - added support for 16 bit WAV sound files
+ - enhanced sound system (especially regarding stereo and loop sounds)
+ - new structured setup menu (with sub-menues for graphics and sounds)
+ - added "quick save" and "quick load" functions with shortcut key
+ - added single-step playing mode (automatic pause after each step)
+ - behaviour of "Escape" key in level editor now more intuitive
+ - changed default slipping behaviour of gems back to 2.0.0 style;
+ this is now an element property for gems in the level editor,
+ although existing converted levels use the new EM gems behaviour
+ - bug fixed that prevented walking through tubes when gravity on
+ - added Boulder Dash style "snap-pushing" (thanks to Achim Härtel)
+ - fixed memory leak in image loading code
+ - fixed some "solid" elements that were accidentally destructible
+ - fixed some tape stuff
+ - added new contributed levels from the following players:
+ + Conor Mancone
+ + Gavin Davidson
+ + Jerome Kunegis
+ + Rüdiger Schäfer
+ + Flyboy: level group "Cops and Robbers", with own graphics set
+ - added custom graphics set "Animal Kingdom" by Flyboy
+
Release Version 2.0.1 [19 MAR 2002]
-----------------------------------
- bug in explosion code fixed that broke level 24 of "Baby Ghost Mine"
+ explosion chain reactions are now a bit slower than murphy
- behaviour of robots adjusted to make them less aggressive
(needed for quite some Emerald Mine Club levels)
+ - emeralds and diamonds now fall off normal, steel and growing walls,
+ as this is the correct behaviour in Emerald Mine; existing private
+ and contributed levels will still behave as before, unless saved
+ again (with or without modifications) from the level editor of the
+ current version of the game
- icon for Windows executable added
- bug when selecting default level series fixed
- new IFF style file format for level and tape files
Release Version 1.4.0 [27 OCT 1999]
-----------------------------------
- - new Boulderdash elements for better game emulation
+ - new Boulder Dash elements for better game emulation
- new cool medium-sized crystal font
- new elements and graphics for Diamond Caves II levels
- new elements and graphics for Emerald Mine Club levels
there are diagonal directions with keyboard playing
and the fire buttons are mapped to the shift keys)
- a lot of new elements for better emulation of levels
- from the games "Boulderdash", "Emerald Mine" and
+ from the games "Boulder Dash", "Emerald Mine" and
"Sokoban". New elements to build "Dynablaster" style
levels.
- enhanced functionality of the level tape recorder
#=============================================================================#
# Makefile for Rocks'n'Diamonds #
-# (c) 1995-2000 Holger Schemel, info@artsoft.org #
+# (c) 1995-2002 Holger Schemel, info@artsoft.org #
#=============================================================================#
#-----------------------------------------------------------------------------#
# configuration section #
#-----------------------------------------------------------------------------#
-# specify your favorite ANSI C compiler
+# specify command name of your favorite ANSI C compiler
+# (this must be set to "cc" for some systems)
CC = gcc
+# specify command name of GNU make on your system
+# (this must be set to "gmake" for some systems)
+MAKE = make
+
# specify path to X11 on your system
-# if undefined, use system defaults (works with Linux/gcc/libc5)
-X11_PATH = /usr/X11
+X11_PATH = /usr/X11R6
# specify directory for read-only game data (like graphics, sounds, levels)
# default is '.', so you can play without installing game data somewhere
.EXPORT_ALL_VARIABLES:
-MAKE = make
-
SRC_DIR = src
MAKE_CMD = $(MAKE) -C $(SRC_DIR)
solaris-sdl:
@$(MAKE_CMD) PLATFORM=solaris TARGET=sdl
+mac:
+ @$(MAKE_CMD) PLATFORM=macosx
+
msdos:
@$(MAKE_CMD) PLATFORM=msdos
# development only stuff #
#-----------------------------------------------------------------------------#
+run:
+ @$(MAKE_CMD) TARGET=x11 && ./rocksndiamonds --verbose
+
backup:
./Scripts/make_backup.sh src
dist-win32:
./Scripts/make_dist.sh win .
+dist-macosx:
+ ./Scripts/make_dist.sh mac . $(MAKE)
+
dist-clean:
@$(MAKE_CMD) dist-clean
@BUILD_DIST=TRUE $(MAKE) cross-win32 ; $(MAKE) dist-clean
@BUILD_DIST=TRUE $(MAKE) cross-msdos ; $(MAKE) dist-clean
-dist-all: dist-build-all dist-unix dist-msdos dist-win32
+dist-all: dist-build-all dist-unix dist-msdos dist-win32 dist-macosx
depend dep:
$(MAKE_CMD) depend
#=============================================================================#
# Makefile for Rocks'n'Diamonds #
-# (c) 1995-2000 Holger Schemel, info@artsoft.org #
+# (c) 1995-2002 Holger Schemel, info@artsoft.org #
#=============================================================================#
.EXPORT_ALL_VARIABLES:
PLATFORM = unix
endif
+ifeq ($(PLATFORM),macosx)
+PLATFORM = unix
+TARGET=sdl
+endif
+
ifeq ($(PLATFORM),unix)
PROFILING_FLAGS = -pg
endif
CONFIG = $(CONFIG_GAME_DIR) $(CONFIG_SCORE_ENTRIES) $(JOYSTICK)
-DEBUG = -DDEBUG -g
+# DEBUG = -DDEBUG -g
# PROFILING = $(PROFILING_FLAGS)
# OPTIONS = $(DEBUG) -Wall # only for debugging purposes
SRCS = main.c \
init.c \
+ config.c \
events.c \
tools.c \
screens.c \
editor.c \
files.c \
tape.c \
- joystick.c \
cartoons.c \
network.c \
netserv.c
OBJS = main.o \
init.o \
+ config.o \
events.o \
tools.o \
screens.o \
editor.o \
files.o \
tape.o \
- joystick.o \
cartoons.o \
network.o \
netserv.o
+TIMESTAMP_FILE = conftime.h
+
LIBDIR = libgame
LIBGAME = $(LIBDIR)/libgame.a
all: libgame_dir $(PROGNAME)
-$(PROGNAME): $(LIBGAME) $(OBJS) $(ICON)
+$(PROGNAME): $(LIBGAME) $(TIMESTAMP_FILE) $(OBJS) $(ICON)
$(CC) $(PROFILING) $(OBJS) $(ICON) $(LIBGAME) $(LDFLAGS) -o $(PROGNAME)
libgame_dir:
$(LIBGAME):
@$(MAKE) -C $(LIBDIR)
+$(TIMESTAMP_FILE): $(SRCS)
+ @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)
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "tools.h"
-static void HandleAnimation(int);
-static boolean AnimateToon(int, boolean);
-static void DrawAnim(Bitmap *, GC, int, int, int, int, int, int, int, int);
-
-struct AnimInfo
-{
- int width, height;
- int src_x, src_y;
- int frames;
- int frames_per_second;
- int stepsize;
- boolean pingpong;
- int direction;
- int position;
-};
-
-/* values for cartoon figures */
+/* values for toon definition */
#define NUM_TOONS 18
#define DWARF_XSIZE 40
#define GAMETOON_FPS 20
#define GAMETOON_STEPSIZE 4
-#define ANIMDIR_LEFT 1
-#define ANIMDIR_RIGHT 2
-#define ANIMDIR_UP 4
-#define ANIMDIR_DOWN 8
-
-#define ANIMPOS_ANY 0
-#define ANIMPOS_LEFT 1
-#define ANIMPOS_RIGHT 2
-#define ANIMPOS_UP 4
-#define ANIMPOS_DOWN 8
-#define ANIMPOS_UPPER 16
-
-#define ANIM_START 0
-#define ANIM_CONTINUE 1
-#define ANIM_STOP 2
-
-void InitAnimation()
-{
- HandleAnimation(ANIM_START);
-}
-
-void StopAnimation()
+struct ToonInfo toons[NUM_TOONS] =
{
- HandleAnimation(ANIM_STOP);
-}
-
-void DoAnimation()
-{
- HandleAnimation(ANIM_CONTINUE);
-}
-
-void HandleAnimation(int mode)
-{
- static unsigned long animstart_delay = -1;
- static unsigned long animstart_delay_value = 0;
- static boolean anim_restart = TRUE;
- static boolean reset_delay = TRUE;
- static int toon_nr = 0;
- int draw_mode;
-
- if (!setup.toons)
- return;
-
- switch(mode)
{
- case ANIM_START:
- anim_restart = TRUE;
- reset_delay = TRUE;
-
- /* Fill empty backbuffer for animation functions */
- if (setup.direct_draw && game_status == PLAYING)
- {
- int xx,yy;
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for(xx=0; xx<SCR_FIELDX; xx++)
- for(yy=0; yy<SCR_FIELDY; yy++)
- DrawScreenField(xx,yy);
- DrawAllPlayers();
-
- SetDrawtoField(DRAW_DIRECT);
- }
-
- if (setup.soft_scrolling && game_status == PLAYING)
- {
- 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);
- }
-
- return;
- break;
- case ANIM_CONTINUE:
- break;
- case ANIM_STOP:
- redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
-
- /* Redraw background even when in direct drawing mode */
- draw_mode = setup.direct_draw;
- setup.direct_draw = FALSE;
-
- BackToFront();
-
- setup.direct_draw = draw_mode;
-
- return;
- break;
- default:
- break;
- }
-
- if (reset_delay)
+ PIX_TOONS,
+ DWARF_XSIZE, DWARF_YSIZE,
+ DWARF_X, DWARF_Y,
+ DWARF_FRAMES,
+ DWARF_FPS,
+ DWARF_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
{
- animstart_delay = Counter();
- animstart_delay_value = SimpleRND(3000);
- reset_delay = FALSE;
- }
-
- if (anim_restart)
+ PIX_TOONS,
+ DWARF_XSIZE, DWARF_YSIZE,
+ DWARF_X, DWARF2_Y,
+ DWARF_FRAMES,
+ DWARF_FPS,
+ DWARF_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
{
- if (!DelayReached(&animstart_delay, animstart_delay_value))
- return;
-
- toon_nr = SimpleRND(NUM_TOONS);
- }
-
- anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
-}
-
-boolean AnimateToon(int toon_nr, boolean restart)
-{
- static int pos_x = 0, pos_y = 0;
- static int delta_x = 0, delta_y = 0;
- static int frame = 0, frame_step = 1;
- 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;
- static struct AnimInfo toon[NUM_TOONS] =
+ PIX_TOONS,
+ JUMPER_XSIZE, JUMPER_YSIZE,
+ JUMPER_X, JUMPER_Y,
+ JUMPER_FRAMES,
+ JUMPER_FPS,
+ JUMPER_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
{
- {
- DWARF_XSIZE, DWARF_YSIZE,
- DWARF_X, DWARF_Y,
- DWARF_FRAMES,
- DWARF_FPS,
- DWARF_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- DWARF_XSIZE, DWARF_YSIZE,
- DWARF_X, DWARF2_Y,
- DWARF_FRAMES,
- DWARF_FPS,
- DWARF_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- JUMPER_XSIZE, JUMPER_YSIZE,
- JUMPER_X, JUMPER_Y,
- JUMPER_FRAMES,
- JUMPER_FPS,
- JUMPER_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- CLOWN_XSIZE, CLOWN_YSIZE,
- CLOWN_X, CLOWN_Y,
- CLOWN_FRAMES,
- CLOWN_FPS,
- CLOWN_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_UP,
- ANIMPOS_ANY
- },
- {
- BIRD_XSIZE, BIRD_YSIZE,
- BIRD1_X, BIRD1_Y,
- BIRD_FRAMES,
- BIRD_FPS,
- BIRD_STEPSIZE,
- ANIM_OSCILLATE,
- ANIMDIR_RIGHT,
- ANIMPOS_UPPER
- },
- {
- BIRD_XSIZE, BIRD_YSIZE,
- BIRD2_X, BIRD2_Y,
- BIRD_FRAMES,
- BIRD_FPS,
- BIRD_STEPSIZE,
- ANIM_OSCILLATE,
- ANIMDIR_LEFT,
- ANIMPOS_UPPER
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_4,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_DOWN
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_8,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_LEFT,
- ANIMPOS_ANY
- },
- {
- GAMETOON_XSIZE, GAMETOON_YSIZE,
- ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
- ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
- GAMETOON_FRAMES_8,
- GAMETOON_FPS,
- GAMETOON_STEPSIZE,
- ANIM_NORMAL,
- ANIMDIR_RIGHT,
- ANIMPOS_ANY
- },
- };
- struct AnimInfo *anim = &toon[toon_nr];
- int anim_bitmap_nr = (toon_nr < 6 ? PIX_TOONS : PIX_HEROES);
- Bitmap *anim_bitmap = pix[anim_bitmap_nr];
- GC anim_clip_gc = pix[anim_bitmap_nr]->stored_clip_gc;
-
- if (restart)
+ PIX_TOONS,
+ CLOWN_XSIZE, CLOWN_YSIZE,
+ CLOWN_X, CLOWN_Y,
+ CLOWN_FRAMES,
+ CLOWN_FPS,
+ CLOWN_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_UP,
+ ANIMPOS_ANY
+ },
{
- horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
- vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
- anim_delay_value = 1000/anim->frames_per_second;
- frame = 0;
-
- if (horiz_move)
- {
- if (anim->position==ANIMPOS_UP)
- pos_y = 0;
- else if (anim->position==ANIMPOS_DOWN)
- pos_y = FULL_SYSIZE-anim->height;
- else if (anim->position==ANIMPOS_UPPER)
- pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2);
- else
- pos_y = SimpleRND(FULL_SYSIZE-anim->height);
-
- if (anim->direction==ANIMDIR_RIGHT)
- {
- delta_x = anim->stepsize;
- pos_x = -anim->width+delta_x;
- }
- else
- {
- delta_x = -anim->stepsize;
- pos_x = FULL_SXSIZE+delta_x;
- }
- delta_y = 0;
- }
- else
- {
- if (anim->position==ANIMPOS_LEFT)
- pos_x = 0;
- else if (anim->position==ANIMPOS_RIGHT)
- pos_x = FULL_SXSIZE-anim->width;
- else
- pos_x = SimpleRND(FULL_SXSIZE-anim->width);
-
- if (anim->direction==ANIMDIR_DOWN)
- {
- delta_y = anim->stepsize;
- pos_y = -anim->height+delta_y;
- }
- else
- {
- delta_y = -anim->stepsize;
- pos_y = FULL_SYSIZE+delta_y;
- }
- delta_x = 0;
- }
- }
-
- if (pos_x <= -anim->width - anim->stepsize ||
- pos_x >= FULL_SXSIZE + anim->stepsize ||
- pos_y <= -anim->height - anim->stepsize ||
- pos_y >= FULL_SYSIZE + anim->stepsize)
- return(TRUE);
-
- if (!DelayReached(&anim_delay, anim_delay_value))
+ PIX_TOONS,
+ BIRD_XSIZE, BIRD_YSIZE,
+ BIRD1_X, BIRD1_Y,
+ BIRD_FRAMES,
+ BIRD_FPS,
+ BIRD_STEPSIZE,
+ ANIM_OSCILLATE,
+ ANIMDIR_RIGHT,
+ ANIMPOS_UPPER
+ },
+ {
+ PIX_TOONS,
+ BIRD_XSIZE, BIRD_YSIZE,
+ BIRD2_X, BIRD2_Y,
+ BIRD_FRAMES,
+ BIRD_FPS,
+ BIRD_STEPSIZE,
+ ANIM_OSCILLATE,
+ ANIMDIR_LEFT,
+ ANIMPOS_UPPER
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
{
- if ((game_status == HELPSCREEN ||
- (game_status == MAINMENU && redraw_mask & REDRAW_MICROLEVEL))
- && !restart)
- DrawAnim(anim_bitmap, anim_clip_gc,
- src_x + cut_x, src_y + cut_y, width, height,
- REAL_SX + dest_x, REAL_SY + dest_y, pad_x, pad_y);
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_4,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_DOWN
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_8,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_LEFT,
+ ANIMPOS_ANY
+ },
+ {
+ PIX_HEROES,
+ GAMETOON_XSIZE, GAMETOON_YSIZE,
+ ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+ ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+ GAMETOON_FRAMES_8,
+ GAMETOON_FPS,
+ GAMETOON_STEPSIZE,
+ ANIM_NORMAL,
+ ANIMDIR_RIGHT,
+ ANIMPOS_ANY
+ },
+};
- return(FALSE);
- }
+static void PrepareBackbuffer()
+{
+ /* Fill empty backbuffer for animation functions */
+ if (setup.direct_draw && game_status == PLAYING)
+ {
+ int xx,yy;
- if (pos_x<-anim->width)
- pos_x = -anim->width;
- else if (pos_x>FULL_SXSIZE)
- pos_x = FULL_SXSIZE;
- if (pos_y<-anim->height)
- pos_y = -anim->height;
- else if (pos_y>FULL_SYSIZE)
- pos_y = FULL_SYSIZE;
+ SetDrawtoField(DRAW_BACKBUFFER);
- pad_x = (horiz_move ? anim->stepsize : 0);
- pad_y = (vert_move ? anim->stepsize : 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;
+ for(xx=0; xx<SCR_FIELDX; xx++)
+ for(yy=0; yy<SCR_FIELDY; yy++)
+ DrawScreenField(xx,yy);
+ DrawAllPlayers();
- if (pos_x<0)
- {
- dest_x = 0;
- width += pos_x;
- cut_x = -pos_x;
+ SetDrawtoField(DRAW_DIRECT);
}
- else if (pos_x>FULL_SXSIZE-anim->width)
- width -= (pos_x - (FULL_SXSIZE-anim->width));
- if (pos_y<0)
+ if (setup.soft_scrolling && game_status == PLAYING)
{
- dest_y = 0;
- height += pos_y;
- cut_y = -pos_y;
- }
- else if (pos_y>FULL_SYSIZE-anim->height)
- height -= (pos_y - (FULL_SYSIZE-anim->height));
+ int fx = FX, fy = FY;
- DrawAnim(anim_bitmap,anim_clip_gc,
- src_x+cut_x,src_y+cut_y, width,height,
- REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
+ fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
+ fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
- pos_x += delta_x;
- pos_y += delta_y;
- frame += frame_step;
-
- if (frame<0 || frame>=anim->frames)
- {
- if (anim->pingpong)
- {
- frame_step *= -1;
- frame = (frame<0 ? 1 : anim->frames-2);
- }
- else
- frame = (frame<0 ? anim->frames-1 : 0);
+ BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
}
-
- return(FALSE);
}
-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)
+boolean ToonNeedsRedraw()
{
- int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
-
-#if 1
- /* special method to avoid flickering interference with BackToFront() */
- BlitBitmap(backbuffer, pix[PIX_DB_DOOR], dest_x-pad_x, dest_y-pad_y,
- width+2*pad_x, height+2*pad_y, buf_x, buf_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, dest_x-pad_x, dest_y-pad_y,
- width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
- BackToFront();
- BlitBitmap(pix[PIX_DB_DOOR], backbuffer, buf_x, buf_y,
- width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
-#else
- /* normal method, causing flickering interference with BackToFront() */
- BlitBitmap(backbuffer, pix[PIX_DB_DOOR], dest_x-pad_x, dest_y-pad_y,
- width+2*pad_x, height+2*pad_y, buf_x, buf_y);
- SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
- BlitBitmapMasked(toon_bitmap, pix[PIX_DB_DOOR],
- src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
- BlitBitmap(pix[PIX_DB_DOOR], window, buf_x, buf_y,
- width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
-#endif
+ return (game_status == HELPSCREEN ||
+ (game_status == MAINMENU &&
+ ((redraw_mask & REDRAW_MICROLEVEL) ||
+ (redraw_mask & REDRAW_MICROLABEL))));
+}
- FlushDisplay();
+void InitToons()
+{
+ InitToonScreen(pix, pix[PIX_DB_DOOR],
+ BackToFront, PrepareBackbuffer, ToonNeedsRedraw,
+ toons, NUM_TOONS,
+ REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
}
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#ifndef CARTOONS_H
#define CARTOONS_H
-void InitAnimation(void);
-void StopAnimation(void);
-void DoAnimation(void);
+void InitToons(void);
#endif
--- /dev/null
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back! *
+*----------------------------------------------------------*
+* (c) 1995-2002 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"
+
+/* use timestamp created at compile-time */
+#define PROGRAM_BUILD_STRING PROGRAM_IDENT_STRING " " COMPILE_DATE_STRING
+#ifdef DEBUG
+#undef WINDOW_TITLE_STRING
+#define WINDOW_TITLE_STRING PROGRAM_TITLE_STRING " " PROGRAM_BUILD_STRING
+#endif
+
+
+char *getWindowTitleString()
+{
+ return WINDOW_TITLE_STRING;
+}
--- /dev/null
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back! *
+*----------------------------------------------------------*
+* (c) 1995-2002 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 *getWindowTitleString(void);
+
+#endif /* CONFIG_H */
--- /dev/null
+#define COMPILE_DATE_STRING "[2002-08-05 02:26]"
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#define GADGET_ID_DOUBLE_SPEED 73
#define GADGET_ID_GRAVITY 74
#define GADGET_ID_STICK_ELEMENT 75
+#define GADGET_ID_EM_SLIPPERY_GEMS 76
/* another drawing area for random placement */
-#define GADGET_ID_RANDOM_BACKGROUND 76
+#define GADGET_ID_RANDOM_BACKGROUND 77
/* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST 77
-#define GADGET_ID_ELEMENTLIST_LAST (77 + ED_NUM_ELEMENTLIST_BUTTONS - 1)
+#define GADGET_ID_ELEMENTLIST_FIRST 78
+#define GADGET_ID_ELEMENTLIST_LAST (78 + ED_NUM_ELEMENTLIST_BUTTONS - 1)
#define NUM_EDITOR_GADGETS (GADGET_ID_ELEMENTLIST_LAST + 1)
#define ED_CHECKBUTTON_ID_GRAVITY 1
#define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED 2
#define ED_CHECKBUTTON_ID_STICK_ELEMENT 3
+#define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS 4
-#define ED_NUM_CHECKBUTTONS 4
+#define ED_NUM_CHECKBUTTONS 5
#define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_DOUBLE_SPEED
#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
GADGET_ID_STICK_ELEMENT,
&stick_element_properties_window,
"stick window to edit content", "stick window to edit content"
+ },
+ {
+ ED_SETTINGS_XPOS, ED_COUNTER_YPOS(4),
+ GADGET_ID_EM_SLIPPERY_GEMS,
+ &level.em_slippery_gems,
+ "slip down from certain flat walls","use EM style slipping behaviour"
}
};
{
char *info_text = "unknown";
- if (element < num_element_info)
- info_text = element_info[element];
+ if (element < NUM_LEVEL_ELEMENTS)
+ info_text = element_info[element].editor_description;
else
Error(ERR_WARN, "no element description for element %d", element);
else
DrawElementContentAreas();
}
+
+ if (IS_GEM(properties_element))
+ {
+ /* draw checkbutton gadget */
+ i = ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS;
+ x = checkbutton_info[i].x + xoffset_right2;
+ y = checkbutton_info[i].y + yoffset_right2;
+
+ DrawTextF(x, y, font_color, checkbutton_info[i].text);
+ ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
+ GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+ MapCheckbuttonGadget(i);
+ }
}
static void DrawLineElement(int sx, int sy, int element, boolean change_level)
case ED_COUNTER_ID_SELECT_LEVEL:
LoadLevel(level_nr);
+ TapeErase();
ResetUndoBuffer();
DrawEditModeWindow();
break;
Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
else
{
+ if (LevelChanged())
+ level.game_version = GAME_VERSION_ACTUAL;
+
for(x=0; x<lev_fieldx; x++)
for(y=0; y<lev_fieldy; y++)
FieldBackup[x][y] = Ur[x][y];
break;
case GADGET_ID_EXIT:
- if (!LevelChanged() ||
- Request("Level has changed! Exit without saving ?",
- REQ_ASK | REQ_STAY_OPEN))
- {
- CloseDoor(DOOR_CLOSE_1);
-
- /*
- CloseDoor(DOOR_CLOSE_ALL);
- */
-
- game_status = MAINMENU;
- DrawMainMenu();
- }
- else
- {
- CloseDoor(DOOR_CLOSE_1);
- BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
- DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
- DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
- OpenDoor(DOOR_OPEN_1);
- }
+ RequestExitLevelEditor(TRUE); /* if level has changed, ask user */
break;
default:
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 i, id;
+ int i, id = GADGET_ID_NONE;
switch (key)
{
button = MB_RIGHTBUTTON;
break;
+ case KSYM_Escape:
+ if (edit_mode == ED_MODE_DRAWING)
+ {
+ RequestExitLevelEditor(setup.ask_on_escape);
+ }
+ else
+ {
+ DrawDrawingWindow();
+ edit_mode = ED_MODE_DRAWING;
+ }
+ break;
+
default:
- id = GADGET_ID_NONE;
break;
}
ClickOnGadget(level_editor_gadget[id], button);
else if (letter == '.')
ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
- else if (key == KSYM_space || key == KSYM_Return)
+ else if (key == KSYM_Return || key == setup.shortcut.toggle_pause)
ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
else
for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
ClearEditorGadgetInfoText();
+ if (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();
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);
"Content area %d position: %d, %d",
id - GADGET_ID_ELEM_CONTENT_0 + 1, sx, sy);
}
+
+void RequestExitLevelEditor(boolean ask_if_level_has_changed)
+{
+ if (!ask_if_level_has_changed ||
+ !LevelChanged() ||
+ Request("Level has changed! Exit without saving ?",
+ REQ_ASK | REQ_STAY_OPEN))
+ {
+ CloseDoor(DOOR_CLOSE_1);
+ /*
+ CloseDoor(DOOR_CLOSE_ALL);
+ */
+ game_status = MAINMENU;
+ DrawMainMenu();
+ }
+ else
+ {
+ CloseDoor(DOOR_CLOSE_1);
+ BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
+ DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
+ DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+ OpenDoor(DOOR_OPEN_1);
+ }
+}
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
void DrawLevelEd(void);
void HandleLevelEditorKeyInput(Key);
void HandleEditorGadgetInfoText(void *ptr);
+void RequestExitLevelEditor(boolean);
#endif
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "editor.h"
#include "files.h"
#include "tape.h"
-#include "joystick.h"
#include "network.h"
/* values for key_status */
}
}
+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;
void HandleExposeEvent(ExposeEvent *event)
{
#ifndef TARGET_SDL
- int x = event->x, y = event->y;
- int width = event->width, height = event->height;
-
- if (setup.direct_draw && game_status==PLAYING)
- {
- int xx,yy;
- int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
- int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for(xx=0; xx<SCR_FIELDX; xx++)
- for(yy=0; yy<SCR_FIELDY; yy++)
- if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
- DrawScreenField(xx,yy);
- DrawAllPlayers();
-
- SetDrawtoField(DRAW_DIRECT);
- }
-
- if (setup.soft_scrolling && game_status == PLAYING)
- {
- 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);
- }
-
- BlitBitmap(drawto, window, x,y, width,height, x,y);
-
+ RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
FlushDisplay();
#endif
}
if (event->type == EVENT_FOCUSOUT)
{
- int i;
-
KeyboardAutoRepeatOn();
- old_joystick_status = joystick_status;
- joystick_status = JOYSTICK_OFF;
+ old_joystick_status = joystick.status;
+ joystick.status = JOYSTICK_NOT_AVAILABLE;
- /* simulate key release events for still pressed keys */
- key_joystick_mapping = 0;
- for (i=0; i<MAX_PLAYERS; i++)
- stored_player[i].action = 0;
+ ClearPlayerAction();
}
else if (event->type == EVENT_FOCUSIN)
{
KeyboardAutoRepeatOff();
}
if (old_joystick_status != -1)
- joystick_status = old_joystick_status;
+ joystick.status = old_joystick_status;
}
}
HandleSetupScreen(mx,my, 0,0, button);
break;
- case SETUPINPUT:
- HandleSetupInputScreen(mx,my, 0,0, button);
- break;
-
case PLAYING:
#ifdef DEBUG
if (button == MB_RELEASED)
if (game_status == PLAYING)
{
+ /* only needed for single-step tape recording mode */
+ static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
+ static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
int pnr;
for (pnr=0; pnr<MAX_PLAYERS; pnr++)
if (key == *key_info[i].key_custom)
key_action |= key_info[i].action;
+ 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)
+ bomb_placed[pnr] = TRUE;
+ }
+ }
+ else if (key_status == KEY_RELEASED &&
+ (key_action & KEY_BUTTON_2))
+ {
+ if (!bomb_placed[pnr])
+ {
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+ stored_player[pnr].action |= KEY_BUTTON_2;
+ clear_button_2[pnr] = TRUE;
+ }
+
+ bomb_placed[pnr] = FALSE;
+ }
+ }
+ else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
}
}
else
if (key_status == KEY_RELEASED)
return;
- if ((key == KSYM_Return || key == KSYM_space) &&
+ if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
game_status == PLAYING && AllPlayersGone)
{
CloseDoor(DOOR_CLOSE_1);
}
/* allow quick escape to the main menu with the Escape key */
- if (key == KSYM_Escape && game_status != MAINMENU)
+ if (key == KSYM_Escape &&
+ game_status != MAINMENU &&
+ game_status != PLAYING &&
+ game_status != LEVELED &&
+ game_status != CHOOSELEVEL &&
+ game_status != SETUP)
{
- CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
game_status = MAINMENU;
DrawMainMenu();
return;
}
+ /* special key shortcuts */
+ if (game_status == MAINMENU || game_status == 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);
+ }
#ifndef DEBUG
case MAINMENU:
case CHOOSELEVEL:
case SETUP:
- case SETUPINPUT:
switch(key)
{
case KSYM_Return:
- case KSYM_space:
if (game_status == MAINMENU)
HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
else if (game_status == CHOOSELEVEL)
HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
else if (game_status == SETUP)
HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
- else if (game_status == SETUPINPUT)
- HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
+ break;
+
+ case KSYM_Escape:
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
+ else if (game_status == SETUP)
+ HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
break;
case KSYM_Page_Up:
if (game_status == CHOOSELEVEL)
HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
+ else if (game_status == SETUP)
+ HandleSetupScreen(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
break;
case KSYM_Page_Down:
if (game_status == CHOOSELEVEL)
HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
+ else if (game_status == SETUP)
+ HandleSetupScreen(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
break;
#ifdef DEBUG
switch(key)
{
case KSYM_Return:
- case KSYM_space:
game_status = MAINMENU;
DrawMainMenu();
BackToFront();
break;
case LEVELED:
- if (!anyTextGadgetActiveOrJustFinished)
+ if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
HandleLevelEditorKeyInput(key);
break;
{
switch(key)
{
+ case KSYM_Escape:
+ RequestQuitGame(setup.ask_on_escape);
+ break;
#ifdef DEBUG
case KSYM_0:
joy_action = Joystick(i);
result |= joy_action;
-
if (!setup.input[i].use_joystick)
continue;
-
stored_player[i].action = joy_action;
}
case MAINMENU:
case CHOOSELEVEL:
case SETUP:
- case SETUPINPUT:
{
static unsigned long joystickmove_delay = 0;
!DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
newbutton = dx = dy = 0;
- if (game_status==MAINMENU)
+ if (game_status == MAINMENU)
HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
- else if (game_status==CHOOSELEVEL)
+ else if (game_status == CHOOSELEVEL)
HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
- else if (game_status==SETUP)
+ else if (game_status == SETUP)
HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
- else if (game_status==SETUPINPUT)
- HandleSetupInputScreen(0,0,dx,dy,
- newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
break;
}
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
void EventLoop(void);
void HandleOtherEvents(Event *);
void ClearEventQueue(void);
+void ClearPlayerAction(void);
void SleepWhileUnmapped(void);
void HandleExposeEvent(ExposeEvent *);
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
***********************************************************/
#include <ctype.h>
-#include <dirent.h>
#include <sys/stat.h>
#include "libgame/libgame.h"
#include "files.h"
#include "tools.h"
#include "tape.h"
-#include "joystick.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 FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
#define LEVEL_HEADER_SIZE 80 /* size of level file header */
-#define LEVEL_HEADER_UNUSED 15 /* unused level header bytes */
+#define LEVEL_HEADER_UNUSED 14 /* 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 TAPE_HEADER_SIZE 20 /* size of tape file header */
-#define TAPE_HEADER_UNUSED 7 /* unused tape header bytes */
+#define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
/* 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"
-#define SETUP_COOKIE "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2"
-#define LEVELSETUP_COOKIE "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2"
-#define LEVELINFO_COOKIE "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2"
-
-/* file names and filename extensions */
-#if !defined(PLATFORM_MSDOS)
-#define LEVELSETUP_DIRECTORY "levelsetup"
-#define SETUP_FILENAME "setup.conf"
-#define LEVELSETUP_FILENAME "levelsetup.conf"
-#define LEVELINFO_FILENAME "levelinfo.conf"
-#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 LEVELINFO_FILENAME "lvlinfo.cnf"
-#define LEVELFILE_EXTENSION "lvl"
-#define TAPEFILE_EXTENSION "tap"
-#define SCOREFILE_EXTENSION "sco"
-#endif
-
-/* 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_CONTRIBUTION_START 200
-#define LEVELCLASS_CONTRIBUTION_END 299
-#define LEVELCLASS_USER_START 300
-#define LEVELCLASS_USER_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_TUTORIAL LEVELCLASS_TUTORIAL_START
-#define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START
-#define LEVELCLASS_CONTRIBUTION LEVELCLASS_CONTRIBUTION_START
-#define LEVELCLASS_USER LEVELCLASS_USER_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_UNDEFINED 999
-
-#define NUM_LEVELCLASS_DESC 8
-char *levelclass_desc[NUM_LEVELCLASS_DESC] =
-{
- "Tutorial Levels",
- "Classic Originals",
- "Contributions",
- "Private Levels",
- "Boulderdash",
- "Emerald Mine",
- "Supaplex",
- "DX Boulderdash"
-};
-
-#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_CONTRIBUTION(p) \
- ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \
- (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END)
-#define IS_LEVELCLASS_USER(p) \
- ((p)->sort_priority >= LEVELCLASS_USER_START && \
- (p)->sort_priority <= LEVELCLASS_USER_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 LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \
- IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \
- IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \
- IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \
- IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \
- IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \
- IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \
- IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \
- LEVELCLASS_UNDEFINED)
-
-#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \
- IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \
- IS_LEVELCLASS_BD(n) ? FC_GREEN : \
- IS_LEVELCLASS_EM(n) ? FC_YELLOW : \
- IS_LEVELCLASS_SP(n) ? FC_GREEN : \
- IS_LEVELCLASS_DX(n) ? FC_YELLOW : \
- IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \
- IS_LEVELCLASS_USER(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_CONTRIBUTION(n) ? 6 : \
- IS_LEVELCLASS_USER(n) ? 7 : \
- 9)
-
-char *getLevelClassDescription(struct LevelDirInfo *ldi)
-{
- int position = ldi->sort_priority / 100;
-
- if (position >= 0 && position < NUM_LEVELCLASS_DESC)
- return levelclass_desc[position];
- else
- return "Unknown Level Class";
-}
-
-static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */
-static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */
-
-static char *getUserLevelDir(char *level_subdir)
-{
- static char *userlevel_dir = NULL;
- char *data_dir = getUserDataDir();
- char *userlevel_subdir = LEVELS_DIRECTORY;
- if (userlevel_dir)
- free(userlevel_dir);
- if (strlen(level_subdir) > 0)
- userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir);
- else
- userlevel_dir = getPath2(data_dir, userlevel_subdir);
-
- return userlevel_dir;
-}
-
-static char *getTapeDir(char *level_subdir)
-{
- static char *tape_dir = NULL;
- char *data_dir = getUserDataDir();
- char *tape_subdir = TAPES_DIRECTORY;
-
- if (tape_dir)
- free(tape_dir);
-
- if (strlen(level_subdir) > 0)
- tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
- else
- tape_dir = getPath2(data_dir, tape_subdir);
-
- return tape_dir;
-}
-
-static char *getScoreDir(char *level_subdir)
-{
- static char *score_dir = NULL;
- char *data_dir = options.rw_base_directory;
- char *score_subdir = SCORES_DIRECTORY;
-
- if (score_dir)
- free(score_dir);
-
- if (strlen(level_subdir) > 0)
- 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 = getUserDataDir();
- char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
-
- if (levelsetup_dir)
- free(levelsetup_dir);
-
- if (strlen(level_subdir) > 0)
- levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir);
- else
- levelsetup_dir = getPath2(data_dir, levelsetup_subdir);
-
- return levelsetup_dir;
-}
-
-static char *getLevelFilename(int nr)
-{
- static char *filename = NULL;
- char basename[MAX_FILENAME_LEN];
-
- if (filename != NULL)
- free(filename);
-
- sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
- filename = getPath3((leveldir_current->user_defined ?
- getUserLevelDir("") :
- options.level_directory),
- leveldir_current->fullpath,
- basename);
-
- return filename;
-}
-
-static char *getTapeFilename(int nr)
-{
- static char *filename = NULL;
- char basename[MAX_FILENAME_LEN];
-
- if (filename != NULL)
- free(filename);
-
- sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
- filename = getPath2(getTapeDir(leveldir_current->filename), basename);
-
- return filename;
-}
-
-static char *getScoreFilename(int nr)
-{
- static char *filename = NULL;
- char basename[MAX_FILENAME_LEN];
-
- if (filename != NULL)
- free(filename);
-
- sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
- filename = getPath2(getScoreDir(leveldir_current->filename), basename);
-
- return filename;
-}
-
-static void InitTapeDirectory(char *level_subdir)
-{
- createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
- createDirectory(getTapeDir(""), "main tape", PERMS_PRIVATE);
- createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
-}
-
-static void InitScoreDirectory(char *level_subdir)
-{
- createDirectory(getScoreDir(""), "main score", PERMS_PUBLIC);
- createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC);
-}
-
-static void InitUserLevelDirectory(char *level_subdir)
-{
- if (access(getUserLevelDir(level_subdir), F_OK) != 0)
- {
- createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
- createDirectory(getUserLevelDir(""), "main user level", PERMS_PRIVATE);
- createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE);
-
- SaveUserLevelInfo();
- }
-}
-
-static void InitLevelSetupDirectory(char *level_subdir)
-{
- createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
- createDirectory(getLevelSetupDir(""), "main level setup", PERMS_PRIVATE);
- createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
-}
-
-static void ReadChunk_VERS(FILE *file, int *file_version, int *game_version)
-{
- int file_version_major, file_version_minor, file_version_patch;
- int game_version_major, game_version_minor, game_version_patch;
-
- file_version_major = fgetc(file);
- file_version_minor = fgetc(file);
- file_version_patch = fgetc(file);
- fgetc(file); /* not used */
-
- game_version_major = fgetc(file);
- game_version_minor = fgetc(file);
- game_version_patch = fgetc(file);
- fgetc(file); /* not used */
-
- *file_version = VERSION_IDENT(file_version_major,
- file_version_minor,
- file_version_patch);
-
- *game_version = VERSION_IDENT(game_version_major,
- game_version_minor,
- game_version_patch);
-}
-
-static void WriteChunk_VERS(FILE *file, int file_version, int game_version)
-{
- int file_version_major = VERSION_MAJOR(file_version);
- int file_version_minor = VERSION_MINOR(file_version);
- int file_version_patch = VERSION_PATCH(file_version);
- int game_version_major = VERSION_MAJOR(game_version);
- int game_version_minor = VERSION_MINOR(game_version);
- int game_version_patch = VERSION_PATCH(game_version);
-
- fputc(file_version_major, file);
- fputc(file_version_minor, file);
- fputc(file_version_patch, file);
- fputc(0, file); /* not used */
-
- fputc(game_version_major, file);
- fputc(game_version_minor, file);
- fputc(game_version_patch, file);
- fputc(0, file); /* not used */
-}
+/* ========================================================================= */
+/* level file functions */
+/* ========================================================================= */
static void setLevelInfoToDefaults()
{
level.amoeba_content = EL_DIAMANT;
level.double_speed = FALSE;
level.gravity = FALSE;
+ level.em_slippery_gems = FALSE;
for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
level.name[i] = '\0';
static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
{
- ReadChunk_VERS(file, &(level->file_version), &(level->game_version));
+ level->file_version = getFileVersion(file);
+ level->game_version = getFileVersion(file);
return chunk_size;
}
lev_fieldx = level->fieldx = fgetc(file);
lev_fieldy = level->fieldy = fgetc(file);
- level->time = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
- level->gems_needed = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+ level->time = getFile16BitBE(file);
+ level->gems_needed = getFile16BitBE(file);
for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
level->name[i] = fgetc(file);
level->amoeba_content = checkLevelElement(fgetc(file));
level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
-
level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
+ level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
for(x=0; x<3; x++)
level->yam_content[i][x][y] =
checkLevelElement(level->encoding_16bit_field ?
- getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
- fgetc(file));
+ getFile16BitBE(file) : fgetc(file));
return chunk_size;
}
for(x=0; x<level->fieldx; x++)
Feld[x][y] = Ur[x][y] =
checkLevelElement(level->encoding_16bit_field ?
- getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
- fgetc(file));
+ getFile16BitBE(file) : fgetc(file));
return chunk_size;
}
int num_contents, content_xsize, content_ysize;
int content_array[MAX_ELEMENT_CONTENTS][3][3];
- element = checkLevelElement(getFile16BitInteger(file,BYTE_ORDER_BIG_ENDIAN));
+ element = checkLevelElement(getFile16BitBE(file));
num_contents = fgetc(file);
content_xsize = fgetc(file);
content_ysize = fgetc(file);
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] =
- checkLevelElement(getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN));
+ content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
/* correct invalid number of content fields -- should never happen */
if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
return;
}
- getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
+ getFileChunkBE(file, chunk_name, NULL);
if (strcmp(chunk_name, "RND1") == 0)
{
- getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */
+ getFile32BitBE(file); /* not used */
- getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
+ getFileChunkBE(file, chunk_name, NULL);
if (strcmp(chunk_name, "CAVE") != 0)
{
Error(ERR_WARN, "unknown format 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)
{ NULL, 0, NULL }
};
- while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
+ while (getFileChunkBE(file, chunk_name, &chunk_size))
{
int i = 0;
if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
IS_LEVELCLASS_USER(leveldir_current))
{
- /* for user contributed and private levels, use the version of
- the game engine the levels were created for */
- level.game_version = level.file_version;
-
- /* player was faster than monsters in pre-1.0 levels */
+ /* For user contributed and private 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). */
+
+ /* do some special adjustments to support older level versions */
if (level.file_version == FILE_VERSION_1_0)
{
Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
Error(ERR_WARN, "using high speed movement for player");
+
+ /* player was faster than monsters in (pre-)1.0 levels */
level.double_speed = TRUE;
}
+
+ /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
+ if (level.game_version == VERSION_IDENT(2,0,1))
+ level.em_slippery_gems = TRUE;
}
else
{
- /* always use the latest version of the game engine for all but
- user contributed and private levels */
+ /* Always use the latest version of the game engine for all but
+ user contributed and private levels; 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 game emulation 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;
}
/* determine border element for this level */
SetBorderElement();
}
+static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+{
+ putFileVersion(file, level->file_version);
+ putFileVersion(file, level->game_version);
+}
+
static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
{
int i, x, y;
fputc(level->fieldx, file);
fputc(level->fieldy, file);
- putFile16BitInteger(file, level->time, BYTE_ORDER_BIG_ENDIAN);
- putFile16BitInteger(file, level->gems_needed, BYTE_ORDER_BIG_ENDIAN);
+ putFile16BitBE(file, level->time);
+ putFile16BitBE(file, level->gems_needed);
for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
fputc(level->name[i], file);
file);
fputc((level->double_speed ? 1 : 0), file);
fputc((level->gravity ? 1 : 0), file);
-
fputc((level->encoding_16bit_field ? 1 : 0), file);
+ fputc((level->em_slippery_gems ? 1 : 0), file);
WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
}
for(y=0; y<3; y++)
for(x=0; x<3; x++)
if (level->encoding_16bit_field)
- putFile16BitInteger(file, level->yam_content[i][x][y],
- BYTE_ORDER_BIG_ENDIAN);
+ putFile16BitBE(file, level->yam_content[i][x][y]);
else
fputc(level->yam_content[i][x][y], file);
}
for(y=0; y<level->fieldy; y++)
for(x=0; x<level->fieldx; x++)
if (level->encoding_16bit_field)
- putFile16BitInteger(file, Ur[x][y], BYTE_ORDER_BIG_ENDIAN);
+ putFile16BitBE(file, Ur[x][y]);
else
fputc(Ur[x][y], file);
}
return;
}
- putFile16BitInteger(file, element, BYTE_ORDER_BIG_ENDIAN);
+ putFile16BitBE(file, element);
fputc(num_contents, file);
fputc(content_xsize, file);
fputc(content_ysize, file);
for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
for(y=0; y<3; y++)
for(x=0; x<3; x++)
- putFile16BitInteger(file, content_array[i][x][y],
- BYTE_ORDER_BIG_ENDIAN);
+ putFile16BitBE(file, content_array[i][x][y]);
}
void SaveLevel(int level_nr)
return;
}
+ level.file_version = FILE_VERSION_ACTUAL;
+ level.game_version = GAME_VERSION_ACTUAL;
/* check level field for 16-bit elements */
level.encoding_16bit_field = FALSE;
body_chunk_size =
level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
- putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
- putFileChunk(file, "CAVE", CHUNK_SIZE_NONE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+ putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
- putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
- WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
+ putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+ SaveLevel_VERS(file, &level);
- putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
SaveLevel_HEAD(file, &level);
- putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
SaveLevel_AUTH(file, &level);
- putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "BODY", body_chunk_size);
SaveLevel_BODY(file, &level);
if (level.encoding_16bit_yamyam ||
level.num_yam_contents != STD_ELEMENT_CONTENTS)
{
- putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
SaveLevel_CNT2(file, &level, EL_MAMPFER);
}
if (level.encoding_16bit_amoeba)
{
- putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
}
SetFilePermissions(filename, PERMS_PRIVATE);
}
+
+/* ========================================================================= */
+/* tape file functions */
+/* ========================================================================= */
+
static void setTapeInfoToDefaults()
{
int i;
/* always start with reliable default values (empty tape) */
- tape.file_version = FILE_VERSION_ACTUAL;
- tape.game_version = GAME_VERSION_ACTUAL;
TapeErase();
/* default values (also for pre-1.2 tapes) with only the first player */
static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
{
- ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
+ tape->file_version = getFileVersion(file);
+ tape->game_version = getFileVersion(file);
return chunk_size;
}
{
int i;
- tape->random_seed = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
- tape->date = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
- tape->length = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+ 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 = fgetc(file);
-
- ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+ int engine_version;
/* since version 1.2, tapes store which players participate in the tape */
tape->num_participating_players = 0;
tape->num_participating_players++;
}
}
+
+ ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+
+ engine_version = getFileVersion(file);
+ if (engine_version > 0)
+ tape->engine_version = engine_version;
}
return chunk_size;
}
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 */
if (!(file = fopen(filename, MODE_READ)))
return;
- getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
+ getFileChunkBE(file, chunk_name, NULL);
if (strcmp(chunk_name, "RND1") == 0)
{
- getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */
+ getFile32BitBE(file); /* not used */
- getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
+ getFileChunkBE(file, chunk_name, NULL);
if (strcmp(chunk_name, "TAPE") != 0)
{
Error(ERR_WARN, "unknown format of tape file '%s'", filename);
fclose(file);
return;
}
- }
- tape.game_version = tape.file_version;
+ /* 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)
{
{ NULL, 0, NULL }
};
- while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
+ while (getFileChunkBE(file, chunk_name, &chunk_size))
{
int i = 0;
tape.length_seconds = GetTapeLength();
}
+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;
if (tape->player_participates[i])
store_participating_players |= (1 << i);
- putFile32BitInteger(file, tape->random_seed, BYTE_ORDER_BIG_ENDIAN);
- putFile32BitInteger(file, tape->date, BYTE_ORDER_BIG_ENDIAN);
- putFile32BitInteger(file, tape->length, BYTE_ORDER_BIG_ENDIAN);
+ putFile32BitBE(file, tape->random_seed);
+ putFile32BitBE(file, tape->date);
+ putFile32BitBE(file, tape->length);
fputc(store_participating_players, file);
+ /* unused bytes not at the end here for 4-byte alignment of engine_version */
WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+
+ putFileVersion(file, tape->engine_version);
}
static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
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])
body_chunk_size = (num_participating_players + 1) * tape.length;
- putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
- putFileChunk(file, "TAPE", CHUNK_SIZE_NONE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+ putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
- putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
- WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
+ putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+ SaveTape_VERS(file, &tape);
- putFileChunk(file, "HEAD", TAPE_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
SaveTape_HEAD(file, &tape);
- putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
+ putFileChunkBE(file, "BODY", body_chunk_size);
SaveTape_BODY(file, &tape);
fclose(file);
printf("\n");
printf("-------------------------------------------------------------------------------\n");
- printf("Tape of Level %d (file version %06d, game version %06d\n",
+ printf("Tape of Level %d (file version %06d, game version %06d)\n",
tape->level_nr, tape->file_version, tape->game_version);
printf("-------------------------------------------------------------------------------\n");
printf("-------------------------------------------------------------------------------\n");
}
+
+/* ========================================================================= */
+/* score file functions */
+/* ========================================================================= */
+
void LoadScore(int level_nr)
{
int i;
SetFilePermissions(filename, PERMS_PUBLIC);
}
-/* ------------------------------------------------------------------------- */
-/* 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"
-#define TOKEN_STR_PLAYER_PREFIX "player_"
+/* ========================================================================= */
+/* 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_SCROLL_DELAY 5
-#define SETUP_TOKEN_SOFT_SCROLLING 6
-#define SETUP_TOKEN_FADING 7
-#define SETUP_TOKEN_AUTORECORD 8
-#define SETUP_TOKEN_QUICK_DOORS 9
-#define SETUP_TOKEN_TEAM_MODE 10
-#define SETUP_TOKEN_HANDICAP 11
-#define SETUP_TOKEN_TIME_LIMIT 12
-#define SETUP_TOKEN_FULLSCREEN 13
+#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_SOFT_SCROLLING 7
+#define SETUP_TOKEN_FADING 8
+#define SETUP_TOKEN_AUTORECORD 9
+#define SETUP_TOKEN_QUICK_DOORS 10
+#define SETUP_TOKEN_TEAM_MODE 11
+#define SETUP_TOKEN_HANDICAP 12
+#define SETUP_TOKEN_TIME_LIMIT 13
+#define SETUP_TOKEN_FULLSCREEN 14
+#define SETUP_TOKEN_ASK_ON_ESCAPE 15
+#define SETUP_TOKEN_GRAPHICS_SET 16
+#define SETUP_TOKEN_SOUNDS_SET 17
+#define SETUP_TOKEN_MUSIC_SET 18
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
+
+#define NUM_GLOBAL_SETUP_TOKENS 22
+
+/* shortcut setup */
+#define SETUP_TOKEN_SAVE_GAME 0
+#define SETUP_TOKEN_LOAD_GAME 1
+#define SETUP_TOKEN_TOGGLE_PAUSE 2
+
+#define NUM_SHORTCUT_SETUP_TOKENS 3
/* player setup */
-#define SETUP_TOKEN_USE_JOYSTICK 14
-#define SETUP_TOKEN_JOY_DEVICE_NAME 15
-#define SETUP_TOKEN_JOY_XLEFT 16
-#define SETUP_TOKEN_JOY_XMIDDLE 17
-#define SETUP_TOKEN_JOY_XRIGHT 18
-#define SETUP_TOKEN_JOY_YUPPER 19
-#define SETUP_TOKEN_JOY_YMIDDLE 20
-#define SETUP_TOKEN_JOY_YLOWER 21
-#define SETUP_TOKEN_JOY_SNAP 22
-#define SETUP_TOKEN_JOY_BOMB 23
-#define SETUP_TOKEN_KEY_LEFT 24
-#define SETUP_TOKEN_KEY_RIGHT 25
-#define SETUP_TOKEN_KEY_UP 26
-#define SETUP_TOKEN_KEY_DOWN 27
-#define SETUP_TOKEN_KEY_SNAP 28
-#define SETUP_TOKEN_KEY_BOMB 29
-
-/* level directory info */
-#define LEVELINFO_TOKEN_NAME 30
-#define LEVELINFO_TOKEN_NAME_SHORT 31
-#define LEVELINFO_TOKEN_NAME_SORTING 32
-#define LEVELINFO_TOKEN_AUTHOR 33
-#define LEVELINFO_TOKEN_IMPORTED_FROM 34
-#define LEVELINFO_TOKEN_LEVELS 35
-#define LEVELINFO_TOKEN_FIRST_LEVEL 36
-#define LEVELINFO_TOKEN_SORT_PRIORITY 37
-#define LEVELINFO_TOKEN_LEVEL_GROUP 38
-#define LEVELINFO_TOKEN_READONLY 39
-
-#define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_PLAYER_NAME
-#define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_FULLSCREEN
-
-#define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK
-#define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB
-
-#define FIRST_LEVELINFO_TOKEN LEVELINFO_TOKEN_NAME
-#define LAST_LEVELINFO_TOKEN LEVELINFO_TOKEN_READONLY
+#define SETUP_TOKEN_USE_JOYSTICK 0
+#define SETUP_TOKEN_JOY_DEVICE_NAME 1
+#define SETUP_TOKEN_JOY_XLEFT 2
+#define SETUP_TOKEN_JOY_XMIDDLE 3
+#define SETUP_TOKEN_JOY_XRIGHT 4
+#define SETUP_TOKEN_JOY_YUPPER 5
+#define SETUP_TOKEN_JOY_YMIDDLE 6
+#define SETUP_TOKEN_JOY_YLOWER 7
+#define SETUP_TOKEN_JOY_SNAP 8
+#define SETUP_TOKEN_JOY_BOMB 9
+#define SETUP_TOKEN_KEY_LEFT 10
+#define SETUP_TOKEN_KEY_RIGHT 11
+#define SETUP_TOKEN_KEY_UP 12
+#define SETUP_TOKEN_KEY_DOWN 13
+#define SETUP_TOKEN_KEY_SNAP 14
+#define SETUP_TOKEN_KEY_BOMB 15
+
+#define NUM_PLAYER_SETUP_TOKENS 16
static struct SetupInfo si;
+static struct SetupShortcutInfo ssi;
static struct SetupInputInfo sii;
-static struct LevelDirInfo ldi;
-static struct TokenInfo token_info[] =
+
+static struct TokenInfo global_setup_tokens[] =
{
/* global setup */
- { 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.scroll_delay, "scroll_delay" },
- { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
- { TYPE_SWITCH, &si.fading, "screen_fading" },
- { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
- { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
- { TYPE_SWITCH, &si.team_mode, "team_mode" },
- { TYPE_SWITCH, &si.handicap, "handicap" },
- { TYPE_SWITCH, &si.time_limit, "time_limit" },
- { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
+ { 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_SWITCH, &si.soft_scrolling, "soft_scrolling" },
+ { TYPE_SWITCH, &si.fading, "screen_fading" },
+ { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
+ { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
+ { TYPE_SWITCH, &si.team_mode, "team_mode" },
+ { TYPE_SWITCH, &si.handicap, "handicap" },
+ { TYPE_SWITCH, &si.time_limit, "time_limit" },
+ { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
+ { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
+ { TYPE_STRING, &si.graphics_set, "graphics_set" },
+ { TYPE_STRING, &si.sounds_set, "sounds_set" },
+ { TYPE_STRING, &si.music_set, "music_set" },
+ { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
+ { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
+ { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
+};
+
+static struct TokenInfo shortcut_setup_tokens[] =
+{
+ /* shortcut setup */
+ { 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" }
+};
+static struct TokenInfo player_setup_tokens[] =
+{
/* player setup */
{ TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
{ TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
{ TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
{ TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
{ TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
- { TYPE_KEY, &sii.key.left, ".key.move_left" },
- { TYPE_KEY, &sii.key.right, ".key.move_right" },
- { TYPE_KEY, &sii.key.up, ".key.move_up" },
- { TYPE_KEY, &sii.key.down, ".key.move_down" },
- { TYPE_KEY, &sii.key.snap, ".key.snap_field" },
- { TYPE_KEY, &sii.key.bomb, ".key.place_bomb" },
-
- /* level directory info */
- { TYPE_STRING, &ldi.name, "name" },
- { TYPE_STRING, &ldi.name_short, "name_short" },
- { TYPE_STRING, &ldi.name_sorting, "name_sorting" },
- { TYPE_STRING, &ldi.author, "author" },
- { TYPE_STRING, &ldi.imported_from, "imported_from" },
- { TYPE_INTEGER, &ldi.levels, "levels" },
- { TYPE_INTEGER, &ldi.first_level, "first_level" },
- { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" },
- { TYPE_BOOLEAN, &ldi.level_group, "level_group" },
- { TYPE_BOOLEAN, &ldi.readonly, "readonly" }
+ { 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.bomb, ".key.place_bomb" }
};
-static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
-{
- ldi->filename = NULL;
- ldi->fullpath = NULL;
- ldi->basepath = NULL;
- ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
- ldi->name_sorting = NULL;
- ldi->author = getStringCopy(ANONYMOUS_NAME);
- ldi->imported_from = NULL;
- ldi->levels = 0;
- ldi->first_level = 0;
- ldi->last_level = 0;
- ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */
- ldi->level_group = FALSE;
- ldi->parent_link = FALSE;
- ldi->user_defined = FALSE;
- ldi->readonly = TRUE;
- ldi->color = 0;
- ldi->class_desc = NULL;
- ldi->handicap_level = 0;
- ldi->cl_first = -1;
- ldi->cl_cursor = -1;
-
- ldi->node_parent = NULL;
- ldi->node_group = NULL;
- ldi->next = NULL;
-}
-
-static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi,
- struct LevelDirInfo *parent)
-{
- if (parent == NULL)
- {
- setLevelDirInfoToDefaults(ldi);
- return;
- }
-
- /* first copy all values from the parent structure ... */
- *ldi = *parent;
-
- /* ... then set all fields to default that cannot be inherited from parent.
- This is especially important for all those fields that can be set from
- the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
- calls 'free()' for all already set token values which requires that no
- other structure's pointer may point to them!
- */
-
- ldi->filename = NULL;
- ldi->fullpath = NULL;
- ldi->basepath = NULL;
- ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
- ldi->name_sorting = NULL;
- ldi->author = getStringCopy(parent->author);
- ldi->imported_from = getStringCopy(parent->imported_from);
-
- ldi->level_group = FALSE;
- ldi->parent_link = FALSE;
-
- ldi->node_parent = parent;
- ldi->node_group = NULL;
- ldi->next = NULL;
-}
-
static void setSetupInfoToDefaults(struct SetupInfo *si)
{
int i;
si->handicap = TRUE;
si->time_limit = TRUE;
si->fullscreen = FALSE;
+ si->ask_on_escape = TRUE;
+
+ si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
+ si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
+ si->music_set = getStringCopy(MUSIC_SUBDIR);
+ si->override_level_graphics = FALSE;
+ si->override_level_sounds = FALSE;
+ si->override_level_music = 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;
for (i=0; i<MAX_PLAYERS; i++)
{
si->input[i].use_joystick = FALSE;
- si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]);
+ 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;
}
}
-static void setSetupInfo(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_string_boolean_value(token_value);
- break;
-
- case TYPE_KEY:
- *(Key *)setup_value = getKeyFromX11KeyName(token_value);
- break;
-
- case TYPE_INTEGER:
- *(int *)setup_value = get_string_integer_value(token_value);
- break;
-
- case TYPE_STRING:
- if (*(char **)setup_value != NULL)
- free(*(char **)setup_value);
- *(char **)setup_value = getStringCopy(token_value);
- break;
-
- default:
- break;
- }
-}
-
static void decodeSetupFileList(struct SetupFileList *setup_file_list)
{
int i, pnr;
if (!setup_file_list)
return;
- /* handle global setup values */
+ /* global setup */
si = setup;
- for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
- setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
+ for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
+ setSetupInfo(global_setup_tokens, i,
+ getTokenValue(setup_file_list, global_setup_tokens[i].text));
setup = si;
- /* handle player specific setup values */
+ /* shortcut setup */
+ ssi = setup.shortcut;
+ for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
+ setSetupInfo(shortcut_setup_tokens, i,
+ getTokenValue(setup_file_list,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=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
+ for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
{
char full_token[100];
- sprintf(full_token, "%s%s", prefix, token_info[i].text);
- setSetupInfo(i, getTokenValue(setup_file_list, full_token));
+ sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
+ setSetupInfo(player_setup_tokens, i,
+ getTokenValue(setup_file_list, full_token));
}
setup.input[pnr] = sii;
}
}
-static int compareLevelDirInfoEntries(const void *object1, const void *object2)
-{
- const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1);
- const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2);
- int compare_result;
-
- 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 (LEVELSORTING(entry1) == LEVELSORTING(entry2))
- compare_result = entry1->sort_priority - entry2->sort_priority;
- else
- compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2);
-
- return compare_result;
-}
-
-static void createParentLevelDirNode(struct LevelDirInfo *node_parent)
-{
- struct LevelDirInfo *leveldir_new = newLevelDirInfo();
-
- setLevelDirInfoToDefaults(leveldir_new);
-
- leveldir_new->node_parent = node_parent;
- leveldir_new->parent_link = TRUE;
-
- leveldir_new->name = ".. (parent directory)";
- leveldir_new->name_short = getStringCopy(leveldir_new->name);
- leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
- leveldir_new->filename = "..";
- leveldir_new->fullpath = getStringCopy(node_parent->fullpath);
-
- leveldir_new->sort_priority = node_parent->sort_priority;
- leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
- pushLevelDirInfo(&node_parent->node_group, leveldir_new);
-}
-
-static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first,
- struct LevelDirInfo *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 SetupFileList *setup_file_list = NULL;
- struct stat file_status;
- char *directory_name = dir_entry->d_name;
- char *directory_path = getPath2(level_directory, directory_name);
- char *filename = NULL;
-
- /* skip entries for current and parent directory */
- if (strcmp(directory_name, ".") == 0 ||
- strcmp(directory_name, "..") == 0)
- {
- 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;
- }
-
- filename = getPath2(directory_path, LEVELINFO_FILENAME);
- setup_file_list = loadSetupFileList(filename);
-
- if (setup_file_list)
- {
- struct LevelDirInfo *leveldir_new = newLevelDirInfo();
- int i;
-
- checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE);
- setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent);
-
- /* set all structure fields according to the token/value pairs */
- ldi = *leveldir_new;
- for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
- setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
- *leveldir_new = ldi;
-
- DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-
- if (leveldir_new->name_short == NULL)
- leveldir_new->name_short = getStringCopy(leveldir_new->name);
-
- if (leveldir_new->name_sorting == NULL)
- leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
- leveldir_new->filename = getStringCopy(directory_name);
-
- if (node_parent == NULL) /* top level group */
- {
- leveldir_new->basepath = level_directory;
- leveldir_new->fullpath = leveldir_new->filename;
- }
- else /* sub level group */
- {
- leveldir_new->basepath = node_parent->basepath;
- leveldir_new->fullpath = getPath2(node_parent->fullpath,
- directory_name);
- }
-
- if (leveldir_new->levels < 1)
- leveldir_new->levels = 1;
-
- leveldir_new->last_level =
- leveldir_new->first_level + leveldir_new->levels - 1;
-
- leveldir_new->user_defined =
- (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
-
- leveldir_new->color = LEVELCOLOR(leveldir_new);
- leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
- leveldir_new->handicap_level = /* set handicap to default value */
- (leveldir_new->user_defined ?
- leveldir_new->last_level :
- leveldir_new->first_level);
-
- pushLevelDirInfo(node_first, leveldir_new);
-
- freeSetupFileList(setup_file_list);
- valid_entry_found = TRUE;
-
- if (leveldir_new->level_group)
- {
- /* create node to link back to current level directory */
- createParentLevelDirNode(leveldir_new);
-
- /* step into sub-directory and look for more level series */
- LoadLevelInfoFromLevelDir(&leveldir_new->node_group,
- leveldir_new, directory_path);
- }
- }
- else
- Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
-
- free(directory_path);
- free(filename);
- }
-
- closedir(dir);
-
- if (!valid_entry_found)
- Error(ERR_WARN, "cannot find any valid level series in directory '%s'",
- level_directory);
-}
-
-void LoadLevelInfo()
-{
- InitUserLevelDirectory(getLoginName());
-
- DrawInitText("Loading level series:", 120, FC_GREEN);
-
- LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
- LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(""));
-
- leveldir_current = getFirstValidLevelSeries(leveldir_first);
-
- if (leveldir_first == NULL)
- Error(ERR_EXIT, "cannot find any valid level series in any directory");
-
- sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries);
-
-#if 0
- dumpLevelDirInfo(leveldir_first, 0);
-#endif
-}
-
-static void SaveUserLevelInfo()
-{
- 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;
- }
-
- /* always start with reliable default values */
- setLevelDirInfoToDefaults(&ldi);
-
- ldi.name = getLoginName();
- ldi.author = getRealName();
- ldi.levels = 100;
- ldi.first_level = 1;
- ldi.sort_priority = LEVELCLASS_USER_START;
- ldi.readonly = FALSE;
-
- fprintf(file, "%s\n\n",
- getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE));
-
- for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
- if (i != LEVELINFO_TOKEN_NAME_SHORT &&
- i != LEVELINFO_TOKEN_NAME_SORTING &&
- i != LEVELINFO_TOKEN_IMPORTED_FROM)
- fprintf(file, "%s\n", getSetupLine("", i));
-
- fclose(file);
- free(filename);
-
- SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
void LoadSetup()
{
- char *filename;
+ char *filename = getSetupFilename();
struct SetupFileList *setup_file_list = NULL;
/* always start with reliable default values */
setSetupInfoToDefaults(&setup);
- filename = getPath2(getSetupDir(), SETUP_FILENAME);
-
setup_file_list = loadSetupFileList(filename);
if (setup_file_list)
{
- checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
+ checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
decodeSetupFileList(setup_file_list);
setup.direct_draw = !setup.double_buffering;
}
else
Error(ERR_WARN, "using default setup values");
-
- free(filename);
-}
-
-static char *getSetupLine(char *prefix, int token_nr)
-{
- int i;
- static char entry[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;
-
- /* start with the prefix, token and some spaces to format output line */
- sprintf(entry, "%s%s:", prefix, token_text);
- for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
- strcat(entry, " ");
-
- /* continue with the token's value (which can have different types) */
- switch (token_type)
- {
- case TYPE_BOOLEAN:
- strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
- break;
-
- case TYPE_SWITCH:
- strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
- break;
-
- case TYPE_KEY:
- {
- Key key = *(Key *)setup_value;
- char *keyname = getKeyNameFromKey(key);
-
- strcat(entry, getX11KeyNameFromKey(key));
- for (i=strlen(entry); i<50; i++)
- strcat(entry, " ");
-
- /* add comment, if useful */
- if (strcmp(keyname, "(undefined)") != 0 &&
- strcmp(keyname, "(unknown)") != 0)
- {
- strcat(entry, "# ");
- strcat(entry, keyname);
- }
- }
- break;
-
- case TYPE_INTEGER:
- {
- char buffer[MAX_LINE_LEN];
-
- sprintf(buffer, "%d", *(int *)setup_value);
- strcat(entry, buffer);
- }
- break;
-
- case TYPE_STRING:
- strcat(entry, *(char **)setup_value);
- break;
-
- default:
- break;
- }
-
- return entry;
}
void SaveSetup()
{
- int i, pnr;
- char *filename;
+ char *filename = getSetupFilename();
FILE *file;
+ int i, pnr;
InitUserDataDirectory();
- filename = getPath2(getSetupDir(), SETUP_FILENAME);
-
if (!(file = fopen(filename, MODE_WRITE)))
{
Error(ERR_WARN, "cannot write setup file '%s'", filename);
- free(filename);
return;
}
- fprintf(file, "%s\n",
- getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
+ fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+ getCookie("SETUP")));
fprintf(file, "\n");
- /* handle global setup values */
+ /* global setup */
si = setup;
- for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
+ for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
{
- fprintf(file, "%s\n", getSetupLine("", i));
+ fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
/* just to make things nicer :) */
- if (i == SETUP_TOKEN_PLAYER_NAME)
+ if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
fprintf(file, "\n");
}
- /* handle player specific setup values */
+ /* 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];
fprintf(file, "\n");
sii = setup.input[pnr];
- for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
- fprintf(file, "%s\n", getSetupLine(prefix, i));
+ for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
}
fclose(file);
- free(filename);
-
- SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-void LoadLevelSetup_LastSeries()
-{
- char *filename;
- struct SetupFileList *level_setup_list = NULL;
-
- /* always start with reliable default values */
- leveldir_current = getFirstValidLevelSeries(leveldir_first);
-
- /* ----------------------------------------------------------------------- */
- /* ~/.rocksndiamonds/levelsetup.conf */
- /* ----------------------------------------------------------------------- */
-
- filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
-
- if ((level_setup_list = loadSetupFileList(filename)))
- {
- char *last_level_series =
- getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
-
- leveldir_current = getLevelDirInfoFromFilename(last_level_series);
- if (leveldir_current == NULL)
- leveldir_current = leveldir_first;
-
- checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
-
- freeSetupFileList(level_setup_list);
- }
- else
- Error(ERR_WARN, "using default setup values");
-
- free(filename);
-}
-
-void SaveLevelSetup_LastSeries()
-{
- char *filename;
- char *level_subdir = leveldir_current->filename;
- FILE *file;
-
- /* ----------------------------------------------------------------------- */
- /* ~/.rocksndiamonds/levelsetup.conf */
- /* ----------------------------------------------------------------------- */
-
- InitUserDataDirectory();
-
- filename = getPath2(getSetupDir(), 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,
- LEVELSETUP_COOKIE));
- fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
- level_subdir));
-
- fclose(file);
- free(filename);
-
- SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-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->user_defined ?
- getUserLevelDir("") :
- 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] == '.' &&
- strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
- {
- 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 (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;
- }
- }
- }
-
- closedir(dir);
-}
-
-void LoadLevelSetup_SeriesInfo()
-{
- char *filename;
- struct SetupFileList *level_setup_list = NULL;
- char *level_subdir = leveldir_current->filename;
-
- /* always start with reliable default values */
- level_nr = leveldir_current->first_level;
-
- checkSeriesInfo(leveldir_current);
-
- /* ----------------------------------------------------------------------- */
- /* ~/.rocksndiamonds/levelsetup/<level series>/levelsetup.conf */
- /* ----------------------------------------------------------------------- */
-
- level_subdir = leveldir_current->filename;
-
- filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
-
- if ((level_setup_list = loadSetupFileList(filename)))
- {
- char *token_value;
-
- token_value = getTokenValue(level_setup_list, 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 = getTokenValue(level_setup_list, 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)
- level_nr = leveldir_current->last_level;
-
- leveldir_current->handicap_level = level_nr;
- }
-
- checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
-
- freeSetupFileList(level_setup_list);
- }
- else
- Error(ERR_WARN, "using default setup values");
-
- free(filename);
-}
-
-void SaveLevelSetup_SeriesInfo()
-{
- char *filename;
- char *level_subdir = leveldir_current->filename;
- char *level_nr_str = int2str(level_nr, 0);
- char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
- FILE *file;
-
- /* ----------------------------------------------------------------------- */
- /* ~/.rocksndiamonds/levelsetup/<level series>/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,
- LEVELSETUP_COOKIE));
- 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);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
}
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
void LoadScore(int);
void SaveScore(int);
-void LoadLevelInfo(void);
void LoadSetup(void);
void SaveSetup(void);
-void LoadLevelSetup_LastSeries(void);
-void SaveLevelSetup_LastSeries(void);
-void LoadLevelSetup_SeriesInfo(void);
-void SaveLevelSetup_SeriesInfo(void);
#endif /* FILES_H */
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "init.h"
#include "files.h"
#include "tape.h"
-#include "joystick.h"
#include "network.h"
/* this switch controls how rocks move horizontally */
#define DX_TIME (DX + XX_TIME)
#define DY_TIME (DY + YY_TIME)
-#define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \
- (s)==SND_NJAM || (s)==SND_MIEP)
-#define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
- (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
- (s)==SND_TYGER || (s)==SND_VOYAGER || \
- (s)==SND_TWILIGHT)
+/* 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_NORMAL_SPEED 8
static void CheckGravityMovement(struct PlayerInfo *);
static void KillHeroUnlessProtected(int, int);
+void PlaySoundLevel(int, int, int);
+void PlaySoundLevelAction(int, int, int);
+void PlaySoundLevelElementAction(int, int, int, int);
+
static void MapGameButtons();
static void HandleGameButtons(struct GadgetInfo *);
static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
+#define SND_ACTION_UNKNOWN 0
+#define SND_ACTION_WAITING 1
+#define SND_ACTION_MOVING 2
+#define SND_ACTION_DIGGING 3
+#define SND_ACTION_COLLECTING 4
+#define SND_ACTION_PASSING 5
+#define SND_ACTION_IMPACT 6
+#define SND_ACTION_PUSHING 7
+#define SND_ACTION_ACTIVATING 8
+#define SND_ACTION_BURNING 9
+
+#define NUM_SND_ACTIONS 10
+
+static struct
+{
+ char *text;
+ int value;
+ boolean is_loop;
+} sound_action_properties[] =
+{
+ /* insert _all_ loop sound actions here */
+ { ".waiting", SND_ACTION_WAITING, TRUE },
+ { ".moving", SND_ACTION_MOVING, TRUE }, /* continuos moving */
+ { ".running", SND_ACTION_UNKNOWN, TRUE },
+ { ".burning", SND_ACTION_BURNING, TRUE },
+ { ".growing", SND_ACTION_UNKNOWN, TRUE },
+ { ".attacking", SND_ACTION_UNKNOWN, TRUE },
+ { ".activated", SND_ACTION_UNKNOWN, TRUE },
+
+ /* other (non-loop) sound actions are optional */
+ { ".stepping", SND_ACTION_MOVING, FALSE }, /* discrete moving */
+ { ".digging", SND_ACTION_DIGGING, FALSE },
+ { ".collecting", SND_ACTION_COLLECTING, FALSE },
+ { ".passing", SND_ACTION_PASSING, FALSE },
+ { ".impact", SND_ACTION_IMPACT, FALSE },
+ { ".pushing", SND_ACTION_PUSHING, FALSE },
+ { ".activating", SND_ACTION_ACTIVATING, FALSE },
+ { NULL, 0, 0 },
+};
+static int element_action_sound[NUM_LEVEL_ELEMENTS][NUM_SND_ACTIONS];
+static boolean is_loop_sound[NUM_SOUND_EFFECTS];
+
+#define IS_LOOP_SOUND(x) (is_loop_sound[x])
#ifdef DEBUG
setup.sound = FALSE;
if (!audio.loops_available)
- {
setup.sound_loops = FALSE;
+
+ if (!audio.music_available)
setup.sound_music = FALSE;
- }
if (!video.fullscreen_available)
setup.fullscreen = FALSE;
}
}
+void DrawGameDoorValues()
+{
+ int i, j;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ for (j=0; j<4; j++)
+ if (stored_player[i].key[j])
+ DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS,
+ GFX_SCHLUESSEL1 + j);
+
+ DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
+ int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
+ int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_SCORE, DY + YY_SCORE,
+ int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_TIME, DY + YY_TIME,
+ int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+}
+
+
+/*
+ =============================================================================
+ InitGameSound()
+ -----------------------------------------------------------------------------
+ initialize sound effect lookup table for element actions
+ =============================================================================
+*/
+
+void InitGameSound()
+{
+ int sound_effect_properties[NUM_SOUND_EFFECTS];
+ int i, j;
+
+#if 0
+ debug_print_timestamp(0, NULL);
+#endif
+
+ for (i=0; i<NUM_SND_ACTIONS; i++)
+ for (j=0; j<NUM_LEVEL_ELEMENTS; j++)
+ element_action_sound[j][i] = -1;
+
+ for (i=0; i<NUM_SOUND_EFFECTS; i++)
+ {
+ int len_effect_text = strlen(sound_effects[i].text);
+
+ sound_effect_properties[i] = SND_ACTION_UNKNOWN;
+ is_loop_sound[i] = FALSE;
+
+ /* determine all loop sounds and identify certain sound classes */
+
+ j = 0;
+ while (sound_action_properties[j].text)
+ {
+ int len_action_text = strlen(sound_action_properties[j].text);
+
+ if (len_action_text < len_effect_text &&
+ strcmp(&sound_effects[i].text[len_effect_text - len_action_text],
+ sound_action_properties[j].text) == 0)
+ {
+ sound_effect_properties[i] = sound_action_properties[j].value;
+
+ if (sound_action_properties[j].is_loop)
+ is_loop_sound[i] = TRUE;
+ }
+
+ j++;
+ }
+
+ /* associate elements and some selected sound actions */
+
+ for (j=0; j<NUM_LEVEL_ELEMENTS; j++)
+ {
+ if (element_info[j].sound_class_name)
+ {
+ int len_class_text = strlen(element_info[j].sound_class_name);
+
+ if (len_class_text + 1 < len_effect_text &&
+ strncmp(sound_effects[i].text,
+ element_info[j].sound_class_name, len_class_text) == 0 &&
+ sound_effects[i].text[len_class_text] == '.')
+ {
+ int sound_action_value = sound_effect_properties[i];
+
+ element_action_sound[j][sound_action_value] = i;
+ }
+ }
+ }
+ }
+
+#if 0
+ debug_print_timestamp(0, "InitGameEngine");
+#endif
+
+#if 0
+ /* TEST ONLY */
+ {
+ int element = EL_ERDREICH;
+ int sound_action = SND_ACTION_DIGGING;
+ int j = 0;
+
+ while (sound_action_properties[j].text)
+ {
+ if (sound_action_properties[j].value == sound_action)
+ printf("element %d, sound action '%s' == %d\n",
+ element, sound_action_properties[j].text,
+ element_action_sound[element][sound_action]);
+ j++;
+ }
+ }
+#endif
+}
+
+
+/*
+ =============================================================================
+ InitGameEngine()
+ -----------------------------------------------------------------------------
+ initialize game engine due to level / tape version number
+ =============================================================================
+*/
+
+static void InitGameEngine()
+{
+ int i;
+
+ game.engine_version = (tape.playing ? tape.engine_version :
+ level.game_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
+
+ /* dynamically adjust player properties according to game engine version */
+ game.initial_move_delay =
+ (game.engine_version <= VERSION_IDENT(2,0,1) ? INITIAL_MOVE_DELAY_ON :
+ INITIAL_MOVE_DELAY_OFF);
+
+ /* dynamically adjust player properties according to level information */
+ game.initial_move_delay_value =
+ (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
+
+ /* dynamically adjust element properties according to game engine version */
+ {
+ static int ep_em_slippery_wall[] =
+ {
+ EL_BETON,
+ EL_MAUERWERK,
+ EL_MAUER_LEBT,
+ EL_MAUER_X,
+ EL_MAUER_Y,
+ EL_MAUER_XY
+ };
+ static int ep_em_slippery_wall_num = SIZEOF_ARRAY_INT(ep_em_slippery_wall);
+
+ for (i=0; i<ep_em_slippery_wall_num; i++)
+ {
+ if (level.em_slippery_gems) /* special EM style gems behaviour */
+ Elementeigenschaften2[ep_em_slippery_wall[i]] |=
+ EP_BIT_EM_SLIPPERY_WALL;
+ else
+ Elementeigenschaften2[ep_em_slippery_wall[i]] &=
+ ~EP_BIT_EM_SLIPPERY_WALL;
+ }
+
+ /* "EL_MAUERND" was not slippery for EM gems in version 2.0.1 */
+ if (level.em_slippery_gems && game.engine_version > VERSION_IDENT(2,0,1))
+ Elementeigenschaften2[EL_MAUERND] |= EP_BIT_EM_SLIPPERY_WALL;
+ else
+ Elementeigenschaften2[EL_MAUERND] &= ~EP_BIT_EM_SLIPPERY_WALL;
+ }
+}
+
+
+/*
+ =============================================================================
+ InitGame()
+ -----------------------------------------------------------------------------
+ initialize and start new game
+ =============================================================================
+*/
+
void InitGame()
{
- int i, j, x, y;
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 */
+ int i, j, x, y;
+
+ InitGameEngine();
#if DEBUG
#if USE_NEW_AMOEBA_CODE
player->frame_reset_delay = 0;
- player->push_delay = 0;
- player->push_delay_value = 5;
-
- player->move_delay = 0;
player->last_move_dir = MV_NO_MOVING;
player->is_moving = FALSE;
- player->move_delay_value =
- (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
+ player->move_delay = game.initial_move_delay;
+ player->move_delay_value = game.initial_move_delay_value;
+
+ player->push_delay = 0;
+ player->push_delay_value = 5;
player->snapped = FALSE;
}
}
+ game.emulation = (emulate_bd ? EMU_BOULDERDASH :
+ emulate_sb ? EMU_SOKOBAN :
+ emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
+
/* correct non-moving belts to start moving left */
for (i=0; i<4; i++)
if (game.belt_dir[i] == MV_NO_MOVING)
}
}
- game.version = (tape.playing ? tape.game_version : level.game_version);
- game.emulation = (emulate_bd ? EMU_BOULDERDASH :
- emulate_sb ? EMU_SOKOBAN :
- emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
-
- /* dynamically adjust element properties according to game engine version */
- {
- static int ep_slippery[] =
- {
- EL_BETON,
- EL_MAUERWERK,
- EL_MAUER_LEBT,
- EL_MAUER_X,
- EL_MAUER_Y,
- EL_MAUER_XY
- };
- static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int);
-
- for (i=0; i<ep_slippery_num; i++)
- {
- if (game.version >= GAME_VERSION_2_0)
- Elementeigenschaften2[ep_slippery[i]] |= EP_BIT_SLIPPERY_GEMS;
- else
- Elementeigenschaften2[ep_slippery[i]] &= ~EP_BIT_SLIPPERY_GEMS;
- }
- }
-
if (BorderElement == EL_LEERRAUM)
{
SBX_Left = 0;
DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
}
- DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
- int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
- DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
- int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
- DrawText(DX + XX_SCORE, DY + YY_SCORE,
- int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
- DrawText(DX + XX_TIME, DY + YY_TIME,
- int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+ DrawGameDoorValues();
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;
OpenDoor(DOOR_OPEN_ALL);
- if (setup.sound_music && num_bg_loops)
- PlayMusic(level_nr % num_bg_loops);
+ PlaySoundStereo(SND_GAME_STARTING, SOUND_MAX_RIGHT);
+ if (setup.sound_music)
+ PlayMusic(level_nr);
KeyboardAutoRepeatOff();
local_player->LevelSolved = FALSE;
+ PlaySoundStereo(SND_GAME_WINNING, SOUND_MAX_RIGHT);
+
if (TimeLeft)
{
if (!tape.playing && setup.sound_loops)
- PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
+ PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
+ SND_CTRL_PLAY_LOOP);
- while(TimeLeft > 0)
+ while (TimeLeft > 0)
{
if (!tape.playing && !setup.sound_loops)
- PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_RIGHT);
if (TimeLeft > 0 && !(TimeLeft % 10))
RaiseScore(level.score[SC_ZEITBONUS]);
if (TimeLeft > 100 && !(TimeLeft % 10))
}
if (!tape.playing && setup.sound_loops)
- StopSound(SND_SIRR);
+ StopSound(SND_GAME_LEVELTIME_BONUS);
}
else if (level.time == 0) /* level without time limit */
{
if (!tape.playing && setup.sound_loops)
- PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
+ PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
+ SND_CTRL_PLAY_LOOP);
- while(TimePlayed < 999)
+ while (TimePlayed < 999)
{
if (!tape.playing && !setup.sound_loops)
- PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_RIGHT);
if (TimePlayed < 999 && !(TimePlayed % 10))
RaiseScore(level.score[SC_ZEITBONUS]);
if (TimePlayed < 900 && !(TimePlayed % 10))
}
if (!tape.playing && setup.sound_loops)
- StopSound(SND_SIRR);
+ StopSound(SND_GAME_LEVELTIME_BONUS);
}
#if 0
MovDelay[x][y]--;
if (MovDelay[x][y])
{
- if (!(MovDelay[x][y] % 12))
- PlaySoundLevel(x, y, SND_ZISCH);
+ if (!(MovDelay[x][y] % 6))
+ PlaySoundLevelAction(x, y, SND_ACTION_BURNING);
if (IS_ACTIVE_BOMB(Feld[x][y]))
{
}
}
- StopSound(SND_ZISCH);
+ if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
+ StopSound(SND_DYNAMITE_BURNING);
+ else
+ StopSound(SND_DYNABOMB_BURNING);
+
Bang(x, y);
}
int element = Feld[x][y];
if (game.emulation == EMU_SUPAPLEX)
- PlaySoundLevel(x, y, SND_SP_BOOOM);
+ PlaySoundLevel(x, y, SND_SP_ELEMENT_EXPLODING);
else
- PlaySoundLevel(x, y, SND_ROAAAR);
+ PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING);
#if 0
if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT) /* start */
{
- PlaySoundLevel(x, y, SND_BLURB);
+ PlaySoundLevel(x, y, SND_ACID_SPLASHING);
if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
(!IN_LEV_FIELD(x-1, y-1) ||
!CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
element == EL_SWITCHGATE_OPENING)
{
Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
- PlaySoundLevel(xx, yy, SND_OEFFNEN);
+ PlaySoundLevel(xx, yy, SND_SWITCHGATE_CLOSING);
}
else if (element == EL_SWITCHGATE_CLOSED ||
element == EL_SWITCHGATE_CLOSING)
{
Feld[xx][yy] = EL_SWITCHGATE_OPENING;
- PlaySoundLevel(xx, yy, SND_OEFFNEN);
+ PlaySoundLevel(xx, yy, SND_SWITCHGATE_OPENING);
}
}
}
element == EL_TIMEGATE_CLOSING)
{
Feld[xx][yy] = EL_TIMEGATE_OPENING;
- PlaySoundLevel(xx, yy, SND_OEFFNEN);
+ PlaySoundLevel(xx, yy, SND_TIMEGATE_OPENING);
}
/*
else if (element == EL_PEARL)
{
Feld[x][y] = EL_PEARL_BREAKING;
- PlaySoundLevel(x, y, SND_KNACK);
+ PlaySoundLevel(x, y, SND_PEARL_BREAKING);
return;
}
if (CAN_CHANGE(element) &&
(smashed == EL_MAGIC_WALL_OFF || smashed == EL_MAGIC_WALL_BD_OFF))
{
- int x, y;
+ int xx, yy;
int activated_magic_wall =
(smashed == EL_MAGIC_WALL_OFF ? EL_MAGIC_WALL_EMPTY :
EL_MAGIC_WALL_BD_EMPTY);
/* activate magic wall / mill */
-
- for (y=0; y<lev_fieldy; y++)
- for (x=0; x<lev_fieldx; x++)
- if (Feld[x][y] == smashed)
- Feld[x][y] = activated_magic_wall;
+ for (yy=0; yy<lev_fieldy; yy++)
+ for (xx=0; xx<lev_fieldx; xx++)
+ 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;
+
+ PlaySoundLevel(x, y, (smashed == EL_MAGIC_WALL_OFF ?
+ SND_MAGIC_WALL_ACTIVATING :
+ SND_BD_MAGIC_WALL_ACTIVATING));
}
if (IS_PLAYER(x, y+1))
else if (smashed == EL_KOKOSNUSS)
{
Feld[x][y+1] = EL_CRACKINGNUT;
- PlaySoundLevel(x, y, SND_KNACK);
+ PlaySoundLevel(x, y, SND_NUT_CRACKING);
RaiseScoreElement(EL_KOKOSNUSS);
return;
}
else if (smashed == EL_PEARL)
{
Feld[x][y+1] = EL_PEARL_BREAKING;
- PlaySoundLevel(x, y, SND_KNACK);
+ PlaySoundLevel(x, y, SND_PEARL_BREAKING);
return;
}
else if (smashed == EL_DIAMANT)
{
Feld[x][y+1] = EL_LEERRAUM;
- PlaySoundLevel(x, y, SND_QUIRK);
+ PlaySoundLevel(x, y, SND_DIAMOND_BREAKING);
return;
}
else if (IS_BELT_SWITCH(smashed))
(Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
{
- PlaySoundLevel(x, y, SND_QUIRK);
+ if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY)
+ PlaySoundLevel(x, y, SND_MAGIC_WALL_CHANGING);
+ else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)
+ PlaySoundLevel(x, y, SND_BD_MAGIC_WALL_CHANGING);
+
return;
}
/* play sound of object that hits the ground */
if (lastline || object_hit)
- {
- int sound;
-
- switch(element)
- {
- case EL_EDELSTEIN:
- case EL_EDELSTEIN_BD:
- case EL_EDELSTEIN_GELB:
- case EL_EDELSTEIN_ROT:
- case EL_EDELSTEIN_LILA:
- case EL_DIAMANT:
- case EL_SP_INFOTRON:
- sound = SND_PLING;
- break;
- case EL_KOKOSNUSS:
- sound = SND_KLUMPF;
- break;
- case EL_FELSBROCKEN:
- case EL_BD_ROCK:
- sound = SND_KLOPF;
- break;
- case EL_SP_ZONK:
- sound = SND_SP_ZONKDOWN;
- break;
- case EL_SCHLUESSEL:
- case EL_SCHLUESSEL1:
- case EL_SCHLUESSEL2:
- case EL_SCHLUESSEL3:
- case EL_SCHLUESSEL4:
- case EL_EM_KEY_1:
- case EL_EM_KEY_2:
- case EL_EM_KEY_3:
- case EL_EM_KEY_4:
- sound = SND_KINK;
- break;
- case EL_ZEIT_VOLL:
- case EL_ZEIT_LEER:
- sound = SND_DENG;
- break;
- default:
- sound = -1;
- break;
- }
-
- if (sound >= 0)
- PlaySoundLevel(x, y, sound);
- }
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_IMPACT);
}
void TurnRound(int x, int y)
InitMovingField(x, y, MV_DOWN);
Feld[x][y] = EL_QUICKSAND_EMPTYING;
Store[x][y] = EL_FELSBROCKEN;
+ PlaySoundLevel(x, y, SND_QUICKSAND_EMPTYING);
}
else if (Feld[x][y+1] == EL_MORAST_LEER)
{
Feld[x][y+1] = EL_MORAST_VOLL;
Store[x][y+1] = Store[x][y];
Store[x][y] = 0;
+ PlaySoundLevel(x, y, SND_QUICKSAND_SLIPPING_THROUGH);
}
}
else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) &&
InitMovingField(x, y, MV_DOWN);
Feld[x][y] = EL_QUICKSAND_FILLING;
Store[x][y] = element;
+ PlaySoundLevel(x, y, SND_QUICKSAND_FILLING);
}
else if (element == EL_MAGIC_WALL_FULL)
{
#endif
#else
else if ((IS_SLIPPERY(Feld[x][y+1]) ||
- (IS_SLIPPERY_GEMS(Feld[x][y+1]) && IS_GEM(element))) &&
+ (IS_EM_SLIPPERY_WALL(Feld[x][y+1]) && IS_GEM(element))) &&
!IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
#endif
if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
{
TurnRound(x, y);
+
if (MovDelay[x][y] && (element == EL_KAEFER ||
element == EL_FLIEGER ||
element == EL_SP_SNIKSNAK ||
{
int phase = MovDelay[x][y] % 8;
- if (phase>3)
- phase = 7-phase;
+ if (phase > 3)
+ phase = 7 - phase;
if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
- DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
+ DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element) + phase);
- if ((element == EL_MAMPFER || element == EL_MAMPFER2)
- && MovDelay[x][y]%4 == 3)
- PlaySoundLevel(x, y, SND_NJAM);
+ if (MovDelay[x][y] % 4 == 3)
+ {
+ if (element == EL_MAMPFER)
+ PlaySoundLevel(x, y, SND_YAMYAM_WAITING);
+ else if (element == EL_MAMPFER2)
+ PlaySoundLevel(x, y, SND_DARK_YAMYAM_WAITING);
+ }
}
else if (element == EL_SP_ELECTRON)
DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
}
}
- if (MovDelay[x][y])
- return;
- }
+ if (MovDelay[x][y]) /* element still has to wait some time */
+ {
+ PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
- if (element == EL_KAEFER || element == EL_BUTTERFLY)
- {
- PlaySoundLevel(x, y, SND_KLAPPER);
- }
- else if (element == EL_FLIEGER || element == EL_FIREFLY)
- {
- PlaySoundLevel(x, y, SND_ROEHR);
+ return;
+ }
}
/* now make next step */
Feld[x][y] = EL_LEERRAUM;
DrawLevelField(x, y);
- PlaySoundLevel(newx, newy, SND_BUING);
+ PlaySoundLevel(newx, newy, SND_PENGUIN_ENTERING_EXIT);
if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
Feld[newx][newy] = EL_LEERRAUM;
DrawLevelField(newx, newy);
}
+
+ PlaySoundLevel(x, y, SND_PIG_EATING_GEM);
}
else if (!IS_FREE(newx, newy))
{
else
DrawLevelField(x, y);
+ PlaySoundLevel(x, y, SND_DRAGON_ATTACKING);
+
MovDelay[x][y] = 50;
Feld[newx][newy] = EL_BURNING;
if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
Feld[newx][newy] = EL_LEERRAUM;
DrawLevelField(newx, newy);
}
+
+ PlaySoundLevel(x, y, SND_YAMYAM_EATING_DIAMOND);
}
else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
IS_MAMPF2(Feld[newx][newy]))
Feld[newx][newy] = EL_LEERRAUM;
DrawLevelField(newx, newy);
}
+
+ PlaySoundLevel(x, y, SND_DARK_YAMYAM_EATING_ANY);
}
else if ((element == EL_PACMAN || element == EL_MOLE)
&& IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
if (element == EL_MOLE)
{
Feld[newx][newy] = EL_DEAMOEBING;
+ PlaySoundLevel(x, y, SND_MOLE_EATING_AMOEBA);
MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */
return; /* wait for shrinking amoeba */
}
{
Feld[newx][newy] = EL_LEERRAUM;
DrawLevelField(newx, newy);
+ PlaySoundLevel(x, y, SND_PACMAN_EATING_AMOEBA);
}
}
else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
if (DONT_TOUCH(element))
TestIfBadThingTouchesHero(x, y);
+ PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
+
return;
}
- if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
- PlaySoundLevel(x, y, SND_SCHLURF);
-
InitMovingField(x, y, MovDir[x][y]);
+
+ PlaySoundLevelAction(x, y, SND_ACTION_MOVING);
}
if (MovDir[x][y])
MovPos[x][y] += step;
- if (ABS(MovPos[x][y])>=TILEX) /* object reached its destination */
+ if (ABS(MovPos[x][y]) >= TILEX) /* object reached its destination */
{
Feld[x][y] = EL_LEERRAUM;
Feld[newx][newy] = element;
}
}
}
+ PlaySoundLevel(ax, ay, (IS_GEM(level.amoeba_content) ?
+ SND_AMOEBA_TURNING_TO_GEM :
+ SND_AMOEBA_TURNING_TO_ROCK));
Bang(ax, ay);
}
else
continue;
if (Feld[x][y] == EL_AMOEBA2DIAM)
+ {
+ PlaySoundLevel(x, y, (IS_GEM(level.amoeba_content) ?
+ SND_AMOEBA_TURNING_TO_GEM :
+ SND_AMOEBA_TURNING_TO_ROCK));
Bang(x, y);
+ }
}
}
}
}
if (done)
- PlaySoundLevel(ax, ay,
- (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING));
+ PlaySoundLevel(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)
if (DelayReached(&sound_delay, sound_delay_value))
{
- PlaySoundLevel(x, y, SND_AMOEBE);
+ if (Store[x][y] == EL_AMOEBE_BD)
+ PlaySoundLevel(x, y, SND_BD_AMOEBA_CREATING);
+ else
+ PlaySoundLevel(x, y, SND_AMOEBA_CREATING);
sound_delay_value = 30;
}
}
}
}
-void AmoebeSchrumpft(int x, int y)
+void AmoebaDisappearing(int x, int y)
{
static unsigned long sound_delay = 0;
static unsigned long sound_delay_value = 0;
MovDelay[x][y] = 7;
if (DelayReached(&sound_delay, sound_delay_value))
- {
- PlaySoundLevel(x, y, SND_BLURB);
sound_delay_value = 30;
- }
}
if (MovDelay[x][y]) /* wait some time before shrinking */
Store[newax][neway] = element;
}
else if (neway == ay)
+ {
Feld[newax][neway] = EL_TROPFEN; /* drop left or right from amoeba */
+ PlaySoundLevel(newax, neway, SND_AMOEBA_DROPPING);
+ }
else
{
InitMovingField(ax, ay, MV_DOWN); /* drop dripping out of amoeba */
static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
int life_time = 40;
int element = Feld[ax][ay];
+ boolean changed = FALSE;
if (Stop[ax][ay])
return;
if (xx == ax && yy == ay) /* field in the middle */
{
- if (nachbarn<life[0] || nachbarn>life[1])
+ if (nachbarn < life[0] || nachbarn > life[1])
{
Feld[xx][yy] = EL_LEERRAUM;
if (!Stop[xx][yy])
DrawLevelField(xx, yy);
Stop[xx][yy] = TRUE;
+ changed = TRUE;
}
}
else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
{ /* free border field */
- if (nachbarn>=life[2] && nachbarn<=life[3])
+ if (nachbarn >= life[2] && nachbarn <= life[3])
{
Feld[xx][yy] = element;
MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
if (!Stop[xx][yy])
DrawLevelField(xx, yy);
Stop[xx][yy] = TRUE;
+ changed = TRUE;
}
}
}
+
+ if (changed)
+ PlaySoundLevel(ax, ay, element == EL_LIFE ? SND_GAMEOFLIFE_CREATING :
+ SND_BIOMAZE_CREATING);
}
-void Ablenk(int x, int y)
+void RobotWheel(int x, int y)
{
if (!MovDelay[x][y]) /* next animation frame */
MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
if (!(MovDelay[x][y]%4))
- PlaySoundLevel(x, y, SND_MIEP);
+ PlaySoundLevel(x, y, SND_ROBOT_WHEEL_RUNNING);
return;
}
}
DrawGraphic(SCREENX(x), SCREENY(y),
GFX_TIMEGATE_SWITCH + MovDelay[x][y]%4);
if (!(MovDelay[x][y]%4))
- PlaySoundLevel(x, y, SND_MIEP);
+ PlaySoundLevel(x, y, SND_TIMEGATE_WHEEL_RUNNING);
return;
}
}
(x > LEVELX(BX2) ? LEVELX(BX2) : x),
y < LEVELY(BY1) ? LEVELY(BY1) :
(y > LEVELY(BY2) ? LEVELY(BY2) : y),
- SND_OEFFNEN);
+ SND_EXIT_OPENING);
}
}
if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
{
Feld[x][y] = EL_TIMEGATE_CLOSING;
- PlaySoundLevel(x, y, SND_OEFFNEN);
+ PlaySoundLevel(x, y, SND_TIMEGATE_CLOSING);
}
}
}
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 (!MovDelay[ax][ay]) /* start building new wall */
MovDelay[ax][ay] = 6;
MovDir[ax][ay-1] = MV_UP;
if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
+ new_wall = TRUE;
}
if (unten_frei)
{
MovDir[ax][ay+1] = MV_DOWN;
if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
+ new_wall = TRUE;
}
}
MovDir[ax-1][ay] = MV_LEFT;
if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
+ new_wall = TRUE;
}
+
if (rechts_frei)
{
Feld[ax+1][ay] = EL_MAUERND;
MovDir[ax+1][ay] = MV_RIGHT;
if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
+ new_wall = TRUE;
}
}
((links_massiv && rechts_massiv) ||
element == EL_MAUER_Y))
Feld[ax][ay] = EL_MAUERWERK;
+
+ if (new_wall)
+ PlaySoundLevel(ax, ay, SND_WALL_GROWING);
}
void CheckForDragon(int x, int y)
if (IS_PLAYER(xx, yy))
{
- PlaySoundLevel(x, y, SND_SP_BUG);
+ PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVATING);
break;
}
}
return;
Feld[x][y] = EL_TRAP_ACTIVE;
+ PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
}
}
else if (element == EL_TRAP_ACTIVE)
int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
+
+ if (!(FrameCounter % 2))
+ PlaySoundLevel(x, y, SND_CONVEYOR_BELT_RUNNING);
}
}
moved = MoveFigure(player, dx, dy);
}
+ if (tape.single_step && tape.recording && !tape.pausing)
+ {
+ if (button1 || (bombed && !moved))
+ {
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+ SnapField(player, 0, 0); /* stop snapping */
+ }
+ }
+
#if 0
if (tape.recording && (moved || snapped || bombed))
{
action_delay_value =
(tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
+ if (tape.playing && tape.index_search && !tape.pausing)
+ action_delay_value = 0;
+
/* ---------- main game synchronization point ---------- */
WaitUntilDelayReached(&action_delay, action_delay_value);
if (tape.pausing)
return;
- if (tape.playing)
- TapePlayDelay();
- else if (tape.recording)
- TapeRecordDelay();
-
recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
for (i=0; i<MAX_PLAYERS; i++)
else if (element == EL_AMOEBING)
AmoebeWaechst(x, y);
else if (element == EL_DEAMOEBING)
- AmoebeSchrumpft(x, y);
+ AmoebaDisappearing(x, y);
#if !USE_NEW_AMOEBA_CODE
else if (IS_AMOEBALIVE(element))
else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
Life(x, y);
else if (element == EL_ABLENK_EIN)
- Ablenk(x, y);
+ RobotWheel(x, y);
else if (element == EL_TIMEGATE_SWITCH_ON)
TimegateWheel(x, y);
else if (element == EL_SALZSAEURE)
else if (element == EL_EXTRA_TIME)
DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
else if (element == EL_SHIELD_PASSIVE)
+ {
DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL);
+#if 0
+ if (!(FrameCounter % 4))
+ PlaySoundLevel(x, y, SND_SHIELD_PASSIVE_ACTIVATED);
+#endif
+ }
else if (element == EL_SHIELD_ACTIVE)
+ {
DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL);
+#if 0
+ if (!(FrameCounter % 4))
+ PlaySoundLevel(x, y, SND_SHIELD_ACTIVE_ACTIVATED);
+#endif
+ }
if (game.magic_wall_active)
{
if (game.magic_wall_active)
{
if (!(game.magic_wall_time_left % 4))
- PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
+ {
+ int element = Feld[sieb_x][sieb_y];
+
+ if (element == EL_MAGIC_WALL_BD_FULL ||
+ element == EL_MAGIC_WALL_BD_EMPTY ||
+ element == EL_MAGIC_WALL_BD_EMPTYING)
+ PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_RUNNING);
+ else
+ PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_RUNNING);
+ }
if (game.magic_wall_time_left > 0)
{
CloseAllOpenTimegates();
}
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ if (SHIELD_ON(player))
+ {
+ if (player->shield_active_time_left)
+ PlaySoundLevel(player->jx, player->jy, SND_SHIELD_ACTIVE_ACTIVATED);
+ else if (player->shield_passive_time_left)
+ PlaySoundLevel(player->jx, player->jy, SND_SHIELD_PASSIVE_ACTIVATED);
+ }
+ }
+
if (TimeFrames >= (1000 / GameFrameDelay))
{
TimeFrames = 0;
for (i=0; i<MAX_PLAYERS; i++)
{
- if (SHIELD_ON(&stored_player[i]))
+ struct PlayerInfo *player = &stored_player[i];
+
+ if (SHIELD_ON(player))
{
- stored_player[i].shield_passive_time_left--;
+ player->shield_passive_time_left--;
- if (stored_player[i].shield_active_time_left > 0)
- stored_player[i].shield_active_time_left--;
+ if (player->shield_active_time_left > 0)
+ player->shield_active_time_left--;
}
}
TimeLeft--;
if (TimeLeft <= 10 && setup.time_limit)
- PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MAX_RIGHT);
DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
for (i=0; i<MAX_PLAYERS; i++)
KillHero(&stored_player[i]);
}
- else if (level.time == 0) /* level without time limit */
+ else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
}
(Feld[new_jx][new_jy] == EL_SP_BASE ||
Feld[new_jx][new_jy] == EL_ERDREICH));
- if (field_under_player_is_free && !player_is_moving_to_valid_field)
+ if (field_under_player_is_free &&
+ !player_is_moving_to_valid_field &&
+ !IS_TUBE(Feld[jx][jy]))
player->programmed_action = MV_DOWN;
}
}
if (!local_player->friends_still_needed)
player->LevelSolved = player->GameOver = TRUE;
}
+
+ if (tape.single_step && tape.recording && !tape.pausing &&
+ !player->programmed_action)
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
}
}
if (!player->active)
return;
- PlaySoundLevel(jx, jy, SND_AUTSCH);
- PlaySoundLevel(jx, jy, SND_LACHEN);
+ PlaySoundLevel(jx, jy, SND_PLAYER_DYING);
+ PlaySoundLevel(jx, jy, SND_GAME_LOSING);
player->GameOver = TRUE;
RemoveHero(player);
dy == +1 ? MV_DOWN : MV_NO_MOVING);
int element;
- if (!player->MovPos)
+ if (player->MovPos == 0)
player->Pushing = FALSE;
if (mode == DF_NO_PUSH)
switch (element)
{
case EL_LEERRAUM:
- PlaySoundLevel(x, y, SND_EMPTY);
- break;
-
case EL_ERDREICH:
case EL_SAND_INVISIBLE:
case EL_TRAP_INACTIVE:
- Feld[x][y] = EL_LEERRAUM;
- PlaySoundLevel(x, y, SND_SCHLURF);
- break;
-
case EL_SP_BASE:
case EL_SP_BUG:
- Feld[x][y] = EL_LEERRAUM;
- PlaySoundLevel(x, y, SND_SP_BASE);
+ RemoveField(x, y);
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_DIGGING);
break;
case EL_EDELSTEIN:
DrawText(DX_EMERALDS, DY_EMERALDS,
int2str(local_player->gems_still_needed, 3),
FS_SMALL, FC_YELLOW);
- if (element == EL_SP_INFOTRON)
- PlaySoundLevel(x, y, SND_SP_INFOTRON);
- else
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
break;
case EL_SPEED_PILL:
RemoveField(x, y);
player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
break;
case EL_ENVELOPE:
Feld[x][y] = EL_LEERRAUM;
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
break;
case EL_EXTRA_TIME:
TimeLeft += 10;
DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
}
- PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MAX_RIGHT);
break;
case EL_SHIELD_PASSIVE:
RemoveField(x, y);
player->shield_passive_time_left += 10;
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_SHIELD_PASSIVE_COLLECTING);
break;
case EL_SHIELD_ACTIVE:
RemoveField(x, y);
player->shield_passive_time_left += 10;
player->shield_active_time_left += 10;
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_SHIELD_ACTIVE_COLLECTING);
break;
case EL_DYNAMITE_INACTIVE:
DrawText(DX_DYNAMITE, DY_DYNAMITE,
int2str(local_player->dynamite, 3),
FS_SMALL, FC_YELLOW);
- if (element == EL_SP_DISK_RED)
- PlaySoundLevel(x, y, SND_SP_INFOTRON);
- else
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
break;
case EL_DYNABOMB_NR:
player->dynabomb_count++;
player->dynabombs_left++;
RaiseScoreElement(EL_DYNAMITE_INACTIVE);
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_DYNABOMB_NR_COLLECTING);
break;
case EL_DYNABOMB_SZ:
RemoveField(x, y);
player->dynabomb_size++;
RaiseScoreElement(EL_DYNAMITE_INACTIVE);
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_DYNABOMB_SZ_COLLECTING);
break;
case EL_DYNABOMB_XL:
RemoveField(x, y);
player->dynabomb_xl = TRUE;
RaiseScoreElement(EL_DYNAMITE_INACTIVE);
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_DYNABOMB_XL_COLLECTING);
break;
case EL_SCHLUESSEL1:
GFX_SCHLUESSEL1 + key_nr);
DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
GFX_SCHLUESSEL1 + key_nr);
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_KEY_COLLECTING);
break;
}
GFX_SCHLUESSEL1 + key_nr);
DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
GFX_SCHLUESSEL1 + key_nr);
- PlaySoundLevel(x, y, SND_PONG);
+ PlaySoundLevel(x, y, SND_KEY_COLLECTING);
break;
}
ZX = x;
ZY = y;
DrawLevelField(x, y);
+ PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING);
return MF_ACTION;
break;
{
int xx, yy;
+ PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
+
for (yy=0; yy<lev_fieldy; yy++)
{
for (xx=0; xx<lev_fieldx; xx++)
{
player->Switching = TRUE;
ToggleBeltSwitch(x, y);
+ PlaySoundLevel(x, y, SND_CONVEYOR_BELT_SWITCH_ACTIVATING);
}
return MF_ACTION;
break;
{
player->Switching = TRUE;
ToggleSwitchgateSwitch(x, y);
+ PlaySoundLevel(x, y, SND_SWITCHGATE_SWITCH_ACTIVATING);
}
return MF_ACTION;
break;
{
player->Switching = TRUE;
ToggleLightSwitch(x, y);
+ PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH_OFF ?
+ SND_LIGHT_SWITCH_ACTIVATING :
+ SND_LIGHT_SWITCH_DEACTIVATING);
}
return MF_ACTION;
break;
case EL_TIMEGATE_SWITCH_OFF:
ActivateTimegateSwitch(x, y);
+ PlaySoundLevel(x, y, SND_TIMEGATE_WHEEL_ACTIVATING);
return MF_ACTION;
break;
element == EL_BALLOON_SEND_UP ? MV_UP :
element == EL_BALLOON_SEND_DOWN ? MV_DOWN :
MV_NO_MOVING);
+ PlaySoundLevel(x, y, SND_BALLOON_SWITCH_ACTIVATING);
return MF_ACTION;
break;
return MF_NO_ACTION;
player->LevelSolved = player->GameOver = TRUE;
- PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_SP_EXIT_ENTERING, SOUND_MAX_RIGHT);
break;
+ /* the following elements cannot be pushed by "snapping" */
case EL_FELSBROCKEN:
- case EL_BD_ROCK:
case EL_BOMBE:
case EL_DX_SUPABOMB:
case EL_KOKOSNUSS:
case EL_SP_ZONK:
case EL_SP_DISK_ORANGE:
case EL_SPRING:
- if (dy || mode == DF_SNAP)
+ if (mode == DF_SNAP)
+ return MF_NO_ACTION;
+ /* no "break" -- fall through to next case */
+ /* the following elements can be pushed by "snapping" */
+ case EL_BD_ROCK:
+ if (dy)
return MF_NO_ACTION;
player->Pushing = TRUE;
return MF_NO_ACTION;
#endif
- RemoveField(x, y);
- Feld[x+dx][y+dy] = element;
+ if (mode == DF_SNAP)
+ {
+ InitMovingField(x, y, move_direction);
+ ContinueMoving(x, y);
+ }
+ else
+ {
+ RemoveField(x, y);
+ Feld[x+dx][y+dy] = element;
+ }
if (element == EL_SPRING)
{
player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
DrawLevelField(x+dx, y+dy);
- if (element == EL_FELSBROCKEN || element == EL_BD_ROCK)
- PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
- else if (element == EL_KOKOSNUSS)
- PlaySoundLevel(x+dx, y+dy, SND_KNURK);
- else if (IS_SP_ELEMENT(element))
- PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
- else
- PlaySoundLevel(x+dx, y+dy, SND_PUSCH); /* better than "SND_KLOPF" */
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
break;
case EL_PFORTE1:
player->programmed_action = move_direction;
DOUBLE_PLAYER_SPEED(player);
- PlaySoundLevel(x, y, SND_GATE);
-
+ PlaySoundLevel(x, y, SND_GATE_PASSING);
break;
case EL_EM_GATE_1X:
player->programmed_action = move_direction;
DOUBLE_PLAYER_SPEED(player);
- PlaySoundLevel(x, y, SND_GATE);
-
+ PlaySoundLevel(x, y, SND_GATE_PASSING);
break;
case EL_SWITCHGATE_OPEN:
player->programmed_action = move_direction;
DOUBLE_PLAYER_SPEED(player);
- PlaySoundLevel(x, y, SND_GATE);
-
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_PASSING);
break;
case EL_SP_PORT1_LEFT:
player->programmed_action = move_direction;
DOUBLE_PLAYER_SPEED(player);
- PlaySoundLevel(x, y, SND_GATE);
+ PlaySoundLevel(x, y, SND_SP_PORT_PASSING);
break;
case EL_TUBE_CROSS:
if (!(tube_enter_directions[i][1] & move_direction))
return MF_NO_ACTION; /* tube has no opening in this direction */
+
+ PlaySoundLevel(x, y, SND_TUBE_PASSING);
}
break;
if (mode == DF_SNAP)
return MF_NO_ACTION;
- PlaySoundLevel(x, y, SND_BUING);
+ PlaySoundLevel(x, y, SND_EXIT_ENTERING);
break;
Feld[x][y] = EL_BIRNE_EIN;
local_player->lights_still_needed--;
DrawLevelField(x, y);
- PlaySoundLevel(x, y, SND_DENG);
+ PlaySoundLevel(x, y, SND_LAMP_ACTIVATING);
return MF_ACTION;
break;
TimeLeft += 10;
DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
DrawLevelField(x, y);
- PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+ PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MAX_RIGHT);
return MF_ACTION;
break;
case EL_SOKOBAN_FELD_LEER:
break;
- case EL_SOKOBAN_FELD_VOLL:
case EL_SOKOBAN_OBJEKT:
+ case EL_SOKOBAN_FELD_VOLL:
case EL_SONDE:
case EL_SP_DISK_YELLOW:
case EL_BALLOON:
Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
local_player->sokobanfields_still_needed--;
if (element == EL_SOKOBAN_OBJEKT)
- PlaySoundLevel(x, y, SND_DENG);
+ PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_FILLING);
+ else
+ PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
}
else
+ {
Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
+ if (element == EL_SOKOBAN_FELD_VOLL)
+ PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_CLEARING);
+ else
+ PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
+ }
}
else
{
RemoveField(x, y);
Feld[x+dx][y+dy] = element;
+ PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
}
player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
DrawLevelField(x, y);
DrawLevelField(x+dx, y+dy);
- if (element == EL_BALLOON)
- PlaySoundLevel(x+dx, y+dy, SND_SCHLURF);
- else
- PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
if (IS_SB_ELEMENT(element) &&
local_player->sokobanfields_still_needed == 0 &&
game.emulation == EMU_SOKOBAN)
{
player->LevelSolved = player->GameOver = TRUE;
- PlaySoundLevel(x, y, SND_BUING);
+ PlaySoundLevel(x, y, SND_SOKOBAN_GAME_SOLVING);
}
break;
if (!dx && !dy)
{
+ if (player->MovPos == 0)
+ player->Pushing = FALSE;
+
player->snapped = FALSE;
return FALSE;
}
else
DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
}
+
+ PlaySoundLevel(jx, jy, SND_DYNAMITE_PLACING);
}
else
{
player->dynabombs_left--;
if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
+
+ PlaySoundLevel(jx, jy, SND_DYNABOMB_PLACING);
}
return TRUE;
}
-void PlaySoundLevel(int x, int y, int sound_nr)
+void PlaySoundLevel(int x, int y, int nr)
{
+ static int loop_sound_frame[NUM_SOUND_EFFECTS];
+ static int loop_sound_volume[NUM_SOUND_EFFECTS];
int sx = SCREENX(x), sy = SCREENY(y);
- int volume, stereo;
- int silence_distance = 8;
+ 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(sound_nr)) ||
- (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
+ if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
+ (!setup.sound_loops && IS_LOOP_SOUND(nr)))
return;
if (!IN_LEV_FIELD(x, y) ||
- sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
- sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
+ sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
+ sy < -max_distance || sy >= SCR_FIELDY + max_distance)
return;
- volume = PSND_MAX_VOLUME;
-
-#if !defined(PLATFORM_MSDOS)
- stereo = (sx - SCR_FIELDX/2) * 12;
-#else
- stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
- if (stereo > PSND_MAX_RIGHT)
- stereo = PSND_MAX_RIGHT;
- if (stereo < PSND_MAX_LEFT)
- stereo = PSND_MAX_LEFT;
-#endif
+ 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;
+ 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) / silence_distance;
+ volume -= volume * (dx > dy ? dx : dy) / max_distance;
}
- PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
+ 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);
+}
+
+void PlaySoundLevelAction(int x, int y, int sound_action)
+{
+ PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action);
+}
+
+void PlaySoundLevelElementAction(int x, int y, int element, int sound_action)
+{
+ int sound_effect = element_action_sound[element][sound_action];
+
+ if (sound_effect != -1)
+ PlaySoundLevel(x, y, sound_effect);
}
void RaiseScore(int value)
}
}
+void RequestQuitGame(boolean ask_if_really_quit)
+{
+ if (AllPlayersGone ||
+ !ask_if_really_quit ||
+ level_editor_test_game ||
+ Request("Do you really want to quit the game ?",
+ REQ_ASK | REQ_STAY_CLOSED))
+ {
+#if defined(PLATFORM_UNIX)
+ if (options.network)
+ SendToServer_StopPlaying();
+ else
+#endif
+ {
+ game_status = MAINMENU;
+ DrawMainMenu();
+ }
+ }
+ else
+ {
+ OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+ }
+}
+
+
/* ---------- new game button stuff ---------------------------------------- */
/* graphic position values for game buttons */
switch (id)
{
case GAME_CTRL_ID_STOP:
- if (AllPlayersGone)
- {
- CloseDoor(DOOR_CLOSE_1);
- game_status = MAINMENU;
- DrawMainMenu();
- break;
- }
-
- if (level_editor_test_game ||
- Request("Do you really want to quit the game ?",
- REQ_ASK | REQ_STAY_CLOSED))
- {
-#if defined(PLATFORM_UNIX)
- if (options.network)
- SendToServer_StopPlaying();
- else
-#endif
- {
- game_status = MAINMENU;
- DrawMainMenu();
- }
- }
- else
- OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+ RequestQuitGame(TRUE);
break;
case GAME_CTRL_ID_PAUSE:
#endif
}
else
- TapeTogglePause();
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
break;
case GAME_CTRL_ID_PLAY:
setup.sound_music = FALSE;
FadeMusic();
}
- else if (audio.loops_available)
+ else if (audio.music_available)
{
setup.sound = setup.sound_music = TRUE;
- if (num_bg_loops)
- PlayMusic(level_nr % num_bg_loops);
+ PlayMusic(level_nr);
}
break;
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#define SC_ZEITBONUS 10
void GetPlayerConfig(void);
+void DrawGameDoorValues(void);
+void InitGameSound();
void InitGame(void);
void InitMovDir(int, int);
void InitAmoebaNr(int, int);
int DigField(struct PlayerInfo *, int, int, int, int, int);
boolean SnapField(struct PlayerInfo *, int, int);
boolean PlaceBomb(struct PlayerInfo *);
-void PlaySoundLevel(int, int, int);
void RaiseScore(int);
void RaiseScoreElement(int);
+void RequestQuitGame(boolean);
void CreateGameButtons();
void UnmapGameButtons();
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "tape.h"
#include "tools.h"
#include "files.h"
-#include "joystick.h"
#include "network.h"
#include "netserv.h"
+#include "cartoons.h"
+#include "config.h"
+static char *image_filename[NUM_PICTURES] =
+{
+ "RocksScreen.pcx",
+ "RocksDoor.pcx",
+ "RocksHeroes.pcx",
+ "RocksToons.pcx",
+ "RocksSP.pcx",
+ "RocksDC.pcx",
+ "RocksMore.pcx",
+ "RocksFont.pcx",
+ "RocksFont2.pcx",
+ "RocksFont3.pcx"
+};
+
+static void InitSetup(void);
static void InitPlayerInfo(void);
static void InitLevelInfo(void);
+static void InitArtworkInfo(void);
+static void InitLevelArtworkInfo(void);
static void InitNetworkServer(void);
+static void InitMixer(void);
static void InitSound(void);
static void InitGfx(void);
static void InitGfxBackground(void);
static void InitGadgets(void);
static void InitElementProperties(void);
+static void Execute_Debug_Command(char *);
void OpenAll(void)
{
+ if (options.debug_command)
+ {
+ Execute_Debug_Command(options.debug_command);
+
+ exit(0);
+ }
+
if (options.serveronly)
{
#if defined(PLATFORM_UNIX)
}
InitProgramInfo(UNIX_USERDATA_DIRECTORY,
- PROGRAM_TITLE_STRING, WINDOW_TITLE_STRING,
+ PROGRAM_TITLE_STRING, getWindowTitleString(),
ICON_TITLE_STRING, X11_ICON_FILENAME, X11_ICONMASK_FILENAME,
- MSDOS_POINTER_FILENAME);
+ MSDOS_POINTER_FILENAME,
+ COOKIE_PREFIX, FILENAME_PREFIX, GAME_VERSION_ACTUAL);
+ InitSetup();
InitPlayerInfo();
+ InitArtworkInfo(); /* needed before loading gfx, sound & music */
InitCounter();
- InitSound();
+ InitMixer();
InitJoysticks();
InitRND(NEW_RANDOMIZE);
InitElementProperties(); /* initializes IS_CHAR() for el2gfx() */
InitLevelInfo();
+ InitLevelArtworkInfo();
InitGadgets(); /* needs to know number of level series */
+ InitSound(); /* needs to know current level directory */
InitGfxBackground();
+ InitToons();
+
DrawMainMenu();
InitNetworkServer();
}
+void InitSetup()
+{
+ LoadSetup(); /* global setup info */
+}
+
void InitPlayerInfo()
{
int i;
local_player = &stored_player[0];
for (i=0; i<MAX_PLAYERS; i++)
- {
- stored_player[i].joystick_fd = -1; /* joystick device closed */
stored_player[i].connected = FALSE;
- }
local_player->connected = TRUE;
-
- LoadSetup(); /* global setup info */
}
void InitLevelInfo()
LoadLevelSetup_SeriesInfo(); /* last played level info */
}
+void InitArtworkInfo()
+{
+ LoadArtworkInfo();
+}
+
+void InitLevelArtworkInfo()
+{
+ LoadLevelArtworkInfo();
+}
+
void InitNetworkServer()
{
#if defined(PLATFORM_UNIX)
#endif
}
-void InitSound()
+static void InitMixer()
{
- int i;
-
OpenAudio();
+ InitSoundList(sound_effects, NUM_SOUND_EFFECTS);
- for(i=0; i<NUM_SOUNDS; i++)
- {
- if (!LoadSound(sound_name[i]))
- {
- audio.sound_available = FALSE;
- audio.loops_available = FALSE;
- audio.sound_enabled = FALSE;
-
- return;
- }
- }
-
- num_bg_loops = LoadMusic();
-
- StartSoundserver();
+ StartMixer();
}
-void InitJoysticks()
+static void InitSound()
{
-#if defined(TARGET_SDL)
- static boolean sdl_joystick_subsystem_initialized = FALSE;
-#endif
-
- int i;
-
- if (global_joystick_status == JOYSTICK_OFF)
- return;
-
- joystick_status = JOYSTICK_OFF;
-
-#if defined(TARGET_SDL)
-
- 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++)
- {
- char *device_name = setup.input[i].joy.device_name;
- int joystick_nr = getJoystickNrFromDeviceName(device_name);
-
- if (joystick_nr >= SDL_NumJoysticks())
- joystick_nr = -1;
-
- /* misuse joystick file descriptor variable to store joystick number */
- stored_player[i].joystick_fd = joystick_nr;
-
- /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
- if (Check_SDL_JoystickOpened(joystick_nr))
- Close_SDL_Joystick(joystick_nr);
-
- if (!setup.input[i].use_joystick)
- continue;
-
- if (!Open_SDL_Joystick(joystick_nr))
- {
- Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
- continue;
- }
-
- joystick_status = JOYSTICK_AVAILABLE;
- }
-
-#else /* !TARGET_SDL */
-
-#if defined(PLATFORM_UNIX)
- 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 (stored_player[i].joystick_fd != -1)
- {
- close(stored_player[i].joystick_fd);
- stored_player[i].joystick_fd = -1;
- }
-
- if (!setup.input[i].use_joystick)
- continue;
-
- if (access(device_name, R_OK) != 0)
- {
- Error(ERR_WARN, "cannot access joystick device '%s'", device_name);
- continue;
- }
-
- if ((stored_player[i].joystick_fd = open(device_name, O_RDONLY)) < 0)
- {
- Error(ERR_WARN, "cannot open joystick device '%s'", device_name);
- continue;
- }
-
- joystick_status = JOYSTICK_AVAILABLE;
- }
-
-#else /* !PLATFORM_UNIX */
-
- /* 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_AVAILABLE;
-
- /*
- load_joystick_data(JOYSTICK_FILENAME);
- */
-
- 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 */
- stored_player[i].joystick_fd = joystick_nr;
- }
-#endif
+ /* load custom sounds and music */
+ InitReloadSounds(artwork.snd_current->name);
+ InitReloadMusic(artwork.mus_current->name);
-#endif /* !TARGET_SDL */
+ /* initialize sound effect lookup table for element actions */
+ InitGameSound();
}
-void InitGfx()
+static void InitTileClipmasks()
{
- int i;
-
#if defined(TARGET_X11)
- GC copy_clipmask_gc;
XGCValues clip_gc_values;
unsigned long clip_gc_valuemask;
-#endif
-
-#if !defined(PLATFORM_MSDOS)
- static char *image_filename[NUM_PICTURES] =
- {
- "RocksScreen.pcx",
- "RocksDoor.pcx",
- "RocksHeroes.pcx",
- "RocksToons.pcx",
- "RocksSP.pcx",
- "RocksDC.pcx",
- "RocksMore.pcx",
- "RocksFont.pcx",
- "RocksFont2.pcx",
- "RocksFont3.pcx"
- };
-#else
- static char *image_filename[NUM_PICTURES] =
- {
- "Screen.pcx",
- "Door.pcx",
- "Heroes.pcx",
- "Toons.pcx",
- "SP.pcx",
- "DC.pcx",
- "More.pcx",
- "Font.pcx",
- "Font2.pcx",
- "Font3.pcx"
- };
-#endif
#if defined(TARGET_X11_NATIVE)
+ GC copy_clipmask_gc;
+
static struct
{
int start;
{ GFX2_SHIELD_ACTIVE, 3 },
{ -1, 0 }
};
-#endif
-
- /* initialize some global variables */
- global.frames_per_second = 0;
- global.fps_slowdown = FALSE;
- global.fps_slowdown_factor = 1;
-
- /* initialize screen properties */
- InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
- REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
- InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
- InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
- InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
-
- /* create additional image buffers for double-buffering */
- pix[PIX_DB_DOOR] = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
- pix[PIX_DB_FIELD] = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
-
- pix[PIX_SMALLFONT] = LoadImage(image_filename[PIX_SMALLFONT]);
- InitFontInfo(NULL, NULL, pix[PIX_SMALLFONT]);
-
- DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
- DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
-#if defined(PLATFORM_MSDOS)
- DrawInitText(PROGRAM_DOS_PORT_STRING, 210, FC_BLUE);
- rest(200);
-#endif
- DrawInitText("Loading graphics:",120,FC_GREEN);
-
- for(i=0; i<NUM_PICTURES; i++)
- {
- if (i != PIX_SMALLFONT)
- {
- DrawInitText(image_filename[i], 150, FC_YELLOW);
- pix[i] = LoadImage(image_filename[i]);
- }
- }
+#endif /* TARGET_X11_NATIVE */
+#endif /* TARGET_X11 */
- InitFontInfo(pix[PIX_BIGFONT], pix[PIX_MEDIUMFONT], pix[PIX_SMALLFONT]);
+ int i;
/* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
for(i=0; i<NUM_TILES; i++)
To prevent this, create small (tile-sized) mask Pixmaps which will then
be set much faster with XSetClipOrigin() and speed things up a lot. */
- /* create graphic context structures needed for clipping */
- clip_gc_values.graphics_exposures = False;
- clip_gc_valuemask = GCGraphicsExposures;
- copy_clipmask_gc =
- XCreateGC(display, pix[PIX_BACK]->clip_mask,
- clip_gc_valuemask, &clip_gc_values);
-
clip_gc_values.graphics_exposures = False;
clip_gc_valuemask = GCGraphicsExposures;
tile_clip_gc =
clip_gc_values.clip_mask = pix[i]->clip_mask;
clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
- clip_gc_valuemask,&clip_gc_values);
+ clip_gc_valuemask, &clip_gc_values);
}
}
#if defined(TARGET_X11_NATIVE)
+
+ /* create graphic context structures needed for clipping */
+ clip_gc_values.graphics_exposures = False;
+ clip_gc_valuemask = GCGraphicsExposures;
+ copy_clipmask_gc =
+ XCreateGC(display, pix[PIX_BACK]->clip_mask,
+ clip_gc_valuemask, &clip_gc_values);
+
/* create only those clipping Pixmaps we really need */
for(i=0; tile_needs_clipping[i].start>=0; i++)
{
src_x, src_y, TILEX, TILEY, 0, 0);
}
}
+
+ XFreeGC(display, copy_clipmask_gc);
+
#endif /* TARGET_X11_NATIVE */
#endif /* TARGET_X11 */
}
+void FreeTileClipmasks()
+{
+#if defined(TARGET_X11)
+ int i;
+
+ for(i=0; i<NUM_TILES; i++)
+ {
+ if (tile_clipmask[i] != None)
+ {
+ XFreePixmap(display, tile_clipmask[i]);
+ tile_clipmask[i] = None;
+ }
+ }
+
+ if (tile_clip_gc)
+ XFreeGC(display, tile_clip_gc);
+ tile_clip_gc = None;
+
+ for(i=0; i<NUM_BITMAPS; i++)
+ {
+ if (pix[i] != NULL && pix[i]->stored_clip_gc)
+ {
+ XFreeGC(display, pix[i]->stored_clip_gc);
+ pix[i]->stored_clip_gc = None;
+ }
+ }
+#endif /* TARGET_X11 */
+}
+
+void InitGfx()
+{
+ int i;
+
+ /* initialize some global variables */
+ global.frames_per_second = 0;
+ global.fps_slowdown = FALSE;
+ global.fps_slowdown_factor = 1;
+
+ /* initialize screen properties */
+ InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
+ REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+ InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
+ InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+ InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+
+ /* create additional image buffers for double-buffering */
+ pix[PIX_DB_DOOR] = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
+ pix[PIX_DB_FIELD] = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
+
+ pix[PIX_SMALLFONT] = LoadCustomImage(image_filename[PIX_SMALLFONT]);
+
+ InitFontInfo(NULL, NULL, pix[PIX_SMALLFONT]);
+
+ DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
+ DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
+
+ DrawInitText("Loading graphics:", 120, FC_GREEN);
+
+ for(i=0; i<NUM_PICTURES; i++)
+ {
+ if (i != PIX_SMALLFONT)
+ {
+ DrawInitText(image_filename[i], 150, FC_YELLOW);
+
+ pix[i] = LoadCustomImage(image_filename[i]);
+ }
+ }
+
+ InitFontInfo(pix[PIX_BIGFONT], pix[PIX_MEDIUMFONT], pix[PIX_SMALLFONT]);
+
+ InitTileClipmasks();
+}
+
void InitGfxBackground()
{
int x, y;
fieldbuffer = pix[PIX_DB_FIELD];
SetDrawtoField(DRAW_BACKBUFFER);
- BlitBitmap(pix[PIX_BACK], backbuffer, 0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
- ClearRectangle(backbuffer, REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
- ClearRectangle(pix[PIX_DB_DOOR], 0,0, 3*DXSIZE,DYSIZE+VYSIZE);
+ BlitBitmap(pix[PIX_BACK], backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+ ClearRectangle(pix[PIX_DB_DOOR], 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
for(x=0; x<MAX_BUF_XSIZE; x++)
for(y=0; y<MAX_BUF_YSIZE; y++)
redraw_mask = REDRAW_ALL;
}
+void ReloadCustomArtwork()
+{
+ static char *leveldir_current_filename = NULL;
+ static boolean last_override_level_graphics = FALSE;
+ static boolean last_override_level_sounds = FALSE;
+ static boolean last_override_level_music = FALSE;
+
+ if (leveldir_current_filename != leveldir_current->filename)
+ {
+ char *filename_old = leveldir_current_filename;
+ char *filename_new = leveldir_current->filename;
+
+ /* force reload of custom artwork after new level series was selected,
+ but reload only that part of the artwork that really has changed */
+ if (getTreeInfoFromFilename(artwork.gfx_first, filename_old) !=
+ getTreeInfoFromFilename(artwork.gfx_first, filename_new))
+ artwork.graphics_set_current_name = NULL;
+ if (getTreeInfoFromFilename(artwork.snd_first, filename_old) !=
+ getTreeInfoFromFilename(artwork.snd_first, filename_new))
+ artwork.sounds_set_current_name = NULL;
+ if (getTreeInfoFromFilename(artwork.mus_first, filename_new) !=
+ getTreeInfoFromFilename(artwork.mus_first, filename_new))
+ artwork.music_set_current_name = NULL;
+
+ leveldir_current_filename = leveldir_current->filename;
+ }
+
+ if (artwork.graphics_set_current_name != artwork.gfx_current->name ||
+ last_override_level_graphics != setup.override_level_graphics)
+ {
+ int i;
+
+ ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ for(i=0; i<NUM_PICTURES; i++)
+ {
+ DrawInitText(image_filename[i], 150, FC_YELLOW);
+ ReloadCustomImage(pix[i], image_filename[i]);
+ }
+
+ FreeTileClipmasks();
+ InitTileClipmasks();
+ InitGfxBackground();
+
+ /* force redraw of (open or closed) door graphics */
+ SetDoorState(DOOR_OPEN_ALL);
+ CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+
+ artwork.graphics_set_current_name = artwork.gfx_current->name;
+ last_override_level_graphics = setup.override_level_graphics;
+ }
+
+ if (artwork.sounds_set_current_name != artwork.snd_current->name ||
+ last_override_level_sounds != setup.override_level_sounds)
+ {
+ InitReloadSounds(artwork.snd_current->name);
+
+ artwork.sounds_set_current_name = artwork.snd_current->name;
+ last_override_level_sounds = setup.override_level_sounds;
+ }
+
+ if (artwork.music_set_current_name != artwork.mus_current->name ||
+ last_override_level_music != setup.override_level_music)
+ {
+ InitReloadMusic(artwork.mus_current->name);
+
+ artwork.music_set_current_name = artwork.mus_current->name;
+ last_override_level_music = setup.override_level_music;
+ }
+}
+
void InitGadgets()
{
CreateLevelEditorGadgets();
EL_AMOEBE_VOLL,
EL_AMOEBE_BD
};
- static int ep_amoebalive_num = sizeof(ep_amoebalive)/sizeof(int);
+ static int ep_amoebalive_num = SIZEOF_ARRAY_INT(ep_amoebalive);
static int ep_amoeboid[] =
{
EL_AMOEBE_VOLL,
EL_AMOEBE_BD
};
- static int ep_amoeboid_num = sizeof(ep_amoeboid)/sizeof(int);
+ static int ep_amoeboid_num = SIZEOF_ARRAY_INT(ep_amoeboid);
static int ep_schluessel[] =
{
EL_EM_KEY_3,
EL_EM_KEY_4
};
- static int ep_schluessel_num = sizeof(ep_schluessel)/sizeof(int);
+ static int ep_schluessel_num = SIZEOF_ARRAY_INT(ep_schluessel);
static int ep_pforte[] =
{
EL_EM_GATE_3X,
EL_EM_GATE_4X,
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_CROSS,
EL_TUBE_VERTICAL,
EL_TUBE_HORIZONTAL,
EL_TUBE_RIGHT_UP,
EL_TUBE_RIGHT_DOWN
};
- static int ep_pforte_num = sizeof(ep_pforte)/sizeof(int);
+ static int ep_pforte_num = SIZEOF_ARRAY_INT(ep_pforte);
static int ep_solid[] =
{
EL_QUICKSAND_EMPTYING,
EL_MAGIC_WALL_OFF,
EL_MAGIC_WALL_EMPTY,
+ EL_MAGIC_WALL_EMPTYING,
+ EL_MAGIC_WALL_FILLING,
EL_MAGIC_WALL_FULL,
EL_MAGIC_WALL_DEAD,
EL_MAGIC_WALL_BD_OFF,
EL_MAGIC_WALL_BD_EMPTY,
+ EL_MAGIC_WALL_BD_EMPTYING,
EL_MAGIC_WALL_BD_FULL,
+ EL_MAGIC_WALL_BD_FILLING,
EL_MAGIC_WALL_BD_DEAD,
EL_LIFE,
EL_LIFE_ASYNC,
EL_SP_HARD_BASE5,
EL_SP_HARD_BASE6,
EL_SP_TERMINAL,
+ EL_SP_TERMINAL_ACTIVE,
EL_SP_EXIT,
EL_INVISIBLE_STEEL,
EL_BELT1_SWITCH_LEFT,
EL_CRYSTAL,
EL_WALL_PEARL,
EL_WALL_CRYSTAL,
+ EL_PFORTE1,
+ EL_PFORTE2,
+ EL_PFORTE3,
+ EL_PFORTE4,
+ EL_PFORTE1X,
+ EL_PFORTE2X,
+ EL_PFORTE3X,
+ EL_PFORTE4X,
+ EL_EM_GATE_1,
+ EL_EM_GATE_2,
+ EL_EM_GATE_3,
+ EL_EM_GATE_4,
+ EL_EM_GATE_1X,
+ EL_EM_GATE_2X,
+ EL_EM_GATE_3X,
+ EL_EM_GATE_4X,
+ 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_CROSS,
EL_TUBE_VERTICAL,
EL_TUBE_HORIZONTAL,
EL_TUBE_RIGHT_UP,
EL_TUBE_RIGHT_DOWN
};
- static int ep_solid_num = sizeof(ep_solid)/sizeof(int);
+ static int ep_solid_num = SIZEOF_ARRAY_INT(ep_solid);
static int ep_massive[] =
{
EL_BADEWANNE3,
EL_BADEWANNE4,
EL_BADEWANNE5,
- EL_PFORTE1,
- EL_PFORTE2,
- EL_PFORTE3,
- EL_PFORTE4,
- EL_PFORTE1X,
- EL_PFORTE2X,
- EL_PFORTE3X,
- EL_PFORTE4X,
- EL_EM_GATE_1,
- EL_EM_GATE_2,
- EL_EM_GATE_3,
- EL_EM_GATE_4,
- EL_EM_GATE_1X,
- EL_EM_GATE_2X,
- EL_EM_GATE_3X,
- EL_EM_GATE_4X,
- EL_SWITCHGATE_OPEN,
- EL_SWITCHGATE_CLOSED,
- EL_TIMEGATE_OPEN,
- EL_TIMEGATE_CLOSED,
EL_SP_HARD_GRAY,
EL_SP_HARD_GREEN,
EL_SP_HARD_BLUE,
EL_EMC_STEEL_WALL_3,
EL_EMC_STEEL_WALL_4,
EL_CRYSTAL,
+ EL_PFORTE1,
+ EL_PFORTE2,
+ EL_PFORTE3,
+ EL_PFORTE4,
+ EL_PFORTE1X,
+ EL_PFORTE2X,
+ EL_PFORTE3X,
+ EL_PFORTE4X,
+ EL_EM_GATE_1,
+ EL_EM_GATE_2,
+ EL_EM_GATE_3,
+ EL_EM_GATE_4,
+ EL_EM_GATE_1X,
+ EL_EM_GATE_2X,
+ EL_EM_GATE_3X,
+ EL_EM_GATE_4X,
+ 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_CROSS,
EL_TUBE_VERTICAL,
EL_TUBE_HORIZONTAL,
EL_TUBE_RIGHT_UP,
EL_TUBE_RIGHT_DOWN
};
- static int ep_massive_num = sizeof(ep_massive)/sizeof(int);
+ static int ep_massive_num = SIZEOF_ARRAY_INT(ep_massive);
static int ep_slippery[] =
{
EL_PEARL,
EL_CRYSTAL
};
- static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int);
+ static int ep_slippery_num = SIZEOF_ARRAY_INT(ep_slippery);
static int ep_enemy[] =
{
EL_SP_SNIKSNAK,
EL_SP_ELECTRON
};
- static int ep_enemy_num = sizeof(ep_enemy)/sizeof(int);
+ static int ep_enemy_num = SIZEOF_ARRAY_INT(ep_enemy);
static int ep_mauer[] =
{
EL_SP_HARD_BASE5,
EL_SP_HARD_BASE6,
EL_SP_TERMINAL,
+ EL_SP_TERMINAL_ACTIVE,
EL_SP_EXIT,
EL_INVISIBLE_STEEL,
EL_STEEL_SLANTED,
EL_EMC_WALL_7,
EL_EMC_WALL_8
};
- static int ep_mauer_num = sizeof(ep_mauer)/sizeof(int);
+ static int ep_mauer_num = SIZEOF_ARRAY_INT(ep_mauer);
static int ep_can_fall[] =
{
EL_SPRING,
EL_DX_SUPABOMB
};
- static int ep_can_fall_num = sizeof(ep_can_fall)/sizeof(int);
+ static int ep_can_fall_num = SIZEOF_ARRAY_INT(ep_can_fall);
static int ep_can_smash[] =
{
EL_SPRING,
EL_DX_SUPABOMB
};
- static int ep_can_smash_num = sizeof(ep_can_smash)/sizeof(int);
+ static int ep_can_smash_num = SIZEOF_ARRAY_INT(ep_can_smash);
static int ep_can_change[] =
{
EL_EDELSTEIN_LILA,
EL_DIAMANT
};
- static int ep_can_change_num = sizeof(ep_can_change)/sizeof(int);
+ static int ep_can_change_num = SIZEOF_ARRAY_INT(ep_can_change);
static int ep_can_move[] =
{
EL_BALLOON,
EL_SPRING_MOVING
};
- static int ep_can_move_num = sizeof(ep_can_move)/sizeof(int);
+ static int ep_can_move_num = SIZEOF_ARRAY_INT(ep_can_move);
static int ep_could_move[] =
{
EL_PACMAN_LEFT,
EL_PACMAN_DOWN
};
- static int ep_could_move_num = sizeof(ep_could_move)/sizeof(int);
+ static int ep_could_move_num = SIZEOF_ARRAY_INT(ep_could_move);
static int ep_dont_touch[] =
{
EL_BUTTERFLY,
EL_FIREFLY
};
- static int ep_dont_touch_num = sizeof(ep_dont_touch)/sizeof(int);
+ static int ep_dont_touch_num = SIZEOF_ARRAY_INT(ep_dont_touch);
static int ep_dont_go_to[] =
{
EL_TRAP_ACTIVE,
EL_LANDMINE
};
- static int ep_dont_go_to_num = sizeof(ep_dont_go_to)/sizeof(int);
+ static int ep_dont_go_to_num = SIZEOF_ARRAY_INT(ep_dont_go_to);
static int ep_mampf2[] =
{
EL_PEARL,
EL_CRYSTAL
};
- static int ep_mampf2_num = sizeof(ep_mampf2)/sizeof(int);
+ static int ep_mampf2_num = SIZEOF_ARRAY_INT(ep_mampf2);
static int ep_bd_element[] =
{
EL_AMOEBE_BD,
EL_CHAR_FRAGE
};
- static int ep_bd_element_num = sizeof(ep_bd_element)/sizeof(int);
+ static int ep_bd_element_num = SIZEOF_ARRAY_INT(ep_bd_element);
static int ep_sb_element[] =
{
EL_SPIELFIGUR,
EL_INVISIBLE_STEEL
};
- static int ep_sb_element_num = sizeof(ep_sb_element)/sizeof(int);
+ static int ep_sb_element_num = SIZEOF_ARRAY_INT(ep_sb_element);
static int ep_gem[] =
{
EL_EDELSTEIN_LILA,
EL_DIAMANT
};
- static int ep_gem_num = sizeof(ep_gem)/sizeof(int);
+ static int ep_gem_num = SIZEOF_ARRAY_INT(ep_gem);
static int ep_inactive[] =
{
EL_EMC_WALL_7,
EL_EMC_WALL_8
};
- static int ep_inactive_num = sizeof(ep_inactive)/sizeof(int);
+ static int ep_inactive_num = SIZEOF_ARRAY_INT(ep_inactive);
static int ep_explosive[] =
{
EL_SP_ELECTRON,
EL_DX_SUPABOMB
};
- static int ep_explosive_num = sizeof(ep_explosive)/sizeof(int);
+ static int ep_explosive_num = SIZEOF_ARRAY_INT(ep_explosive);
static int ep_mampf3[] =
{
EL_PEARL,
EL_CRYSTAL
};
- static int ep_mampf3_num = sizeof(ep_mampf3)/sizeof(int);
+ static int ep_mampf3_num = SIZEOF_ARRAY_INT(ep_mampf3);
static int ep_pushable[] =
{
EL_SPRING,
EL_DX_SUPABOMB
};
- static int ep_pushable_num = sizeof(ep_pushable)/sizeof(int);
+ static int ep_pushable_num = SIZEOF_ARRAY_INT(ep_pushable);
static int ep_player[] =
{
EL_SPIELER3,
EL_SPIELER4
};
- static int ep_player_num = sizeof(ep_player)/sizeof(int);
+ static int ep_player_num = SIZEOF_ARRAY_INT(ep_player);
static int ep_has_content[] =
{
EL_AMOEBE_VOLL,
EL_AMOEBE_BD
};
- static int ep_has_content_num = sizeof(ep_has_content)/sizeof(int);
+ static int ep_has_content_num = SIZEOF_ARRAY_INT(ep_has_content);
static int ep_eatable[] =
{
EL_TRAP_INACTIVE,
EL_SAND_INVISIBLE
};
- static int ep_eatable_num = sizeof(ep_eatable)/sizeof(int);
+ static int ep_eatable_num = SIZEOF_ARRAY_INT(ep_eatable);
static int ep_sp_element[] =
{
/* more than one murphy in a level results in an inactive clone */
EL_SP_MURPHY_CLONE
};
- static int ep_sp_element_num = sizeof(ep_sp_element)/sizeof(int);
+ static int ep_sp_element_num = SIZEOF_ARRAY_INT(ep_sp_element);
static int ep_quick_gate[] =
{
EL_SWITCHGATE_OPEN,
EL_TIMEGATE_OPEN
};
- static int ep_quick_gate_num = sizeof(ep_quick_gate)/sizeof(int);
+ static int ep_quick_gate_num = SIZEOF_ARRAY_INT(ep_quick_gate);
static int ep_over_player[] =
{
EL_TUBE_RIGHT_UP,
EL_TUBE_RIGHT_DOWN
};
- static int ep_over_player_num = sizeof(ep_over_player)/sizeof(int);
+ static int ep_over_player_num = SIZEOF_ARRAY_INT(ep_over_player);
static int ep_active_bomb[] =
{
EL_DYNABOMB_ACTIVE_3,
EL_DYNABOMB_ACTIVE_4
};
- static int ep_active_bomb_num = sizeof(ep_active_bomb)/sizeof(int);
+ static int ep_active_bomb_num = SIZEOF_ARRAY_INT(ep_active_bomb);
static int ep_belt[] =
{
EL_BELT4_MIDDLE,
EL_BELT4_RIGHT,
};
- static int ep_belt_num = sizeof(ep_belt)/sizeof(int);
+ static int ep_belt_num = SIZEOF_ARRAY_INT(ep_belt);
static int ep_belt_switch[] =
{
EL_BELT4_SWITCH_MIDDLE,
EL_BELT4_SWITCH_RIGHT,
};
- static int ep_belt_switch_num = sizeof(ep_belt_switch)/sizeof(int);
+ static int ep_belt_switch_num = SIZEOF_ARRAY_INT(ep_belt_switch);
static int ep_tube[] =
{
EL_TUBE_RIGHT_UP,
EL_TUBE_RIGHT_DOWN
};
- static int ep_tube_num = sizeof(ep_tube)/sizeof(int);
+ static int ep_tube_num = SIZEOF_ARRAY_INT(ep_tube);
static long ep1_bit[] =
{
&ep_belt_switch_num,
&ep_tube_num
};
- static int num_properties1 = sizeof(ep1_num)/sizeof(int *);
- static int num_properties2 = sizeof(ep2_num)/sizeof(int *);
+ static int num_properties1 = SIZEOF_ARRAY(ep1_num, int *);
+ static int num_properties2 = SIZEOF_ARRAY(ep2_num, int *);
for(i=0; i<MAX_ELEMENTS; i++)
{
Elementeigenschaften1[i] |= (EP_BIT_CHAR | EP_BIT_INACTIVE);
}
+void Execute_Debug_Command(char *command)
+{
+ if (strcmp(command, "create graphicsinfo.conf") == 0)
+ {
+ printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
+ printf("\n");
+ printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
+ printf("\n");
+ printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+ }
+ else if (strcmp(command, "create soundsinfo.conf") == 0)
+ {
+ int i;
+
+ printf("# You can configure additional/alternative sound effects here\n");
+ printf("# (The sounds 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; i<NUM_SOUND_EFFECTS; i++)
+ printf("# %s\n",
+ getFormattedSetupEntry(sound_effects[i].text,
+ sound_effects[i].default_filename));
+ }
+ else if (strcmp(command, "create musicinfo.conf") == 0)
+ {
+ printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
+ printf("\n");
+ printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
+ printf("\n");
+ printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+ }
+}
+
void CloseAllAndExit(int exit_value)
{
int i;
StopSounds();
- FreeSounds(NUM_SOUNDS);
- CloseAudio();
+ FreeAllSounds();
+ FreeAllMusic();
+ CloseAudio(); /* called after freeing sounds (needed for SDL) */
+ FreeTileClipmasks();
for(i=0; i<NUM_BITMAPS; i++)
FreeBitmap(pix[i]);
- CloseVideoDisplay();
+ CloseVideoDisplay();
ClosePlatformDependantStuff();
exit(exit_value);
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "main.h"
void OpenAll(void);
+void ReloadCustomArtwork();
void CloseAllAndExit(int);
-void InitJoysticks(void);
#endif
+++ /dev/null
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back! *
-*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
-* Holger Schemel *
-* Detmolder Strasse 189 *
-* 33604 Bielefeld *
-* Germany *
-* e-mail: info@artsoft.org *
-*----------------------------------------------------------*
-* joystick.c *
-***********************************************************/
-
-#if defined(PLATFORM_FREEBSD)
-#include <machine/joystick.h>
-#endif
-
-#include "libgame/libgame.h"
-
-#include "joystick.h"
-
-#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 (strcmp(*name, translate_joy[i].name) == 0)
- {
- *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;
-}
-
-#if !defined(PLATFORM_MSDOS)
-static int JoystickPosition(int middle, int margin, int actual)
-{
- long range, pos;
- int percentage;
-
- if (margin < middle && actual > middle)
- return 0;
- if (margin > middle && actual < middle)
- return 0;
-
- range = ABS(margin - middle);
- pos = ABS(actual - middle);
- percentage = (int)(pos * 100 / range);
-
- if (percentage > 100)
- percentage = 100;
-
- return percentage;
-}
-#endif
-
-#if defined(TARGET_SDL)
-
-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} };
-
-SDL_Joystick *Get_SDL_Joystick(int nr)
-{
- return sdl_joystick[nr];
-}
-
-boolean Open_SDL_Joystick(int nr)
-{
- if (nr < 0 || nr > MAX_PLAYERS)
- return FALSE;
-
- return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
-}
-
-void Close_SDL_Joystick(int nr)
-{
- if (nr < 0 || nr > MAX_PLAYERS)
- return;
-
- SDL_JoystickClose(sdl_joystick[nr]);
-}
-
-boolean Check_SDL_JoystickOpened(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;
-
-#if 0
- printf("js_%d %s-axis: %d\n",
- event->jaxis.which,
- (event->jaxis.axis == 0 ? "x" : "y"),
- event->jaxis.value);
-#endif
- }
- break;
-
- case SDL_JOYBUTTONDOWN:
- if (event->jbutton.button < 2)
- {
- sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
-
-#if 0
- printf("js_%d button %d: pressed\n",
- event->jbutton.which,
- event->jbutton.button);
-#endif
- }
- break;
-
- case SDL_JOYBUTTONUP:
- if (event->jbutton.button < 2)
- {
- sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
-
-#if 0
- printf("js_%d button %d: released\n",
- event->jbutton.which,
- event->jbutton.button);
-#endif
- }
- break;
-
- default:
- break;
- }
-}
-
-int Get_SDL_Joystick_Axis(int nr, int axis)
-{
- if (nr < 0 || nr > MAX_PLAYERS)
- return 0;
-
- if (axis < 0 || axis > 1)
- return 0;
-
- return sdl_js_axis[nr][axis];
-}
-
-void CheckJoystickData()
-{
-}
-
-int Joystick(int player_nr)
-{
- int joystick_nr = stored_player[player_nr].joystick_fd;
- int js_x,js_y, js_b1,js_b2;
- int left, right, up, down;
- int result = 0;
-
- if (joystick_status == JOYSTICK_OFF)
- return 0;
-
- if (game_status == SETUPINPUT)
- return 0;
-
- if (!setup.input[player_nr].use_joystick ||
- !Check_SDL_JoystickOpened(joystick_nr))
- return 0;
-
- js_x = sdl_js_axis[joystick_nr][0];
- js_y = sdl_js_axis[joystick_nr][1];
-
- js_b1 = sdl_js_button[joystick_nr][0];
- js_b2 = sdl_js_button[joystick_nr][1];
-
-
-
-#if 0
- printf("JOYSTICK %d: js_x == %d, js_y == %d, js_b1 == %d, js_b2 == %d\n",
- joystick_nr, js_x, js_y, js_b1, js_b2);
-#endif
-
-
-
- left = JoystickPosition(setup.input[player_nr].joy.xmiddle,
- setup.input[player_nr].joy.xleft, js_x);
- right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
- setup.input[player_nr].joy.xright, js_x);
- up = JoystickPosition(setup.input[player_nr].joy.ymiddle,
- setup.input[player_nr].joy.yupper, js_y);
- down = JoystickPosition(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;
-
-
-
-#if 0
- printf("result == 0x%08x\n", result);
-#endif
-
-
-
- return result;
-}
-
-#else /* !TARGET_SDL */
-
-void CheckJoystickData()
-{
- int i;
- int distance = 100;
-
- for(i=0; i<MAX_PLAYERS; i++)
- {
- if (setup.input[i].joy.xmiddle <= distance)
- setup.input[i].joy.xmiddle = distance;
- if (setup.input[i].joy.ymiddle <= distance)
- setup.input[i].joy.ymiddle = distance;
-
- 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;
- }
-}
-
-#if defined(PLATFORM_UNIX)
-int Joystick(int player_nr)
-{
-#ifdef __FreeBSD__
- struct joystick joy_ctrl;
-#else
- struct joystick_control
- {
- int buttons;
- int x;
- int y;
- } joy_ctrl;
-#endif
-
- int joystick_fd = stored_player[player_nr].joystick_fd;
- int js_x,js_y, js_b1,js_b2;
- int left, right, up, down;
- int result = 0;
-
- if (joystick_status == JOYSTICK_OFF)
- return 0;
-
- if (game_status == SETUPINPUT)
- return 0;
-
- if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
- return 0;
-
- if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
- {
- Error(ERR_WARN, "cannot read joystick device '%s'",
- setup.input[player_nr].joy.device_name);
- joystick_status = JOYSTICK_OFF;
- return 0;
- }
-
- js_x = joy_ctrl.x;
- js_y = joy_ctrl.y;
-
-#ifdef __FreeBSD__
- js_b1 = joy_ctrl.b1;
- js_b2 = joy_ctrl.b2;
-#else
- js_b1 = joy_ctrl.buttons & 1;
- js_b2 = joy_ctrl.buttons & 2;
-#endif
-
- left = JoystickPosition(setup.input[player_nr].joy.xmiddle,
- setup.input[player_nr].joy.xleft, js_x);
- right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
- setup.input[player_nr].joy.xright, js_x);
- up = JoystickPosition(setup.input[player_nr].joy.ymiddle,
- setup.input[player_nr].joy.yupper, js_y);
- down = JoystickPosition(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;
-}
-
-#else /* PLATFORM_MSDOS */
-
-/* allegro global variables for joystick control */
-extern int num_joysticks;
-extern JOYSTICK_INFO joy[];
-
-int Joystick(int player_nr)
-{
- int joystick_nr = stored_player[player_nr].joystick_fd;
- int result = 0;
-
- if (joystick_status == JOYSTICK_OFF)
- return 0;
-
- if (game_status == SETUPINPUT)
- return 0;
-
- if (joystick_nr < 0)
- return 0;
-
- /* the allegro global variable 'num_joysticks' contains the number
- of joysticks found at initialization under MS-DOS / Windows */
-
-#if 0
- if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick)
- return 0;
-#else
-
-#if 1
- if (joystick_nr >= num_joysticks ||
- (game_status == PLAYING && !setup.input[player_nr].use_joystick))
- return 0;
-#else
- if (joystick_nr >= num_joysticks)
- return 0;
-#endif
-
-#endif
-
- poll_joystick();
-
- if (joy[joystick_nr].stick[0].axis[0].d1)
- result |= JOY_LEFT;
- else if (joy[joystick_nr].stick[0].axis[0].d2)
- result |= JOY_RIGHT;
- if (joy[joystick_nr].stick[0].axis[1].d1)
- result |= JOY_UP;
- else if (joy[joystick_nr].stick[0].axis[1].d2)
- result |= JOY_DOWN;
-
- if (joy[joystick_nr].button[0].b)
- result |= JOY_BUTTON_1;
- if (joy[joystick_nr].button[1].b)
- result |= JOY_BUTTON_2;
-
- return result;
-}
-#endif /* PLATFORM_MSDOS */
-
-#endif /* !TARGET_SDL */
-
-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++)
- {
-
- /*
- if (!setup.input[i].use_joystick)
- continue;
- */
-
-
- result |= Joystick(i);
- }
-
- return result;
-}
-
-int AnyJoystickButton()
-{
- int i;
- int result;
-
- for (i=0; i<MAX_PLAYERS; i++)
- {
-
- /*
- if (!setup.input[i].use_joystick)
- continue;
- */
-
- /*
- result |= JoystickButton(i);
- */
-
- result = JoystickButton(i);
- if (result != JOY_BUTTON_NOT_PRESSED)
- break;
- }
-
- return result;
-}
+++ /dev/null
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back! *
-*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
-* Holger Schemel *
-* Detmolder Strasse 189 *
-* 33604 Bielefeld *
-* Germany *
-* e-mail: info@artsoft.org *
-*----------------------------------------------------------*
-* joystick.h *
-***********************************************************/
-
-#ifndef JOYSTICK_H
-#define JOYSTICK_H
-
-#include "main.h"
-
-/* values for the joystick */
-#define JOYSTICK_OFF 0
-#define JOYSTICK_AVAILABLE 1
-
-#ifdef __FreeBSD__
-#include <machine/joystick.h>
-#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 30
-#define JOYSTICK_XMIDDLE 530
-#define JOYSTICK_XRIGHT 1250
-#define JOYSTICK_YUPPER 40
-#define JOYSTICK_YMIDDLE 680
-#define JOYSTICK_YLOWER 1440
-#endif
-
-#define JOYSTICK_PERCENT 25
-
-#define JOY_LEFT MV_LEFT
-#define JOY_RIGHT MV_RIGHT
-#define JOY_UP MV_UP
-#define JOY_DOWN MV_DOWN
-#define JOY_BUTTON_1 (1<<4)
-#define JOY_BUTTON_2 (1<<5)
-#define JOY_BUTTON (JOY_BUTTON_1 | JOY_BUTTON_2)
-
-#define JOY_BUTTON_NOT_PRESSED 0
-#define JOY_BUTTON_PRESSED 1
-#define JOY_BUTTON_NEW_PRESSED 2
-#define JOY_BUTTON_NEW_RELEASED 3
-
-#ifdef NO_JOYSTICK
-#define JOYSTICK_STATUS JOYSTICK_OFF
-#else
-#define JOYSTICK_STATUS JOYSTICK_AVAILABLE
-#endif
-
-
-#if defined(TARGET_SDL)
-SDL_Joystick *Get_SDL_Joystick(int);
-boolean Open_SDL_Joystick(int);
-void Close_SDL_Joystick(int);
-boolean Check_SDL_JoystickOpened(int);
-void HandleJoystickEvent(Event *);
-int Get_SDL_Joystick_Axis(int, int);
-#endif
-
-void CheckJoystickData(void);
-int Joystick(int);
-int JoystickButton(int);
-int AnyJoystick(void);
-int AnyJoystickButton(void);
-
-#endif /* JOYSTICK_H */
#=============================================================================#
# Makefile for Artsoft Retro-Game Library #
-# (c) 1994-2000 Holger Schemel, info@artsoft.org #
+# (c) 1994-2002 Holger Schemel, info@artsoft.org #
#=============================================================================#
SRCS = system.c \
gadgets.c \
text.c \
sound.c \
+ joystick.c \
+ toons.c \
pcx.c \
image.c \
random.c \
+ setup.c \
misc.c \
msdos.c \
x11.c \
gadgets.o \
text.o \
sound.o \
+ joystick.o \
+ toons.o \
pcx.o \
image.o \
random.o \
+ setup.o \
misc.o \
msdos.o \
x11.o \
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
static void default_callback_info(void *ptr)
{
-#if 0
- if (game_status == LEVELED)
- HandleEditorGadgetInfoText(ptr);
-#endif
-
return;
}
break;
case GDI_CHECKED:
- gi->checked = va_arg(ap, boolean);
+ /* take care here: "boolean" is typedef'ed as "unsigned char",
+ which gets promoted to "int" */
+ gi->checked = (boolean)va_arg(ap, int);
break;
case GDI_RADIO_NR:
if (last_info_gi != new_gi ||
(new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
{
- last_info_gi = new_gi;
-
if (new_gi != NULL && (button == 0 || new_gi == last_gi))
{
- new_gi->event.type = 0;
+ new_gi->event.type = GD_EVENT_INFO_ENTERING;
new_gi->callback_info(new_gi);
}
- else
+ else if (last_info_gi != NULL)
+ {
+ last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
+ last_info_gi->callback_info(last_info_gi);
+
+#if 0
default_callback_info(NULL);
+
+ printf("It seems that we are leaving gadget [%s]!\n",
+ (last_info_gi != NULL &&
+ last_info_gi->info_text != NULL ?
+ last_info_gi->info_text : ""));
+#endif
+ }
+
+ last_info_gi = new_gi;
}
if (gadget_pressed)
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#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
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
{
Image *image;
- const unsigned int bytes_per_pixel = 1;
+ unsigned int bytes_per_pixel = (depth + 7) / 8;
int i;
+#if 0
if (depth > 8)
Error(ERR_EXIT, "images with more than 256 colors are not supported");
depth = 8;
+#endif
+
image = checked_malloc(sizeof(Image));
image->data = checked_malloc(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;
}
/* extra colors to try allocating in private color maps to minimize flashing */
#define NOFLASH_COLORS 256
-/* architecture independent value-to-memory conversion
+/* architecture independent value <-> memory conversions;
note: the internal format is big endian */
-#define value_to_memory(value, ptr, length) ( \
-(length) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \
-(length) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \
- *(((byte *)(ptr))+1) = ( value ) ) : \
-(length) == 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 ) ))
+#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;
+ unsigned int x, y, i;
byte bitmask;
byte *mask_data;
Pixmap mask_pixmap;
for (x=0; x<image->width; x++)
{
- if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
- *dst_ptr2 |= bitmask; /* then write a bit into the image mask */
+ 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? */
{
static int num_cmap_entries, free_cmap_entries;
static boolean private_cmap = FALSE;
Pixel *redvalue, *greenvalue, *bluevalue;
- unsigned int a, c = 0, x, y, bytes_per_pixel, bits_per_pixel;
+ 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)
{
bluestep = 256 / bluecolors;
redbottom = greenbottom = bluebottom = 0;
redtop = greentop = bluetop = 0;
+
for (a=0; a<visual->map_entries; a++)
{
if (redbottom < 256)
/* something completely unexpected happened */
- fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
+ fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n");
+
free(redvalue);
free(greenvalue);
free(bluevalue);
free(ximageinfo);
+
return NULL;
}
while ((bluebottom < 256) && (bluebottom < bluetop))
bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
}
+
break;
}
}
if (!color_found) /* no more free color cells */
- Error(ERR_EXIT, "cannot allocate enough color cells");
+ {
+ SetError(error, "cannot allocate enough color cells");
+ return NULL;
+ }
xcolor.pixel = xcolor2.pixel;
xcolor_private[xcolor.pixel] = xcolor;
break;
default:
- Error(ERR_RETURN, "display class not supported");
- Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
- break;
+ Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed");
+ SetError(error, "display class not supported");
+
+ return NULL;
}
#if DEBUG_TIMING
/* create XImage from internal image structure and convert it to Pixmap */
- bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
- bytes_per_pixel = (bits_per_pixel + 7) / 8;
+ 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 * bytes_per_pixel);
+ 8, image->width * display_bytes_per_pixel);
ximage->data =
- checked_malloc(image->width * image->height * bytes_per_pixel);
+ checked_malloc(image->width * image->height * display_bytes_per_pixel);
ximage->byte_order = MSBFirst;
src_ptr = image->data;
{
Pixel pixval;
- for (y=0; y<image->height; y++) /* general case */
+ switch (image->type)
{
- for (x=0; x<image->width; x++)
+ 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:
{
- 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, bytes_per_pixel);
- dst_ptr += bytes_per_pixel;
+ 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_RETURN, "RGB or TrueColor image needed");
+ SetError(error, "image type not supported");
+
+ return NULL;
}
+
break;
}
case PseudoColor:
{
- if (bytes_per_pixel == 1) /* (common) special case */
+ if (display_bytes_per_pixel == 1) /* special case */
{
for (y=0; y<image->height; y++)
for (x=0; x<image->width; x++)
for (x=0; x<image->width; x++)
{
value_to_memory(ximageinfo->index[c + *src_ptr++],
- dst_ptr, bytes_per_pixel);
- dst_ptr += bytes_per_pixel;
+ dst_ptr, display_bytes_per_pixel);
+ dst_ptr += display_bytes_per_pixel;
}
}
}
+
break;
}
default:
- Error(ERR_RETURN, "display class not supported");
- Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
- break;
+ Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed");
+ SetError(error, "display class not supported");
+
+ return NULL;
}
if (redvalue)
XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
ximage, 0, 0, 0, 0, ximage->width, ximage->height);
- free(ximage->data);
- ximage->data = NULL;
XDestroyImage(ximage);
- return(ximageinfo);
+ return ximageinfo;
}
void freeXImage(Image *image, XImageInfo *ximageinfo)
/* convert image structure to X11 Pixmap */
if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
window, gc, depth, image)))
- Error(ERR_EXIT, "cannot convert Image to Pixmap");
+ {
+ freeImage(image);
+
+ return PCX_OtherError;
+ }
/* if a private colormap has been created, install it */
if (ximageinfo->cmap != DefaultColormap(display, screen))
*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;
}
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
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 *);
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment *
+* Holger Schemel *
+* Detmolder Strasse 189 *
+* 33604 Bielefeld *
+* Germany *
+* e-mail: info@artsoft.org *
+*----------------------------------------------------------*
+* joystick.c *
+***********************************************************/
+
+#if defined(PLATFORM_FREEBSD)
+#include <machine/joystick.h>
+#endif
+
+#include "joystick.h"
+#include "misc.h"
+
+
+/* ========================================================================= */
+/* platform dependant joystick functions */
+/* ========================================================================= */
+
+#if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
+void UnixInitJoysticks()
+{
+ 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)
+ {
+ Error(ERR_WARN, "cannot access joystick device '%s'", device_name);
+ continue;
+ }
+
+ if ((joystick.fd[i] = open(device_name, O_RDONLY)) < 0)
+ {
+ Error(ERR_WARN, "cannot open joystick device '%s'", device_name);
+ continue;
+ }
+
+ joystick.status = JOYSTICK_ACTIVATED;
+ }
+}
+
+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 independant 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 (strcmp(*name, translate_joy[i].name) == 0)
+ {
+ *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;
+}
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1995-2002 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_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 */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "gadgets.h"
#include "text.h"
#include "sound.h"
+#include "joystick.h"
+#include "toons.h"
#include "image.h"
#include "pcx.h"
+#include "setup.h"
#include "misc.h"
#endif /* LIBGAME_H */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#endif
#include "misc.h"
+#include "setup.h"
#include "random.h"
{
boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
+#if 0
#if defined(PLATFORM_MSDOS)
- /* don't use select() to perform waiting operations under DOS/Windows
+ /* don't use select() to perform waiting operations under DOS
environment; always use a busy loop for waiting instead */
do_busy_waiting = TRUE;
+#endif
#endif
if (do_busy_waiting)
{
#if defined(TARGET_SDL)
SDL_Delay(milliseconds_delay);
+#elif defined(TARGET_ALLEGRO)
+ rest(milliseconds_delay);
#else
struct timeval delay;
{
unsigned long actual_frame_counter = FrameCounter;
- if (actual_frame_counter < *frame_counter_var+frame_delay &&
+ if (actual_frame_counter < *frame_counter_var + frame_delay &&
actual_frame_counter >= *frame_counter_var)
- return(FALSE);
+ return FALSE;
*frame_counter_var = actual_frame_counter;
- return(TRUE);
+
+ return TRUE;
}
boolean DelayReached(unsigned long *counter_var,
if (actual_counter < *counter_var + delay &&
actual_counter >= *counter_var)
- return(FALSE);
+ return FALSE;
*counter_var = actual_counter;
- return(TRUE);
+
+ return TRUE;
}
void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
#if defined(PLATFORM_WIN32)
return ANONYMOUS_NAME;
#else
- struct passwd *pwd;
+ static char *login_name = NULL;
- if ((pwd = getpwuid(getuid())) == NULL)
- return ANONYMOUS_NAME;
- else
- return pwd->pw_name;
+ if (login_name == NULL)
+ {
+ struct passwd *pwd;
+
+ if ((pwd = getpwuid(getuid())) == NULL)
+ login_name = ANONYMOUS_NAME;
+ else
+ login_name = getStringCopy(pwd->pw_name);
+ }
+
+ return login_name;
#endif
}
#if defined(PLATFORM_UNIX)
static char *home_dir = NULL;
- if (!home_dir)
+ if (home_dir == NULL)
{
- if (!(home_dir = getenv("HOME")))
+ if ((home_dir = getenv("HOME")) == NULL)
{
struct passwd *pwd;
- if ((pwd = getpwuid(getuid())))
- home_dir = pwd->pw_dir;
- else
+ if ((pwd = getpwuid(getuid())) == NULL)
home_dir = ".";
+ else
+ home_dir = getStringCopy(pwd->pw_dir);
}
}
options.ro_base_directory = RO_BASE_PATH;
options.rw_base_directory = RW_BASE_PATH;
options.level_directory = RO_BASE_PATH "/" LEVELS_DIRECTORY;
+ options.graphics_directory = RO_BASE_PATH "/" GRAPHICS_DIRECTORY;
+ options.sounds_directory = RO_BASE_PATH "/" SOUNDS_DIRECTORY;
+ options.music_directory = RO_BASE_PATH "/" MUSIC_DIRECTORY;
options.serveronly = FALSE;
options.network = FALSE;
options.verbose = FALSE;
options.debug = FALSE;
+ options.debug_command = NULL;
while (*options_left)
{
Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
else if (strncmp(option, "-help", option_len) == 0)
{
- printf("Usage: %s [options] [server.name [port]]\n"
+ printf("Usage: %s [options] [<server host> [<server port>]]\n"
"Options:\n"
- " -d, --display machine:0 X server display\n"
- " -b, --basepath directory alternative base directory\n"
- " -l, --level directory alternative level directory\n"
- " -s, --serveronly only start network server\n"
+ " -d, --display <host>[:<scr>] 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",
program.command_basename);
+
+ if (options.debug)
+ printf(" --debug-command <command> execute special command\n");
+
exit(0);
}
else if (strncmp(option, "-display", option_len) == 0)
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;
{
options.debug = TRUE;
}
+ else if (strncmp(option, "-debug-command", option_len) == 0)
+ {
+ if (option_arg == NULL)
+ Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
+
+ options.debug_command = option_arg;
+ if (option_arg == next_option)
+ options_left++;
+ }
else if (*option == '-')
{
Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
}
}
+/* 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, ...)
{
char *process_name = "";
return ptr;
}
+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;
+}
+
short getFile16BitInteger(FILE *file, int byte_order)
{
if (byte_order == BYTE_ORDER_BIG_ENDIAN)
}
}
+int getFileVersion(FILE *file)
+{
+ int version_major, version_minor, version_patch;
+
+ version_major = fgetc(file);
+ version_minor = fgetc(file);
+ version_patch = fgetc(file);
+ fgetc(file); /* not used */
+
+ return VERSION_IDENT(version_major, version_minor, version_patch);
+}
+
+void putFileVersion(FILE *file, int version)
+{
+ int version_major = VERSION_MAJOR(version);
+ int version_minor = VERSION_MINOR(version);
+ int version_patch = VERSION_PATCH(version);
+
+ fputc(version_major, file);
+ fputc(version_minor, file);
+ fputc(version_patch, file);
+ fputc(0, file); /* not used */
+}
+
void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
{
- while (bytes--)
+ while (bytes-- && !feof(file))
fgetc(file);
}
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_X11KEYNAME_TO_KEYSYM 2
+#define TRANSLATE_KEYNAME_TO_KEYSYM 2
+#define TRANSLATE_X11KEYNAME_TO_KEYSYM 3
void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
{
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_F1 && key <= KSYM_F24)
- sprintf(name_buffer, "function F%d", (int)(key - KSYM_F1 + 1));
+ else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
+ sprintf(name_buffer, "function F%d", (int)(key - KSYM_FKEY_FIRST + 1));
else if (key == KSYM_UNDEFINED)
strcpy(name_buffer, "(undefined)");
else
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_F1 && key <= KSYM_F24)
- sprintf(name_buffer, "XK_F%d", (int)(key - KSYM_F1 + 1));
+ 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
*x11name = name_buffer;
}
+ else if (mode == TRANSLATE_KEYNAME_TO_KEYSYM)
+ {
+ Key key = KSYM_UNDEFINED;
+
+ i = 0;
+ do
+ {
+ if (strcmp(translate_key[i].name, *name) == 0)
+ {
+ 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;
((c2 >= '0' && c1 <= '9') || c2 == '\0'))
d = atoi(&name_ptr[4]);
- if (d >=1 && d <= 24)
+ if (d >= 1 && d <= KSYM_NUM_FKEYS)
key = KSYM_F1 + (Key)(d - 1);
}
else if (strncmp(name_ptr, "XK_", 3) == 0)
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;
return letter;
}
-/* ------------------------------------------------------------------------- */
-/* some functions to handle lists of level directories */
-/* ------------------------------------------------------------------------- */
-
-struct LevelDirInfo *newLevelDirInfo()
-{
- return checked_calloc(sizeof(struct LevelDirInfo));
-}
-
-void pushLevelDirInfo(struct LevelDirInfo **node_first,
- struct LevelDirInfo *node_new)
-{
- node_new->next = *node_first;
- *node_first = node_new;
-}
-
-int numLevelDirInfo(struct LevelDirInfo *node)
-{
- int num = 0;
-
- while (node)
- {
- num++;
- node = node->next;
- }
-
- return num;
-}
-
-boolean validLevelSeries(struct LevelDirInfo *node)
-{
- return (node != NULL && !node->node_group && !node->parent_link);
-}
-
-struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node)
-{
- if (node == NULL)
- {
- if (leveldir_first) /* start with first level directory entry */
- return getFirstValidLevelSeries(leveldir_first);
- else
- return NULL;
- }
- else if (node->node_group) /* enter level group (step down into tree) */
- return getFirstValidLevelSeries(node->node_group);
- else if (node->parent_link) /* skip start entry of level group */
- {
- if (node->next) /* get first real level series entry */
- return getFirstValidLevelSeries(node->next);
- else /* leave empty level group and go on */
- return getFirstValidLevelSeries(node->node_parent->next);
- }
- else /* this seems to be a regular level series */
- return node;
-}
-
-struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node)
-{
- if (node == NULL)
- return NULL;
-
- if (node->node_parent == NULL) /* top level group */
- return leveldir_first;
- else /* sub level group */
- return node->node_parent->node_group;
-}
-
-int numLevelDirInfoInGroup(struct LevelDirInfo *node)
-{
- return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node));
-}
-
-int posLevelDirInfo(struct LevelDirInfo *node)
-{
- struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node);
- int pos = 0;
-
- while (node_cmp)
- {
- if (node_cmp == node)
- return pos;
-
- pos++;
- node_cmp = node_cmp->next;
- }
-
- return 0;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos)
-{
- struct LevelDirInfo *node_default = node;
- int pos_cmp = 0;
-
- while (node)
- {
- if (pos_cmp == pos)
- return node;
-
- pos_cmp++;
- node = node->next;
- }
-
- return node_default;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node,
- char *filename)
-{
- if (filename == NULL)
- return NULL;
-
- while (node)
- {
- if (node->node_group)
- {
- struct LevelDirInfo *node_group;
-
- node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename);
-
- if (node_group)
- return node_group;
- }
- else if (!node->parent_link)
- {
- if (strcmp(filename, node->filename) == 0)
- return node;
- }
-
- node = node->next;
- }
-
- return NULL;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename)
-{
- return getLevelDirInfoFromFilenameExt(leveldir_first, filename);
-}
-
-void dumpLevelDirInfo(struct LevelDirInfo *node, int depth)
-{
- int i;
-
- while (node)
- {
- for (i=0; i<depth * 3; i++)
- printf(" ");
-
- printf("filename == '%s'\n", node->filename);
-
- if (node->node_group != NULL)
- dumpLevelDirInfo(node->node_group, depth + 1);
-
- node = node->next;
- }
-}
-
-void sortLevelDirInfo(struct LevelDirInfo **node_first,
- int (*compare_function)(const void *, const void *))
-{
- int num_nodes = numLevelDirInfo(*node_first);
- struct LevelDirInfo **sort_array;
- struct LevelDirInfo *node = *node_first;
- int i = 0;
-
- if (num_nodes == 0)
- return;
-
- /* allocate array for sorting structure pointers */
- sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *));
-
- /* 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(struct LevelDirInfo *),
- 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)
- sortLevelDirInfo(&node->node_group, compare_function);
-
- node = node->next;
- }
-}
-
-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;
-}
-
/* ========================================================================= */
-/* some stuff from "files.c" */
+/* functions for checking filenames */
/* ========================================================================= */
-#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 *getUserDataDir(void)
-{
- static char *userdata_dir = NULL;
-
- if (!userdata_dir)
- {
- char *home_dir = getHomeDir();
- char *data_dir = program.userdata_directory;
-
- userdata_dir = getPath2(home_dir, data_dir);
- }
-
- return userdata_dir;
-}
-
-char *getSetupDir()
+boolean FileIsGraphic(char *filename)
{
- return getUserDataDir();
-}
-
-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
-}
-
-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 normal_umask = posix_umask(0);
- mode_t group_umask = ~(dir_mode & S_IRWXG);
- posix_umask(normal_umask & group_umask);
-
- if (access(dir, F_OK) != 0)
- if (posix_mkdir(dir, dir_mode) != 0)
- Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
-
- posix_umask(normal_umask); /* reset normal umask */
-}
-
-void InitUserDataDirectory()
-{
- createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
-}
-
-void SetFilePermissions(char *filename, int permission_class)
-{
- chmod(filename, (permission_class == PERMS_PRIVATE ?
- FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC));
-}
-
-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);
-}
-
-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 stuff */
-/* ------------------------------------------------------------------------- */
-
-static char *string_tolower(char *s)
-{
- static char s_lower[100];
- int i;
-
- if (strlen(s) >= 100)
- return s;
-
- strcpy(s_lower, s);
-
- for (i=0; i<strlen(s_lower); i++)
- s_lower[i] = tolower(s_lower[i]);
-
- return s_lower;
-}
-
-int get_string_integer_value(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" },
- };
-
- int i, j;
-
- for (i=0; i<13; i++)
- for (j=0; j<3; j++)
- if (strcmp(string_tolower(s), number_text[i][j]) == 0)
- return i;
-
- return atoi(s);
-}
-
-boolean get_string_boolean_value(char *s)
-{
- if (strcmp(string_tolower(s), "true") == 0 ||
- strcmp(string_tolower(s), "yes") == 0 ||
- strcmp(string_tolower(s), "on") == 0 ||
- get_string_integer_value(s) == 1)
+ if (strlen(filename) > 4 &&
+ strcmp(&filename[strlen(filename) - 4], ".pcx") == 0)
return TRUE;
- else
- return FALSE;
-}
-
-char *getFormattedSetupEntry(char *token, char *value)
-{
- int i;
- static char entry[MAX_LINE_LEN];
-
- sprintf(entry, "%s:", token);
- for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
- entry[i] = ' ';
- entry[i] = '\0';
-
- strcat(entry, value);
-
- return entry;
-}
-
-void freeSetupFileList(struct SetupFileList *setup_file_list)
-{
- if (!setup_file_list)
- return;
- if (setup_file_list->token)
- free(setup_file_list->token);
- if (setup_file_list->value)
- free(setup_file_list->value);
- if (setup_file_list->next)
- freeSetupFileList(setup_file_list->next);
- free(setup_file_list);
+ return FALSE;
}
-static struct SetupFileList *newSetupFileList(char *token, char *value)
+boolean FileIsSound(char *basename)
{
- struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
-
- new->token = checked_malloc(strlen(token) + 1);
- strcpy(new->token, token);
-
- new->value = checked_malloc(strlen(value) + 1);
- strcpy(new->value, value);
-
- new->next = NULL;
-
- return new;
-}
-
-char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
-{
- if (!setup_file_list)
- return NULL;
-
- if (strcmp(setup_file_list->token, token) == 0)
- return setup_file_list->value;
- else
- return getTokenValue(setup_file_list->next, token);
-}
-
-static void setTokenValue(struct SetupFileList *setup_file_list,
- char *token, char *value)
-{
- if (!setup_file_list)
- return;
+ if (strlen(basename) > 4 &&
+ strcmp(&basename[strlen(basename) - 4], ".wav") == 0)
+ return TRUE;
- if (strcmp(setup_file_list->token, token) == 0)
- {
- free(setup_file_list->value);
- setup_file_list->value = checked_malloc(strlen(value) + 1);
- strcpy(setup_file_list->value, value);
- }
- else if (setup_file_list->next == NULL)
- setup_file_list->next = newSetupFileList(token, value);
- else
- setTokenValue(setup_file_list->next, token, value);
+ return FALSE;
}
-#ifdef DEBUG
-static void printSetupFileList(struct SetupFileList *setup_file_list)
+boolean FileIsMusic(char *basename)
{
- if (!setup_file_list)
- return;
+ /* "music" can be a WAV (loop) file or (if compiled with SDL) a MOD file */
- printf("token: '%s'\n", setup_file_list->token);
- printf("value: '%s'\n", setup_file_list->value);
+ if (FileIsSound(basename))
+ return TRUE;
- printSetupFileList(setup_file_list->next);
-}
+#if defined(TARGET_SDL)
+ if (strlen(basename) > 4 &&
+ (strcmp(&basename[strlen(basename) - 4], ".mod") == 0 ||
+ strcmp(&basename[strlen(basename) - 4], ".MOD") == 0 ||
+ strncmp(basename, "mod.", 4) == 0 ||
+ strncmp(basename, "MOD.", 4) == 0))
+ return TRUE;
#endif
-struct SetupFileList *loadSetupFileList(char *filename)
-{
- int line_len;
- char line[MAX_LINE_LEN];
- char *token, *value, *line_ptr;
- struct SetupFileList *setup_file_list = newSetupFileList("", "");
- struct SetupFileList *first_valid_list_entry;
-
- FILE *file;
-
- if (!(file = fopen(filename, MODE_READ)))
- {
- Error(ERR_WARN, "cannot open configuration file '%s'", filename);
- return NULL;
- }
-
- while(!feof(file))
- {
- /* read next line of input file */
- if (!fgets(line, MAX_LINE_LEN, file))
- break;
-
- /* cut trailing comment or whitespace from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- {
- if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
- {
- *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;
-
- line_len = strlen(line);
-
- /* cut leading whitespaces from token */
- for (token = line; *token; token++)
- if (*token != ' ' && *token != '\t')
- break;
-
- /* find end of token */
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
- if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
- {
- *line_ptr = '\0';
- break;
- }
- }
-
- if (line_ptr < line + line_len)
- value = line_ptr + 1;
- else
- value = "\0";
-
- /* cut leading whitespaces from value */
- for (; *value; value++)
- if (*value != ' ' && *value != '\t')
- break;
-
- if (*token && *value)
- setTokenValue(setup_file_list, token, value);
- }
-
- fclose(file);
-
- first_valid_list_entry = setup_file_list->next;
-
- /* free empty list header */
- setup_file_list->next = NULL;
- freeSetupFileList(setup_file_list);
-
- if (first_valid_list_entry == NULL)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
- return first_valid_list_entry;
+ return FALSE;
}
-void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
- char *identifier)
+boolean FileIsArtworkType(char *basename, int type)
{
- if (!setup_file_list)
- return;
-
- if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
- {
- if (strcmp(setup_file_list->value, identifier) != 0)
- {
- Error(ERR_WARN, "configuration file has wrong version");
- return;
- }
- else
- return;
- }
+ if ((type == TREE_TYPE_GRAPHICS_DIR && FileIsGraphic(basename)) ||
+ (type == TREE_TYPE_SOUNDS_DIR && FileIsSound(basename)) ||
+ (type == TREE_TYPE_MUSIC_DIR && FileIsMusic(basename)))
+ return TRUE;
- if (setup_file_list->next)
- checkSetupFileListIdentifier(setup_file_list->next, identifier);
- else
- {
- Error(ERR_WARN, "configuration file has no version information");
- return;
- }
+ return FALSE;
}
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "system.h"
-/* functions for version handling */
-#define VERSION_IDENT(x,y,z) ((x) * 10000 + (y) * 100 + (z))
-#define VERSION_MAJOR(x) ((x) / 10000)
-#define VERSION_MINOR(x) (((x) % 10000) / 100)
-#define VERSION_PATCH(x) ((x) % 100)
-
/* values for InitCounter() and Counter() */
#define INIT_COUNTER 0
#define READ_COUNTER 1
#define MAX_FILENAME_LEN 256
#define MAX_LINE_LEN 1000
-/* values for setup file stuff */
-#define TYPE_BOOLEAN 1
-#define TYPE_SWITCH 2
-#define TYPE_KEY 3
-#define TYPE_INTEGER 4
-#define TYPE_STRING 5
-
-#define TOKEN_STR_FILE_IDENTIFIER "file_identifier"
-
-#define TOKEN_VALUE_POSITION 30
-
-struct SetupFileList
-{
- char *token;
- char *value;
- struct SetupFileList *next;
-};
-
-struct TokenInfo
-{
- int type;
- void *value;
- char *text;
-};
-
void InitCounter(void);
unsigned long Counter(void);
void Delay(unsigned long);
char *getPath3(char *, char *, char*);
char *getStringCopy(char *);
char *getStringToLower(char *);
+
void GetOptions(char **);
+
+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);
+inline void swap_numbers(int *, int *);
+inline void swap_number_pairs(int *, int *, int *, int *);
+
short getFile16BitInteger(FILE *, int);
void putFile16BitInteger(FILE *, short, int);
int getFile32BitInteger(FILE *, int);
void putFile32BitInteger(FILE *, int, int);
boolean getFileChunk(FILE *, char *, int *, int);
void putFileChunk(FILE *, char *, int, int);
+int getFileVersion(FILE *);
+void putFileVersion(FILE *, int);
void ReadUnusedBytesFromFile(FILE *, unsigned long);
void WriteUnusedBytesToFile(FILE *, unsigned long);
+#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 *getJoyNameFromJoySymbol(int);
-int getJoySymbolFromJoyName(char *);
-int getJoystickNrFromDeviceName(char *);
-
-struct LevelDirInfo *newLevelDirInfo();
-void pushLevelDirInfo(struct LevelDirInfo **, struct LevelDirInfo *);
-int numLevelDirInfo(struct LevelDirInfo *);
-boolean validLevelSeries(struct LevelDirInfo *);
-struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *);
-struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *);
-int numLevelDirInfoInGroup(struct LevelDirInfo *);
-int posLevelDirInfo(struct LevelDirInfo *);
-struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *, int);
-struct LevelDirInfo *getLevelDirInfoFromFilename(char *);
-void dumpLevelDirInfo(struct LevelDirInfo *, int);
-void sortLevelDirInfo(struct LevelDirInfo **,
- int (*compare_function)(const void *, const void *));
-
-inline void swap_numbers(int *, int *);
-inline void swap_number_pairs(int *, int *, int *, int *);
-char *getUserDataDir(void);
-char *getSetupDir(void);
-void createDirectory(char *, char *, int);
-void InitUserDataDirectory(void);
-void SetFilePermissions(char *, int);
-int getFileVersionFromCookieString(const char *);
-boolean checkCookieString(const char *, const char *);
-
-int get_string_integer_value(char *);
-boolean get_string_boolean_value(char *);
-char *getFormattedSetupEntry(char *, char *);
-void freeSetupFileList(struct SetupFileList *);
-char *getTokenValue(struct SetupFileList *, char *);
-struct SetupFileList *loadSetupFileList(char *);
-void checkSetupFileListIdentifier(struct SetupFileList *, char *);
+boolean FileIsGraphic(char *);
+boolean FileIsSound(char *);
+boolean FileIsMusic(char *);
+boolean FileIsArtworkType(char *, int);
#if !defined(PLATFORM_UNIX)
void initErrorFile();
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#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])
boolean wait_for_vsync;
-/*
-extern int playing_sounds;
-extern struct SoundControl playlist[MAX_SOUNDS_PLAYING];
-extern struct SoundControl emptySoundControl;
-*/
-
static BITMAP *Read_PCX_to_AllegroBitmap(char *);
static void allegro_init_drivers()
static boolean allegro_init_audio()
{
- reserve_voices(MAX_SOUNDS_PLAYING, 0);
+ reserve_voices(NUM_MIXER_CHANNELS, 0);
if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) == -1)
if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1)
Screen *screen;
Display *display;
BITMAP *mouse_bitmap = NULL;
+ char *mouse_filename =getCustomImageFilename(program.msdos_pointer_filename);
- mouse_bitmap = Read_PCX_to_AllegroBitmap(program.msdos_pointer_filename);
- if (mouse_bitmap == NULL)
+ if ((mouse_bitmap = Read_PCX_to_AllegroBitmap(mouse_filename)) == NULL)
return NULL;
screen = malloc(sizeof(Screen));
screen[0].cmap = 0;
screen[0].root = 0;
-#if 0
- screen[0].white_pixel = 0xFF;
- screen[0].black_pixel = 0x00;
-#else
screen[0].white_pixel = AllegroAllocColorCell(0xFFFF, 0xFFFF, 0xFFFF);
screen[0].black_pixel = AllegroAllocColorCell(0x0000, 0x0000, 0x0000);
-#endif
screen[0].video_bitmap = NULL;
display->default_screen = 0;
byte *src_ptr = image->data;
byte pixel_mapping[MAX_COLORS];
unsigned int depth = 8;
-
-#if 0
- int i, j, x, y;
-#else
int i, x, y;
-#endif
+
+ 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)
/* try to use existing colors from the global colormap */
for (i=0; i<MAX_COLORS; i++)
{
-
-#if 0
- int r, g, b;
-#endif
-
if (!image->rgb.color_used[i])
continue;
-
-#if 0
- r = image->rgb.red[i] >> 10;
- g = image->rgb.green[i] >> 10;
- b = image->rgb.blue[i] >> 10;
-
- for (j=0; j<global_colormap_entries_used; j++)
- {
- if (r == global_colormap[j].r &&
- g == global_colormap[j].g &&
- b == global_colormap[j].b) /* color found */
- {
- pixel_mapping[i] = j;
- break;
- }
- }
-
- if (j == global_colormap_entries_used) /* color not found */
- {
- if (global_colormap_entries_used < MAX_COLORS)
- global_colormap_entries_used++;
-
- global_colormap[j].r = r;
- global_colormap[j].g = g;
- global_colormap[j].b = b;
-
- pixel_mapping[i] = j;
- }
-#else
pixel_mapping[i] = AllegroAllocColorCell(image->rgb.red[i],
image->rgb.green[i],
image->rgb.blue[i]);
-#endif
-
}
/* copy bitmap data */
return errno_pcx;
*pixmap = (Pixmap)bitmap;
-#if 0
- *pixmap_mask = (Pixmap)bitmap;
- /* !!! two pointers on same bitmap => second free() fails !!! */
-#else
+
/* pixmap_mask will never be used in Allegro (which uses masked_blit()),
so use non-NULL dummy pointer to empty Pixmap */
- /*
- *pixmap_mask = (Pixmap)checked_calloc(sizeof(Pixmap));
- */
*pixmap_mask = (Pixmap)DUMMY_MASK;
-#endif
return PCX_Success;
}
audio.music_available = TRUE;
audio.loops_available = TRUE;
audio.sound_enabled = TRUE;
- }
- InitPlaylist();
+ audio.num_channels = NUM_MIXER_CHANNELS;
+ audio.music_channel = MUSIC_CHANNEL;
+ audio.first_sound_channel = FIRST_SOUND_CHANNEL;
+
+ Mixer_InitChannels();
+ }
}
void MSDOSCloseAudio(void)
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 */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/* symbol 'window' is defined in DJGPP cross-compiler in libc.a(conio.o) */
-#define window window_djgpp
+#define window window_internal
/* symbol 'font' is defined in "allegro.h" */
-#define font font_allegro
+#define font font_internal
/* system dependent definitions */
#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 */
/* end of X11 keyboard mapping */
-#define JOYSTICK_FILENAME "joystick.cnf"
#define screen myscreen
void NetworkServer(int, int);
+void MSDOSInitJoysticks();
+boolean MSDOSReadJoystick(int, int *, int *, boolean *, boolean *);
+
#endif /* MSDOS_H */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#define PCX_DEBUG FALSE
#define PCX_MAGIC 0x0a /* first byte in a PCX image file */
-#define PCX_LAST_VERSION 5 /* last acceptable version number */
+#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_MAXDEPTH 8 /* supports up to 8 bits per pixel */
#define PCX_MAXCOLORS 256 /* maximum number of colors */
#define PCX_HEADER_SIZE 128
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, or depth */
+ 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 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; /* bit planes in image */
+ 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;
+#if 0
static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
{
/* Run Length Encoding: If the two high bits are set,
/* return current buffer position for next decoding function */
return buffer_ptr;
}
+#endif
+
+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)
+ 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)
+ 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;
+
+ 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;
+ }
+ return TRUE;
+}
+
+#if 0
static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
{
int i, magic;
/* return current buffer position for next decoding function */
return buffer_ptr;
}
+#endif
+
+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 *file_buffer;
- byte *buffer_ptr, *buffer_last;
- unsigned int file_length;
+ byte header_buffer[PCX_HEADER_SIZE];
struct PCX_Header pcx;
Image *image;
- int width, height, depth;
+ int width, height, depth, pcx_depth;
int i;
errno_pcx = PCX_Success;
return NULL;
}
- if (fseek(file, 0, SEEK_END) == -1)
- {
- fclose(file);
- errno_pcx = PCX_ReadFailed;
- return NULL;
- }
-
- file_length = ftell(file);
- rewind(file);
-
- if (file_length < PCX_HEADER_SIZE)
+ if (fread(header_buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE)
{
- /* PCX file is too short to contain a valid PCX header */
fclose(file);
- errno_pcx = PCX_FileInvalid;
- return NULL;
- }
-
- file_buffer = checked_malloc(file_length);
-
- if (fread(file_buffer, 1, file_length, file) != file_length)
- {
- fclose(file);
errno_pcx = PCX_ReadFailed;
return NULL;
}
- fclose(file);
-
- pcx.signature = file_buffer[0];
- pcx.version = file_buffer[1];
- pcx.encoding = file_buffer[2];
- pcx.bits_per_pixel = file_buffer[3];
- pcx.xmin = file_buffer[4] + 256 * file_buffer[5];
- pcx.ymin = file_buffer[6] + 256 * file_buffer[7];
- pcx.xmax = file_buffer[8] + 256 * file_buffer[9];
- pcx.ymax = file_buffer[10] + 256 * file_buffer[11];
- pcx.color_planes = file_buffer[65];
- pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67];
- pcx.palette_type = file_buffer[68] + 256 * file_buffer[69];
+ 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;
- depth = pcx.bits_per_pixel;
+ pcx_depth = pcx.bits_per_pixel * pcx.color_planes;
+ depth = ((pcx_depth + 7) / 8) * 8;
- if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION ||
- pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH ||
+ if (pcx.signature != PCX_MAGIC ||
+ pcx.version != PCX_SUPPORTED_VERSION ||
+ pcx.encoding != PCX_ENCODING ||
width < 0 || height < 0)
{
- free(file_buffer);
+ fclose(file);
errno_pcx = PCX_FileInvalid;
return NULL;
#if PCX_DEBUG
if (options.verbose)
{
- printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n",
- filename, width, height,
- pcx.color_planes);
- printf("depth: %d\n", pcx.bits_per_pixel);
+ 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",
/* allocate new image structure */
image = newImage(width, height, depth);
- buffer_ptr = file_buffer + PCX_HEADER_SIZE;
- buffer_last = file_buffer + file_length;
-
/* read compressed bitmap data */
- if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL)
+ if (!PCX_ReadBitmap(file, &pcx, image))
{
- free(file_buffer);
+ fclose(file);
freeImage(image);
errno_pcx = PCX_FileInvalid;
return NULL;
}
- if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE)
- {
- /* PCX file is too short to contain a valid 256 colors colormap */
- fclose(file);
- errno_pcx = PCX_ColorFailed;
- return NULL;
- }
-
/* read colormap data */
- if (!PCX_ReadColormap(image, buffer_ptr, buffer_last))
+ if (!PCX_ReadColormap(file, &pcx, image))
{
- free(file_buffer);
+ fclose(file);
freeImage(image);
+
errno_pcx = PCX_ColorFailed;
return NULL;
}
- free(file_buffer);
+ fclose(file);
- /* determine number of used colormap entries */
- image->rgb.used = 0;
- for (i=0; i<PCX_MAXCOLORS; i++)
- if (image->rgb.color_used[i])
- image->rgb.used++;
+ if (pcx_depth == 8)
+ {
+ /* determine number of used colormap entries for 8-bit PCX images */
+ image->rgb.used = 0;
+ for (i=0; i<PCX_MAXCOLORS; i++)
+ if (image->rgb.color_used[i])
+ image->rgb.used++;
+ }
#if PCX_DEBUG
if (options.verbose)
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#define PCX_FileInvalid -3
#define PCX_NoMemory -4
#define PCX_ColorFailed -5
+#define PCX_OtherError -6
/* global PCX error value */
extern int errno_pcx;
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#ifndef PLATFORM_H
#define PLATFORM_H
-/* define keywords for supported main platforms */
+/* ========================================================================= */
+/* define keywords for supported main platforms (Unix, DOS and Windows) */
+/* ========================================================================= */
#if defined(MSDOS)
#define PLATFORM_MSDOS
#define PLATFORM_NETBSD
#endif
+#if defined(__bsdi__)
+#define PLATFORM_BSDI
+#endif
+
+#if defined(sparc) || defined(sun)
+#define PLATFORM_SOLARIS
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define PLATFORM_MACOSX
+#endif
+
/* detecting HP-UX by the following compiler keyword definitions:
- in K&R mode (the default), the HP C compiler defines "hpux"
- in ANSI mode (-Aa or -Ae), the HP C compiler defines "__hpux"
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "system.h"
#include "sound.h"
+#include "joystick.h"
#include "misc.h"
/* load image to temporary surface */
if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
- Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
+ {
+ SetError("IMG_Load(): %s", SDL_GetError());
+ return NULL;
+ }
/* create native non-transparent surface for current image */
if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
- Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
+ {
+ SetError("SDL_DisplayFormat(): %s", SDL_GetError());
+ return NULL;
+ }
/* 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)
- Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
+ {
+ SetError("SDL_DisplayFormat(): %s", SDL_GetError());
+ return NULL;
+ }
/* 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;
}
return;
}
- if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
- AUDIO_STEREO_CHANNELS,
+ if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
+ AUDIO_NUM_CHANNELS_STEREO,
DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
{
Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
audio.loops_available = TRUE;
audio.sound_enabled = TRUE;
- /* determine number of available channels */
- audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
-
- if (!audio.mods_available) /* reserve first channel for music loops */
- {
- if (Mix_ReserveChannels(1) == 1)
- audio.music_channel = 0;
- else
- audio.music_available = FALSE;
- }
+ /* 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;
- Mix_Volume(-1, SOUND_MAX_VOLUME);
- Mix_VolumeMusic(SOUND_MAX_VOLUME);
+ Mixer_InitChannels();
}
inline void SDLCloseAudio(void)
#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;
+ 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++)
+ {
+ char *device_name = setup.input[i].joy.device_name;
+ int joystick_nr = getJoystickNrFromDeviceName(device_name);
+
+ if (joystick_nr >= SDL_NumJoysticks())
+ joystick_nr = -1;
+
+ /* misuse joystick file descriptor variable to store joystick number */
+ joystick.fd[i] = joystick_nr;
+
+ /* 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))
+ {
+ 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 */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
struct SDLSurfaceInfo
{
+ char *source_filename;
+
+ int width, height;
SDL_Surface *surface;
SDL_Surface *surface_masked;
GC gc;
#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)
+
/* SDL function definitions */
inline void SDLNextEvent(Event *);
+void HandleJoystickEvent(Event *);
+void SDLInitJoysticks(void);
+boolean SDLReadJoystick(int, int *, int *, boolean *, boolean *);
+
#endif /* SDL_H */
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1994-2002 Artsoft Entertainment *
+* Holger Schemel *
+* Detmolder Strasse 189 *
+* 33604 Bielefeld *
+* Germany *
+* e-mail: info@artsoft.org *
+*----------------------------------------------------------*
+* setup.c *
+***********************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "setup.h"
+#include "joystick.h"
+#include "text.h"
+#include "misc.h"
+
+/* file names and filename extensions */
+#if !defined(PLATFORM_MSDOS)
+#define LEVELSETUP_DIRECTORY "levelsetup"
+#define SETUP_FILENAME "setup.conf"
+#define LEVELSETUP_FILENAME "levelsetup.conf"
+#define LEVELINFO_FILENAME "levelinfo.conf"
+#define GRAPHICSINFO_FILENAME "graphicsinfo.conf"
+#define SOUNDSINFO_FILENAME "soundsinfo.conf"
+#define MUSICINFO_FILENAME "musicinfo.conf"
+#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 LEVELINFO_FILENAME "lvlinfo.cnf"
+#define GRAPHICSINFO_FILENAME "gfxinfo.cnf"
+#define SOUNDSINFO_FILENAME "sndinfo.cnf"
+#define MUSICINFO_FILENAME "musinfo.cnf"
+#define LEVELFILE_EXTENSION "lvl"
+#define TAPEFILE_EXTENSION "tap"
+#define SCOREFILE_EXTENSION "sco"
+#endif
+
+#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_GREEN : \
+ IS_LEVELCLASS_EM(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_SP(n) ? FC_GREEN : \
+ IS_LEVELCLASS_DX(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \
+ IS_LEVELCLASS_USER(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_CONTRIBUTION(n) ? 6 : \
+ IS_LEVELCLASS_USER(n) ? 7 : \
+ 9)
+
+#define ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \
+ IS_ARTWORKCLASS_CONTRIBUTION(n) ? FC_YELLOW : \
+ IS_ARTWORKCLASS_LEVEL(n) ? FC_GREEN : \
+ IS_ARTWORKCLASS_USER(n) ? FC_RED : \
+ FC_BLUE)
+
+#define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ? 0 : \
+ IS_ARTWORKCLASS_CONTRIBUTION(n) ? 1 : \
+ IS_ARTWORKCLASS_LEVEL(n) ? 2 : \
+ IS_ARTWORKCLASS_USER(n) ? 3 : \
+ 9)
+
+#define TOKEN_VALUE_POSITION 40
+#define TOKEN_COMMENT_POSITION 60
+
+#define MAX_COOKIE_LEN 256
+
+#define ARTWORKINFO_FILENAME(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
+ GRAPHICSINFO_FILENAME : \
+ (type) == TREE_TYPE_SOUNDS_DIR ? \
+ SOUNDSINFO_FILENAME : \
+ (type) == TREE_TYPE_MUSIC_DIR ? \
+ MUSICINFO_FILENAME : "")
+
+#define ARTWORK_DIRECTORY(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
+ GRAPHICS_DIRECTORY : \
+ (type) == TREE_TYPE_SOUNDS_DIR ? \
+ SOUNDS_DIRECTORY : \
+ (type) == TREE_TYPE_MUSIC_DIR ? \
+ MUSIC_DIRECTORY : "")
+
+#define OPTIONS_ARTWORK_DIRECTORY(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
+ options.graphics_directory : \
+ (type) == TREE_TYPE_SOUNDS_DIR ? \
+ options.sounds_directory : \
+ (type) == TREE_TYPE_MUSIC_DIR ? \
+ options.music_directory : "")
+
+
+/* ------------------------------------------------------------------------- */
+/* file functions */
+/* ------------------------------------------------------------------------- */
+
+static char *getLevelClassDescription(TreeInfo *ldi)
+{
+ int position = ldi->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 = getUserDataDir();
+ char *userlevel_subdir = LEVELS_DIRECTORY;
+
+ if (userlevel_dir)
+ 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 *getTapeDir(char *level_subdir)
+{
+ static char *tape_dir = NULL;
+ char *data_dir = getUserDataDir();
+ char *tape_subdir = TAPES_DIRECTORY;
+
+ if (tape_dir)
+ 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 *getScoreDir(char *level_subdir)
+{
+ static char *score_dir = NULL;
+ char *data_dir = options.rw_base_directory;
+ char *score_subdir = SCORES_DIRECTORY;
+
+ if (score_dir)
+ 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 = getUserDataDir();
+ char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
+
+ if (levelsetup_dir)
+ 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 *getLevelDirFromTreeInfo(TreeInfo *node)
+{
+ static char *level_dir = NULL;
+
+ if (node == NULL)
+ return options.level_directory;
+
+ if (level_dir)
+ free(level_dir);
+
+ level_dir = getPath2((node->user_defined ? getUserLevelDir(NULL) :
+ options.level_directory), node->fullpath);
+
+ return level_dir;
+}
+
+static char *getCurrentLevelDir()
+{
+ return getLevelDirFromTreeInfo(leveldir_current);
+}
+
+static char *getDefaultGraphicsDir(char *graphics_subdir)
+{
+ static char *graphics_dir = NULL;
+
+ if (graphics_subdir == NULL)
+ return options.graphics_directory;
+
+ if (graphics_dir)
+ 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;
+
+ if (sounds_dir)
+ 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;
+
+ if (music_dir)
+ free(music_dir);
+
+ music_dir = getPath2(options.music_directory, music_subdir);
+
+ return music_dir;
+}
+
+static char *getUserGraphicsDir()
+{
+ static char *usergraphics_dir = NULL;
+
+ if (usergraphics_dir == NULL)
+ usergraphics_dir = getPath2(getUserDataDir(), GRAPHICS_DIRECTORY);
+
+ return usergraphics_dir;
+}
+
+static char *getUserSoundsDir()
+{
+ static char *usersounds_dir = NULL;
+
+ if (usersounds_dir == NULL)
+ usersounds_dir = getPath2(getUserDataDir(), SOUNDS_DIRECTORY);
+
+ return usersounds_dir;
+}
+
+static char *getUserMusicDir()
+{
+ static char *usermusic_dir = NULL;
+
+ if (usermusic_dir == NULL)
+ usermusic_dir = getPath2(getUserDataDir(), MUSIC_DIRECTORY);
+
+ return usermusic_dir;
+}
+
+char *getLevelFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+ filename = getPath2(getCurrentLevelDir(), basename);
+
+ return filename;
+}
+
+char *getTapeFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
+ filename = getPath2(getTapeDir(leveldir_current->filename), basename);
+
+ return filename;
+}
+
+char *getScoreFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
+ filename = getPath2(getScoreDir(leveldir_current->filename), basename);
+
+ return filename;
+}
+
+char *getSetupFilename()
+{
+ static char *filename = NULL;
+
+ if (filename != NULL)
+ free(filename);
+
+ filename = getPath2(getSetupDir(), SETUP_FILENAME);
+
+ return filename;
+}
+
+static char *getSetupArtworkDir(TreeInfo *ti)
+{
+ static char *artwork_dir = NULL;
+
+ if (artwork_dir != NULL)
+ free(artwork_dir);
+
+ artwork_dir = getPath2(ti->basepath, ti->fullpath);
+
+ return artwork_dir;
+}
+
+static char *getCorrectedImageBasename(char *basename)
+{
+ char *result = 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)
+ result = &basename[prefix_len];
+ }
+#endif
+
+ return result;
+}
+
+static boolean fileExists(char *filename)
+{
+#if 0
+ printf("checking file '%s'\n", filename);
+#endif
+
+ return (access(filename, F_OK) == 0);
+}
+
+char *getCustomImageFilename(char *basename)
+{
+ static char *filename = NULL;
+
+ if (filename != NULL)
+ free(filename);
+
+ basename = getCorrectedImageBasename(basename);
+
+ if (!setup.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;
+ }
+
+ /* 2nd try: look for special artwork in configured artwork directory */
+ filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
+ if (fileExists(filename))
+ return filename;
+
+ /* 3rd try: look for default artwork in new default artwork directory */
+ filename = getPath2(getDefaultGraphicsDir(GRAPHICS_SUBDIR), basename);
+ if (fileExists(filename))
+ return filename;
+
+ /* 4th 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 */
+}
+
+char *getCustomSoundFilename(char *basename)
+{
+ static char *filename = NULL;
+
+ if (filename != NULL)
+ free(filename);
+
+ if (!setup.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;
+ }
+
+ /* 2nd try: look for special artwork in configured artwork directory */
+ filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
+ if (fileExists(filename))
+ return filename;
+
+ /* 3rd try: look for default artwork in new default artwork directory */
+ filename = getPath2(getDefaultSoundsDir(SOUNDS_SUBDIR), basename);
+ if (fileExists(filename))
+ return filename;
+
+ /* 4th try: look for default artwork in old default artwork directory */
+ filename = getPath2(options.sounds_directory, basename);
+ if (fileExists(filename))
+ return filename;
+
+ return NULL; /* cannot find specified artwork file anywhere */
+}
+
+char *getCustomSoundConfigFilename()
+{
+ return getCustomSoundFilename(SOUNDSINFO_FILENAME);
+}
+
+char *getCustomMusicDirectory(void)
+{
+ static char *directory = NULL;
+
+ if (directory != NULL)
+ free(directory);
+
+ if (!setup.override_level_music)
+ {
+ /* 1st try: look for special artwork in current level series directory */
+ directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
+ if (fileExists(directory))
+ return directory;
+ }
+
+ /* 2nd try: look for special artwork in configured artwork directory */
+ directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
+ if (fileExists(directory))
+ return directory;
+
+ /* 3rd try: look for default artwork in new default artwork directory */
+ directory = getStringCopy(getDefaultMusicDir(MUSIC_SUBDIR));
+ if (fileExists(directory))
+ return directory;
+
+ /* 4th 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(getUserDataDir(), "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(getScoreDir(NULL), "main score", PERMS_PUBLIC);
+ createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC);
+}
+
+static void SaveUserLevelInfo();
+
+void InitUserLevelDirectory(char *level_subdir)
+{
+ if (access(getUserLevelDir(level_subdir), F_OK) != 0)
+ {
+ createDirectory(getUserDataDir(), "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(getUserDataDir(), "user data", PERMS_PRIVATE);
+ createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE);
+ createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* some functions to handle lists of level directories */
+/* ------------------------------------------------------------------------- */
+
+TreeInfo *newTreeInfo()
+{
+ return checked_calloc(sizeof(TreeInfo));
+}
+
+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 *getTreeInfoFromFilenameExt(TreeInfo *node, char *filename)
+{
+ if (filename == NULL)
+ return NULL;
+
+ while (node)
+ {
+ if (node->node_group)
+ {
+ TreeInfo *node_group;
+
+ node_group = getTreeInfoFromFilenameExt(node->node_group, filename);
+
+ if (node_group)
+ return node_group;
+ }
+ else if (!node->parent_link)
+ {
+ if (strcmp(filename, node->filename) == 0)
+ return node;
+
+ /* special case when looking for level series artwork:
+ node->name_short contains level series filename */
+ if (strcmp(node->filename, ".") == 0 &&
+ strcmp(filename, node->name_short) == 0)
+ return node;
+ }
+
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+TreeInfo *getTreeInfoFromFilename(TreeInfo *ti, char *filename)
+{
+ return getTreeInfoFromFilenameExt(ti, filename);
+}
+
+void dumpTreeInfo(TreeInfo *node, int depth)
+{
+ int i;
+
+ printf("Dumping TreeInfo:\n");
+
+ while (node)
+ {
+ for (i=0; i<(depth + 1) * 3; i++)
+ printf(" ");
+
+ printf("filename == '%s' (%s) [%s] (%d)\n",
+ node->filename, node->name, node->name_short, node->sort_priority);
+
+ if (node->node_group != NULL)
+ dumpTreeInfo(node->node_group, depth + 1);
+
+ node = node->next;
+ }
+}
+
+void sortTreeInfo(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)
+ sortTreeInfo(&node->node_group, compare_function);
+
+ node = node->next;
+ }
+}
+
+
+/* ========================================================================= */
+/* 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 *getUserDataDir(void)
+{
+ static char *userdata_dir = NULL;
+
+ if (!userdata_dir)
+ {
+ char *home_dir = getHomeDir();
+ char *data_dir = program.userdata_directory;
+
+ userdata_dir = getPath2(home_dir, data_dir);
+ }
+
+ return userdata_dir;
+}
+
+char *getSetupDir()
+{
+ return getUserDataDir();
+}
+
+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
+}
+
+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 normal_umask = posix_umask(0);
+ mode_t group_umask = ~(dir_mode & S_IRWXG);
+ posix_umask(normal_umask & group_umask);
+
+ if (access(dir, F_OK) != 0)
+ if (posix_mkdir(dir, dir_mode) != 0)
+ Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
+
+ posix_umask(normal_umask); /* reset normal umask */
+}
+
+void InitUserDataDirectory()
+{
+ createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+}
+
+void SetFilePermissions(char *filename, int permission_class)
+{
+ chmod(filename, (permission_class == PERMS_PRIVATE ?
+ FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC));
+}
+
+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);
+}
+
+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 handling functions */
+/* ------------------------------------------------------------------------- */
+
+int get_string_integer_value(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" },
+ };
+
+ int i, j;
+ char *s_lower = getStringToLower(s);
+ int result = -1;
+
+ for (i=0; i<13; i++)
+ for (j=0; j<3; j++)
+ if (strcmp(s_lower, number_text[i][j]) == 0)
+ result = i;
+
+ if (result == -1)
+ result = atoi(s);
+
+ free(s_lower);
+
+ return result;
+}
+
+boolean get_string_boolean_value(char *s)
+{
+ char *s_lower = getStringToLower(s);
+ boolean result = FALSE;
+
+ if (strcmp(s_lower, "true") == 0 ||
+ strcmp(s_lower, "yes") == 0 ||
+ strcmp(s_lower, "on") == 0 ||
+ get_string_integer_value(s) == 1)
+ result = TRUE;
+
+ free(s_lower);
+
+ return result;
+}
+
+char *getFormattedSetupEntry(char *token, char *value)
+{
+ int i;
+ static char entry[MAX_LINE_LEN];
+
+ /* 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;
+}
+
+void freeSetupFileList(struct SetupFileList *setup_file_list)
+{
+ if (!setup_file_list)
+ return;
+
+ if (setup_file_list->token)
+ free(setup_file_list->token);
+ if (setup_file_list->value)
+ free(setup_file_list->value);
+ if (setup_file_list->next)
+ freeSetupFileList(setup_file_list->next);
+ free(setup_file_list);
+}
+
+static struct SetupFileList *newSetupFileList(char *token, char *value)
+{
+ struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
+
+ new->token = checked_malloc(strlen(token) + 1);
+ strcpy(new->token, token);
+
+ new->value = checked_malloc(strlen(value) + 1);
+ strcpy(new->value, value);
+
+ new->next = NULL;
+
+ return new;
+}
+
+char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
+{
+ if (!setup_file_list)
+ return NULL;
+
+ if (strcmp(setup_file_list->token, token) == 0)
+ return setup_file_list->value;
+ else
+ return getTokenValue(setup_file_list->next, token);
+}
+
+static void setTokenValue(struct SetupFileList *setup_file_list,
+ char *token, char *value)
+{
+ if (!setup_file_list)
+ return;
+
+ if (strcmp(setup_file_list->token, token) == 0)
+ {
+ free(setup_file_list->value);
+ setup_file_list->value = checked_malloc(strlen(value) + 1);
+ strcpy(setup_file_list->value, value);
+ }
+ else if (setup_file_list->next == NULL)
+ setup_file_list->next = newSetupFileList(token, value);
+ else
+ setTokenValue(setup_file_list->next, token, value);
+}
+
+#ifdef DEBUG
+static void printSetupFileList(struct SetupFileList *setup_file_list)
+{
+ if (!setup_file_list)
+ return;
+
+ printf("token: '%s'\n", setup_file_list->token);
+ printf("value: '%s'\n", setup_file_list->value);
+
+ printSetupFileList(setup_file_list->next);
+}
+#endif
+
+struct SetupFileList *loadSetupFileList(char *filename)
+{
+ int line_len;
+ char line[MAX_LINE_LEN];
+ char *token, *value, *line_ptr;
+ struct SetupFileList *setup_file_list = newSetupFileList("", "");
+ struct SetupFileList *first_valid_list_entry;
+
+ FILE *file;
+
+ if (!(file = fopen(filename, MODE_READ)))
+ {
+ Error(ERR_WARN, "cannot open configuration file '%s'", filename);
+ return NULL;
+ }
+
+ while(!feof(file))
+ {
+ /* read next line of input file */
+ if (!fgets(line, MAX_LINE_LEN, file))
+ break;
+
+ /* cut trailing comment or whitespace from input line */
+ for (line_ptr = line; *line_ptr; line_ptr++)
+ {
+ if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
+ {
+ *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;
+
+ line_len = strlen(line);
+
+ /* cut leading whitespaces from token */
+ for (token = line; *token; token++)
+ if (*token != ' ' && *token != '\t')
+ break;
+
+ /* find end of token */
+ for (line_ptr = token; *line_ptr; line_ptr++)
+ {
+ if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
+ {
+ *line_ptr = '\0';
+ break;
+ }
+ }
+
+ if (line_ptr < line + line_len)
+ value = line_ptr + 1;
+ else
+ value = "\0";
+
+ /* cut leading whitespaces from value */
+ for (; *value; value++)
+ if (*value != ' ' && *value != '\t')
+ break;
+
+ if (*token && *value)
+ setTokenValue(setup_file_list, token, value);
+ }
+
+ fclose(file);
+
+ first_valid_list_entry = setup_file_list->next;
+
+ /* free empty list header */
+ setup_file_list->next = NULL;
+ freeSetupFileList(setup_file_list);
+
+ if (first_valid_list_entry == NULL)
+ Error(ERR_WARN, "configuration file '%s' is empty", filename);
+
+ return first_valid_list_entry;
+}
+
+void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
+ char *identifier)
+{
+ if (!setup_file_list)
+ return;
+
+ if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
+ {
+ if (!checkCookieString(setup_file_list->value, identifier))
+ {
+ Error(ERR_WARN, "configuration file has wrong file identifier");
+ return;
+ }
+ else
+ return;
+ }
+
+ if (setup_file_list->next)
+ checkSetupFileListIdentifier(setup_file_list->next, identifier);
+ else
+ {
+ Error(ERR_WARN, "configuration file has no file identifier");
+ return;
+ }
+}
+
+
+/* ========================================================================= */
+/* 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_NAME 0
+#define LEVELINFO_TOKEN_NAME_SHORT 1
+#define LEVELINFO_TOKEN_NAME_SORTING 2
+#define LEVELINFO_TOKEN_AUTHOR 3
+#define LEVELINFO_TOKEN_IMPORTED_FROM 4
+#define LEVELINFO_TOKEN_LEVELS 5
+#define LEVELINFO_TOKEN_FIRST_LEVEL 6
+#define LEVELINFO_TOKEN_SORT_PRIORITY 7
+#define LEVELINFO_TOKEN_LEVEL_GROUP 8
+#define LEVELINFO_TOKEN_READONLY 9
+
+#define NUM_LEVELINFO_TOKENS 10
+
+static LevelDirTree ldi;
+
+static struct TokenInfo levelinfo_tokens[] =
+{
+ /* level directory info */
+ { TYPE_STRING, &ldi.name, "name" },
+ { TYPE_STRING, &ldi.name_short, "name_short" },
+ { TYPE_STRING, &ldi.name_sorting, "name_sorting" },
+ { TYPE_STRING, &ldi.author, "author" },
+ { TYPE_STRING, &ldi.imported_from, "imported_from" },
+ { TYPE_INTEGER, &ldi.levels, "levels" },
+ { TYPE_INTEGER, &ldi.first_level, "first_level" },
+ { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" },
+ { TYPE_BOOLEAN, &ldi.level_group, "level_group" },
+ { TYPE_BOOLEAN, &ldi.readonly, "readonly" }
+};
+
+static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
+{
+ ldi->type = type;
+
+ ldi->node_top = (ldi->type == TREE_TYPE_LEVEL_DIR ? &leveldir_first :
+ ldi->type == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first :
+ ldi->type == TREE_TYPE_SOUNDS_DIR ? &artwork.snd_first :
+ ldi->type == TREE_TYPE_MUSIC_DIR ? &artwork.mus_first :
+ NULL);
+
+ ldi->node_parent = NULL;
+ ldi->node_group = NULL;
+ ldi->next = NULL;
+
+ ldi->cl_first = -1;
+ ldi->cl_cursor = -1;
+
+ ldi->filename = NULL;
+ ldi->fullpath = NULL;
+ ldi->basepath = NULL;
+ ldi->name = getStringCopy(ANONYMOUS_NAME);
+ ldi->name_short = NULL;
+ ldi->name_sorting = NULL;
+ ldi->author = getStringCopy(ANONYMOUS_NAME);
+
+ ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */
+ ldi->parent_link = FALSE;
+ ldi->user_defined = FALSE;
+ ldi->color = 0;
+ ldi->class_desc = NULL;
+
+ if (ldi->type == TREE_TYPE_LEVEL_DIR)
+ {
+ ldi->imported_from = NULL;
+ ldi->levels = 0;
+ ldi->first_level = 0;
+ ldi->last_level = 0;
+ ldi->level_group = FALSE;
+ ldi->handicap_level = 0;
+ ldi->readonly = TRUE;
+ }
+}
+
+static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
+{
+ if (parent == NULL)
+ {
+ Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
+
+ setTreeInfoToDefaults(ldi, TREE_TYPE_GENERIC);
+ return;
+ }
+
+ /* first copy all values from the parent structure ... */
+ *ldi = *parent;
+
+ /* ... then set all fields to default that cannot be inherited from parent.
+ This is especially important for all those fields that can be set from
+ the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
+ calls 'free()' for all already set token values which requires that no
+ other structure's pointer may point to them!
+ */
+
+ ldi->filename = NULL;
+ ldi->fullpath = NULL;
+ ldi->basepath = NULL;
+ ldi->name = getStringCopy(ANONYMOUS_NAME);
+ ldi->name_short = NULL;
+ ldi->name_sorting = NULL;
+ ldi->author = getStringCopy(parent->author);
+ ldi->imported_from = getStringCopy(parent->imported_from);
+
+ ldi->level_group = FALSE;
+ ldi->parent_link = FALSE;
+
+ ldi->node_top = parent->node_top;
+ ldi->node_parent = parent;
+ ldi->node_group = NULL;
+ ldi->next = NULL;
+}
+
+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_string_boolean_value(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_string_integer_value(token_value);
+ break;
+
+ case TYPE_STRING:
+ if (*(char **)setup_value != NULL)
+ 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;
+
+ ti_new->name = ".. (parent directory)";
+ ti_new->name_short = getStringCopy(ti_new->name);
+ ti_new->name_sorting = getStringCopy(ti_new->name);
+
+ ti_new->filename = "..";
+ ti_new->fullpath = getStringCopy(node_parent->fullpath);
+
+ ti_new->sort_priority = node_parent->sort_priority;
+ ti_new->class_desc = getLevelClassDescription(ti_new);
+
+ pushTreeInfo(&node_parent->node_group, ti_new);
+}
+
+/* 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)
+{
+ char *directory_path = getPath2(level_directory, directory_name);
+ char *filename = getPath2(directory_path, LEVELINFO_FILENAME);
+ struct SetupFileList *setup_file_list = loadSetupFileList(filename);
+ LevelDirTree *leveldir_new = NULL;
+ int i;
+
+ if (setup_file_list == 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->filename = getStringCopy(directory_name);
+
+ checkSetupFileListIdentifier(setup_file_list, 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,
+ getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+ *leveldir_new = ldi;
+
+ if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
+ {
+ free(leveldir_new->name);
+ leveldir_new->name = getStringCopy(leveldir_new->filename);
+ }
+
+ DrawInitText(leveldir_new->name, 150, FC_YELLOW);
+
+ if (leveldir_new->name_short == NULL)
+ leveldir_new->name_short = getStringCopy(leveldir_new->name);
+
+ if (leveldir_new->name_sorting == NULL)
+ leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
+
+ if (node_parent == NULL) /* top level group */
+ {
+ leveldir_new->basepath = level_directory;
+ leveldir_new->fullpath = leveldir_new->filename;
+ }
+ else /* sub level group */
+ {
+ leveldir_new->basepath = node_parent->basepath;
+ leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
+ }
+
+ if (leveldir_new->levels < 1)
+ leveldir_new->levels = 1;
+
+ leveldir_new->last_level =
+ leveldir_new->first_level + leveldir_new->levels - 1;
+
+ leveldir_new->user_defined =
+ (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
+
+ leveldir_new->color = LEVELCOLOR(leveldir_new);
+ leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
+
+ leveldir_new->handicap_level = /* set handicap to default value */
+ (leveldir_new->user_defined ?
+ leveldir_new->last_level :
+ leveldir_new->first_level);
+
+ pushTreeInfo(node_first, leveldir_new);
+
+ freeSetupFileList(setup_file_list);
+
+ if (leveldir_new->level_group)
+ {
+ /* create node to link back to current level directory */
+ createParentTreeInfoNode(leveldir_new);
+
+ /* 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 (strcmp(directory_name, ".") == 0 ||
+ strcmp(directory_name, "..") == 0)
+ {
+ 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 (strcmp(directory_name, GRAPHICS_DIRECTORY) == 0 ||
+ strcmp(directory_name, SOUNDS_DIRECTORY) == 0 ||
+ strcmp(directory_name, MUSIC_DIRECTORY) == 0)
+ continue;
+
+ valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent,
+ level_directory,
+ directory_name);
+ }
+
+ closedir(dir);
+
+ if (!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);
+}
+
+void LoadLevelInfo()
+{
+ InitUserLevelDirectory(getLoginName());
+
+ DrawInitText("Loading level series:", 120, FC_GREEN);
+
+ LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
+ LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
+
+ /* 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, compareTreeInfoEntries);
+
+#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));
+ struct SetupFileList *setup_file_list = NULL;
+ TreeInfo *artwork_new = NULL;
+ int i;
+
+ if (access(filename, F_OK) == 0) /* file exists */
+ setup_file_list = loadSetupFileList(filename);
+
+ if (setup_file_list == 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 (strcmp(directory_name, ".") != 0)
+ 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->filename = getStringCopy(directory_name);
+
+ if (setup_file_list) /* (before defining ".color" and ".class_desc") */
+ {
+#if 0
+ checkSetupFileListIdentifier(setup_file_list, 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,
+ getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+ *artwork_new = ldi;
+
+ if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
+ {
+ free(artwork_new->name);
+ artwork_new->name = getStringCopy(artwork_new->filename);
+ }
+
+#if 0
+ DrawInitText(artwork_new->name, 150, FC_YELLOW);
+#endif
+
+ if (artwork_new->name_short == NULL)
+ artwork_new->name_short = getStringCopy(artwork_new->name);
+
+ 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->filename);
+ }
+ else /* sub level group */
+ {
+ artwork_new->basepath = getStringCopy(node_parent->basepath);
+ artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
+ }
+
+ artwork_new->user_defined =
+ (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
+
+ /* (may use ".sort_priority" from "setup_file_list" above) */
+ artwork_new->color = ARTWORKCOLOR(artwork_new);
+ artwork_new->class_desc = getLevelClassDescription(artwork_new);
+
+ if (setup_file_list == NULL) /* (after determining ".user_defined") */
+ {
+ if (artwork_new->name != NULL)
+ free(artwork_new->name);
+
+ if (strcmp(artwork_new->filename, ".") == 0)
+ {
+ if (artwork_new->user_defined)
+ {
+ artwork_new->name = getStringCopy("private");
+ artwork_new->sort_priority = ARTWORKCLASS_USER;
+ }
+ else
+ {
+ artwork_new->name = getStringCopy("classic");
+ artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
+ }
+
+ artwork_new->color = ARTWORKCOLOR(artwork_new);
+ artwork_new->class_desc = getLevelClassDescription(artwork_new);
+ }
+ else
+ artwork_new->name = getStringCopy(artwork_new->filename);
+
+ artwork_new->name_short = getStringCopy(artwork_new->name);
+ artwork_new->name_sorting = getStringCopy(artwork_new->name);
+ }
+
+ DrawInitText(artwork_new->name, 150, FC_YELLOW);
+
+ pushTreeInfo(node_first, artwork_new);
+
+ freeSetupFileList(setup_file_list);
+
+ 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)
+ {
+ 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 entries for current and parent directory */
+ if (strcmp(directory_name, ".") == 0 ||
+ strcmp(directory_name, "..") == 0)
+ {
+ 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);
+
+ /* 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);
+
+ artwork_new->filename = getStringCopy(NOT_AVAILABLE);
+ artwork_new->fullpath = getStringCopy(NOT_AVAILABLE);
+ artwork_new->basepath = getStringCopy(NOT_AVAILABLE);
+
+ if (artwork_new->name != NULL)
+ free(artwork_new->name);
+
+ artwork_new->name = getStringCopy(NOT_AVAILABLE);
+ artwork_new->name_short = getStringCopy(NOT_AVAILABLE);
+ artwork_new->name_sorting = getStringCopy(NOT_AVAILABLE);
+
+ return artwork_new;
+}
+
+void LoadArtworkInfo()
+{
+ 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 =
+ getTreeInfoFromFilename(artwork.gfx_first, setup.graphics_set);
+ if (artwork.gfx_current == NULL)
+ artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
+
+ artwork.snd_current =
+ getTreeInfoFromFilename(artwork.snd_first, setup.sounds_set);
+ if (artwork.snd_current == NULL)
+ artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
+
+ artwork.mus_current =
+ getTreeInfoFromFilename(artwork.mus_first, setup.music_set);
+ if (artwork.mus_current == NULL)
+ artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
+
+ artwork.graphics_set_current_name = artwork.gfx_current->name;
+ artwork.sounds_set_current_name = artwork.snd_current->name;
+ artwork.music_set_current_name = artwork.mus_current->name;
+
+#if 0
+ printf("graphics set == %s\n\n", artwork.graphics_set_current_name);
+ printf("sounds set == %s\n\n", artwork.sounds_set_current_name);
+ printf("music set == %s\n\n", artwork.music_set_current_name);
+#endif
+
+ sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
+ sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
+ sortTreeInfo(&artwork.mus_first, compareTreeInfoEntries);
+
+#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)
+{
+ /* recursively check all level directories for artwork sub-directories */
+
+ while (level_node)
+ {
+ char *path = getPath2(getLevelDirFromTreeInfo(level_node),
+ ARTWORK_DIRECTORY((*artwork_node)->type));
+
+#if 0
+ if (!level_node->parent_link)
+ printf("CHECKING '%s' ['%s', '%s'] ...\n", path,
+ level_node->filename, level_node->name);
+#endif
+
+ if (!level_node->parent_link)
+ {
+ TreeInfo *topnode_last = *artwork_node;
+
+ LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path,
+ (*artwork_node)->type);
+
+ if (topnode_last != *artwork_node)
+ {
+ free((*artwork_node)->name);
+ free((*artwork_node)->name_sorting);
+ free((*artwork_node)->name_short);
+
+ (*artwork_node)->name = getStringCopy(level_node->name);
+ (*artwork_node)->name_sorting = getStringCopy(level_node->name);
+ (*artwork_node)->name_short = getStringCopy(level_node->filename);
+
+ (*artwork_node)->sort_priority = level_node->sort_priority;
+ (*artwork_node)->color = LEVELCOLOR((*artwork_node));
+ }
+ }
+
+ free(path);
+
+ 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);
+ LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first);
+ LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
+
+ sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
+ sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
+ sortTreeInfo(&artwork.mus_first, compareTreeInfoEntries);
+
+#if 0
+ dumpTreeInfo(artwork.gfx_first, 0);
+ dumpTreeInfo(artwork.snd_first, 0);
+ dumpTreeInfo(artwork.mus_first, 0);
+#endif
+}
+
+static void SaveUserLevelInfo()
+{
+ 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;
+ }
+
+ /* always start with reliable default values */
+ setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR);
+
+ ldi.name = getStringCopy(getLoginName());
+ ldi.author = getStringCopy(getRealName());
+ ldi.levels = 100;
+ ldi.first_level = 1;
+ ldi.sort_priority = LEVELCLASS_USER_START;
+ ldi.readonly = FALSE;
+
+ fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+ getCookie("LEVELINFO")));
+
+ for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+ if (i != LEVELINFO_TOKEN_NAME_SHORT &&
+ i != LEVELINFO_TOKEN_NAME_SORTING &&
+ i != LEVELINFO_TOKEN_IMPORTED_FROM)
+ fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
+
+ fclose(file);
+ free(filename);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+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_YES_NO:
+ strcpy(value_string, (*(boolean *)value ? "yes" : "no"));
+ 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:
+ strcpy(value_string, *(char **)value);
+ break;
+
+ default:
+ value_string[0] = '\0';
+ break;
+ }
+
+ 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 (strcmp(keyname, "(undefined)") != 0 &&
+ strcmp(keyname, "(unknown)") != 0)
+ {
+ /* 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()
+{
+ char *filename;
+ struct SetupFileList *level_setup_list = NULL;
+
+ /* always start with reliable default values */
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+
+ /* ----------------------------------------------------------------------- */
+ /* ~/.<program>/levelsetup.conf */
+ /* ----------------------------------------------------------------------- */
+
+ filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+
+ if ((level_setup_list = loadSetupFileList(filename)))
+ {
+ char *last_level_series =
+ getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
+
+ leveldir_current = getTreeInfoFromFilename(leveldir_first,
+ last_level_series);
+ if (leveldir_current == NULL)
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+
+ checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+
+ freeSetupFileList(level_setup_list);
+ }
+ else
+ Error(ERR_WARN, "using default setup values");
+
+ free(filename);
+}
+
+void SaveLevelSetup_LastSeries()
+{
+ char *filename;
+ char *level_subdir = leveldir_current->filename;
+ FILE *file;
+
+ /* ----------------------------------------------------------------------- */
+ /* ~/.<program>/levelsetup.conf */
+ /* ----------------------------------------------------------------------- */
+
+ InitUserDataDirectory();
+
+ filename = getPath2(getSetupDir(), 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_LEVEL_SERIES,
+ level_subdir));
+
+ fclose(file);
+ free(filename);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+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->user_defined ?
+ 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] == '.' &&
+ strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
+ {
+ 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 (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;
+ }
+ }
+ }
+
+ closedir(dir);
+}
+
+void LoadLevelSetup_SeriesInfo()
+{
+ char *filename;
+ struct SetupFileList *level_setup_list = NULL;
+ char *level_subdir = leveldir_current->filename;
+
+ /* always start with reliable default values */
+ level_nr = leveldir_current->first_level;
+
+ checkSeriesInfo(leveldir_current);
+
+ /* ----------------------------------------------------------------------- */
+ /* ~/.<program>/levelsetup/<level series>/levelsetup.conf */
+ /* ----------------------------------------------------------------------- */
+
+ level_subdir = leveldir_current->filename;
+
+ filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
+
+ if ((level_setup_list = loadSetupFileList(filename)))
+ {
+ char *token_value;
+
+ token_value = getTokenValue(level_setup_list, 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 = getTokenValue(level_setup_list, 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)
+ level_nr = leveldir_current->last_level;
+
+ leveldir_current->handicap_level = level_nr;
+ }
+
+ checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+
+ freeSetupFileList(level_setup_list);
+ }
+ else
+ Error(ERR_WARN, "using default setup values");
+
+ free(filename);
+}
+
+void SaveLevelSetup_SeriesInfo()
+{
+ char *filename;
+ char *level_subdir = leveldir_current->filename;
+ char *level_nr_str = int2str(level_nr, 0);
+ char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
+ FILE *file;
+
+ /* ----------------------------------------------------------------------- */
+ /* ~/.<program>/levelsetup/<level series>/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);
+ free(filename);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1994-2002 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"
+
+
+/* values for setup file handling */
+#define TYPE_BOOLEAN (1 << 0)
+#define TYPE_SWITCH (1 << 1)
+#define TYPE_YES_NO (1 << 2)
+#define TYPE_KEY (1 << 3)
+#define TYPE_KEY_X11 (1 << 4)
+#define TYPE_INTEGER (1 << 5)
+#define TYPE_STRING (1 << 6)
+
+#define TYPE_BOOLEAN_STYLE (TYPE_BOOLEAN | \
+ TYPE_SWITCH | \
+ TYPE_YES_NO)
+
+/* additional values for setup screen */
+#define TYPE_ENTER_MENU (1 << 7)
+#define TYPE_LEAVE_MENU (1 << 8)
+#define TYPE_EMPTY (1 << 9)
+#define TYPE_KEYTEXT (1 << 10)
+
+#define TYPE_GHOSTED (1 << 11)
+#define TYPE_QUERY (1 << 12)
+
+#define TYPE_VALUE (TYPE_BOOLEAN_STYLE | \
+ TYPE_KEY | \
+ TYPE_KEY_X11 | \
+ TYPE_INTEGER | \
+ TYPE_STRING)
+
+#define TYPE_SKIP_ENTRY (TYPE_EMPTY | \
+ TYPE_KEY | \
+ TYPE_STRING)
+
+#define TYPE_ENTER_OR_LEAVE_MENU (TYPE_ENTER_MENU | \
+ TYPE_LEAVE_MENU)
+
+/* cookie token for file identifier and version number */
+#define TOKEN_STR_FILE_IDENTIFIER "file_identifier"
+
+/* structures for setup file handling */
+struct SetupFileList
+{
+ char *token;
+ char *value;
+ struct SetupFileList *next;
+};
+
+struct TokenInfo
+{
+ int type;
+ void *value;
+ char *text;
+};
+
+/* 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_CONTRIBUTION_START 200
+#define LEVELCLASS_CONTRIBUTION_END 299
+#define LEVELCLASS_USER_START 300
+#define LEVELCLASS_USER_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_TUTORIAL LEVELCLASS_TUTORIAL_START
+#define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START
+#define LEVELCLASS_CONTRIBUTION LEVELCLASS_CONTRIBUTION_START
+#define LEVELCLASS_USER LEVELCLASS_USER_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_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_CONTRIBUTION(p) \
+ ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \
+ (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END)
+#define IS_LEVELCLASS_USER(p) \
+ ((p)->sort_priority >= LEVELCLASS_USER_START && \
+ (p)->sort_priority <= LEVELCLASS_USER_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 LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \
+ IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \
+ IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \
+ IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \
+ IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \
+ IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \
+ IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \
+ IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \
+ LEVELCLASS_UNDEFINED)
+
+/* sort priorities of artwork */
+#define ARTWORKCLASS_CLASSICS_START 100
+#define ARTWORKCLASS_CLASSICS_END 199
+#define ARTWORKCLASS_CONTRIBUTION_START 200
+#define ARTWORKCLASS_CONTRIBUTION_END 299
+#define ARTWORKCLASS_LEVEL_START 300
+#define ARTWORKCLASS_LEVEL_END 399
+#define ARTWORKCLASS_USER_START 400
+#define ARTWORKCLASS_USER_END 499
+
+#define ARTWORKCLASS_CLASSICS ARTWORKCLASS_CLASSICS_START
+#define ARTWORKCLASS_CONTRIBUTION ARTWORKCLASS_CONTRIBUTION_START
+#define ARTWORKCLASS_LEVEL ARTWORKCLASS_LEVEL_START
+#define ARTWORKCLASS_USER ARTWORKCLASS_USER_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_CONTRIBUTION(p) \
+ ((p)->sort_priority >= ARTWORKCLASS_CONTRIBUTION_START && \
+ (p)->sort_priority <= ARTWORKCLASS_CONTRIBUTION_END)
+#define IS_ARTWORKCLASS_LEVEL(p) \
+ ((p)->sort_priority >= ARTWORKCLASS_LEVEL_START && \
+ (p)->sort_priority <= ARTWORKCLASS_LEVEL_END)
+#define IS_ARTWORKCLASS_USER(p) \
+ ((p)->sort_priority >= ARTWORKCLASS_USER_START && \
+ (p)->sort_priority <= ARTWORKCLASS_USER_END)
+
+#define ARTWORKCLASS(n) (IS_ARTWORKCLASS_CLASSICS(n) ? ARTWORKCLASS_CLASSICS :\
+ IS_ARTWORKCLASS_CONTRIBUTION(n) ? ARTWORKCLASS_CONTRIBUTION : \
+ IS_ARTWORKCLASS_LEVEL(n) ? ARTWORKCLASS_LEVEL : \
+ IS_ARTWORKCLASS_USER(n) ? ARTWORKCLASS_USER : \
+ ARTWORKCLASS_UNDEFINED)
+
+
+char *getLevelFilename(int);
+char *getTapeFilename(int);
+char *getScoreFilename(int);
+char *getSetupFilename(void);
+char *getImageFilename(char *);
+char *getCustomImageFilename(char *);
+char *getCustomSoundFilename(char *);
+char *getCustomSoundConfigFilename(void);
+char *getCustomMusicDirectory(void);
+
+void InitTapeDirectory(char *);
+void InitScoreDirectory(char *);
+void InitUserLevelDirectory(char *);
+void InitLevelSetupDirectory(char *);
+
+TreeInfo *newTreeInfo();
+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 *getTreeInfoFromFilename(TreeInfo *, char *);
+void dumpTreeInfo(TreeInfo *, int);
+void sortTreeInfo(TreeInfo **,
+ int (*compare_function)(const void *, const void *));
+
+char *getUserDataDir(void);
+char *getSetupDir(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 *);
+void freeSetupFileList(struct SetupFileList *);
+char *getTokenValue(struct SetupFileList *, char *);
+struct SetupFileList *loadSetupFileList(char *);
+void checkSetupFileListIdentifier(struct SetupFileList *, char *);
+void setSetupInfo(struct TokenInfo *, int, char *);
+char *getSetupValue(int, void *);
+char *getSetupLine(struct TokenInfo *, char *, int);
+
+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 */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
* sound.c *
***********************************************************/
-#include <string.h>
+#include <sys/types.h>
#include <sys/time.h>
+#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
+#include <math.h>
+
+#include "platform.h"
+
+#if defined(PLATFORM_LINUX)
+#include <sys/ioctl.h>
+#include <linux/soundcard.h>
+#elif defined(PLATFORM_FREEBSD)
+#include <machine/soundcard.h>
+#elif defined(PLATFORM_NETBSD)
+#include <sys/ioctl.h>
+#include <sys/audioio.h>
+#elif defined(PLATFORM_HPUX)
+#include <sys/audio.h>
+#endif
#include "system.h"
#include "sound.h"
#include "misc.h"
+#include "setup.h"
+#include "text.h"
-static int num_sounds = 0, num_music = 0;
-static struct SampleInfo *Sound = NULL;
-#if defined(TARGET_SDL)
-static int num_mods = 0;
-static struct SampleInfo *Mod = NULL;
+/* 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
+
+#if !defined(PLATFORM_HPUX)
+#define SND_BLOCKSIZE 4096
+#else
+#define SND_BLOCKSIZE 32768
#endif
+#define SND_TYPE_NONE 0
+#define SND_TYPE_WAV 1
-/* ========================================================================= */
-/* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
+#define MUS_TYPE_NONE 0
+#define MUS_TYPE_WAV 1
+#define MUS_TYPE_MOD 2
+
+#define DEVICENAME_DSP "/dev/dsp"
+#define DEVICENAME_AUDIO "/dev/audio"
+#define DEVICENAME_AUDIOCTL "/dev/audioCtl"
-static int playing_sounds = 0;
-static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
-static struct SoundControl emptySoundControl =
+#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 0
+struct SoundHeader_SUN
{
- -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
+ unsigned long magic;
+ unsigned long hdr_size;
+ unsigned long data_size;
+ unsigned long encoding;
+ unsigned long sample_rate;
+ unsigned long channels;
};
-#if defined(PLATFORM_UNIX)
-static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
-static char premix_first_buffer[SND_BLOCKSIZE];
-#if defined(AUDIO_STREAMING_DSP)
-static char premix_left_buffer[SND_BLOCKSIZE];
-static char premix_right_buffer[SND_BLOCKSIZE];
-static int premix_last_buffer[SND_BLOCKSIZE];
+struct SoundHeader_8SVX
+{
+ char magic_FORM[4];
+ unsigned long chunk_size;
+ char magic_8SVX[4];
+};
#endif
-static unsigned char playing_buffer[SND_BLOCKSIZE];
+
+#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
-/* forward declaration of internal functions */
-#if defined(AUDIO_STREAMING_DSP)
-static void SoundServer_InsertNewSound(struct SoundControl);
-#elif defined(PLATFORM_UNIX)
+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 */
+};
+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 */
+
+#if defined(TARGET_ALLEGRO)
+ int voice;
+#endif
+};
+typedef struct SoundControl SoundControl;
+
+struct ListNode
+{
+ char *key;
+ void *content;
+ struct ListNode *next;
+};
+typedef struct ListNode ListNode;
+
+static ListNode *newListNode(void);
+static void addNodeToList(ListNode **, char *, void *);
+static void deleteNodeFromList(ListNode **, char *, void (*function)(void *));
+static ListNode *getNodeFromKey(ListNode *, char *);
+static int getNumNodes(ListNode *);
+
+
+static struct SoundEffectInfo *sound_effect;
+static ListNode *SoundFileList = NULL;
+static SoundInfo **Sound = NULL;
+static MusicInfo **Music = NULL;
+static int num_sounds = 0, num_music = 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
-
-#if defined(AUDIO_LINUX_IOCTL)
-static boolean InitAudioDevice_Linux();
-#elif defined(PLATFORM_NETBSD)
-static boolean InitAudioDevice_NetBSD();
-#elif defined(PLATFORM_HPUX)
-static boolean InitAudioDevice_HPUX();
-#elif defined(PLATFORM_MSDOS)
-static void SoundServer_InsertNewSound(struct SoundControl);
-static void SoundServer_StopSound(int);
-static void SoundServer_StopAllSounds();
#endif
-#if defined(PLATFORM_UNIX)
+static void ReloadCustomSounds();
+static void ReloadCustomMusic();
+static void FreeSound(void *);
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for native (non-SDL) Unix audio/mixer support */
+/* ------------------------------------------------------------------------- */
+
+#if defined(AUDIO_UNIX_NATIVE)
+
static int OpenAudioDevice(char *audio_device_name)
{
- int audio_fd;
+ 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_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
- return audio_fd;
+ 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_fd);
- audio_fd = open(audio_device_name, O_WRONLY);
+ close(audio_device_fd);
+ audio_device_fd = open(audio_device_name, O_WRONLY);
- return audio_fd;
+ 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)
DEVICENAME_DSP,
DEVICENAME_AUDIO
};
- int audio_fd = -1;
+ 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_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
+ if ((audio_device_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
break;
- if (audio_fd < 0)
+ if (audio_device_fd < 0)
{
Error(ERR_WARN, "cannot open audio device -- no sound");
return FALSE;
}
- close(audio_fd);
+ close(audio_device_fd);
audio.device_name = audio_device_name[i];
return TRUE;
}
-#if !defined(TARGET_SDL)
static boolean ForkAudioProcess(void)
{
- if (pipe(audio.soundserver_pipe) < 0)
+ if (pipe(audio.mixer_pipe) < 0)
{
Error(ERR_WARN, "cannot create pipe -- no sounds");
return FALSE;
}
- if ((audio.soundserver_pid = fork()) < 0)
+ if ((audio.mixer_pid = fork()) < 0)
{
Error(ERR_WARN, "cannot create sound server process -- no sounds");
return FALSE;
}
- if (audio.soundserver_pid == 0) /* we are child */
- {
- SoundServer();
-
- /* never reached */
- exit(0);
- }
- else /* we are parent */
- close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
+ if (IS_CHILD_PROCESS(audio.mixer_pid))
+ Mixer_Main(); /* this function never returns */
+ else
+ close(audio.mixer_pipe[0]); /* no reading from pipe needed */
return TRUE;
}
-#endif
void UnixOpenAudio(void)
{
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 (audio.soundserver_pid)
- kill(audio.soundserver_pid, SIGTERM);
+ if (IS_PARENT_PROCESS(audio.mixer_pid))
+ kill(audio.mixer_pid, SIGTERM);
}
-#endif /* PLATFORM_UNIX */
-void InitPlaylist(void)
+
+/* ------------------------------------------------------------------------- */
+/* 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;
+ 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;
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- playlist[i] = emptySoundControl;
- playing_sounds = 0;
+ /* 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 /dev/dsp -- 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 /dev/dsp -- 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 /dev/dsp -- 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 /dev/dsp -- no sounds");
+ if (fragment_size_query != afmt->fragment_size)
+ Error(ERR_EXIT_SOUND_SERVER,
+ "cannot set fragment size of /dev/dsp -- no sounds");
}
+#endif /* AUDIO_LINUX_IOCTL */
-void StartSoundserver(void)
+#if defined(PLATFORM_NETBSD)
+static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt)
{
- if (!audio.sound_available)
- return;
+ audio_info_t a_info;
+ boolean stereo = TRUE;
-#if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
- if (!ForkAudioProcess())
- audio.sound_available = FALSE;
+ 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 = sample_rate;
+ a_info.blocksize = 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 /dev/audio -- 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 /dev/audioCtl -- 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
}
-#if defined(PLATFORM_UNIX)
-void SoundServer(void)
+
+/* ------------------------------------------------------------------------- */
+/* functions for communication between main process and sound mixer process */
+/* ------------------------------------------------------------------------- */
+
+static void SendSoundControlToMixerProcess(SoundControl *snd_ctrl)
+{
+ if (IS_CHILD_PROCESS(audio.mixer_pid))
+ 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(audio.mixer_pid))
+ 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_name, 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(ti->basepath) + 1;
+ unsigned long str_size3 = strlen(ti->fullpath) + 1;
+ boolean override_level_artwork = (type == SND_CTRL_RELOAD_SOUNDS ?
+ setup.override_level_sounds :
+ setup.override_level_music);
+
+ if (IS_CHILD_PROCESS(audio.mixer_pid))
+ return;
+
+ if (leveldir_current == NULL) /* should never happen */
+ Error(ERR_EXIT, "leveldir_current == NULL");
+
+ snd_ctrl.active = FALSE;
+ snd_ctrl.state = type;
+ snd_ctrl.data_len = strlen(set_name) + 1;
+
+ if (write(audio.mixer_pipe[1], &snd_ctrl,
+ sizeof(snd_ctrl)) < 0 ||
+ write(audio.mixer_pipe[1], set_name,
+ 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], leveldir_current->fullpath,
+ str_size1) < 0 ||
+ write(audio.mixer_pipe[1], ti->basepath,
+ str_size2) < 0 ||
+ write(audio.mixer_pipe[1], ti->fullpath,
+ str_size3) < 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;
+ static char *set_name = NULL;
+ boolean *override_level_artwork = (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS ?
+ &setup.override_level_sounds :
+ &setup.override_level_music);
+
+ if (set_name)
+ free(set_name);
+
+ set_name = 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));
+ if (leveldir_current->fullpath != NULL)
+ free(leveldir_current->fullpath);
+ if (ti->basepath != NULL)
+ free(ti->basepath);
+ if (ti->fullpath != NULL)
+ free(ti->fullpath);
+
+ if (read(audio.mixer_pipe[0], set_name,
+ 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))
+ Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+ leveldir_current->fullpath = checked_calloc(str_size1);
+ ti->basepath = checked_calloc(str_size2);
+ ti->fullpath = checked_calloc(str_size3);
+
+ if (read(audio.mixer_pipe[0], leveldir_current->fullpath,
+ str_size1) != str_size1 ||
+ read(audio.mixer_pipe[0], ti->basepath,
+ str_size2) != str_size2 ||
+ read(audio.mixer_pipe[0], ti->fullpath,
+ str_size3) != str_size3)
+ Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+ if (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS)
+ artwork.sounds_set_current_name = set_name;
+ else
+ artwork.music_set_current_name = set_name;
+}
+
+#endif /* AUDIO_UNIX_NATIVE */
+
+
+/* ------------------------------------------------------------------------- */
+/* mixer functions */
+/* ------------------------------------------------------------------------- */
+
+void Mixer_InitChannels()
{
int i;
- struct SoundControl snd_ctrl;
- fd_set sound_fdset;
+ 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
+}
- close(audio.soundserver_pipe[1]); /* no writing into pipe needed */
+static boolean Mixer_ChannelExpired(int channel)
+{
+ if (!mixer[channel].active)
+ return TRUE;
- InitPlaylist();
+ if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
+ DelayReached(&mixer[channel].playing_starttime,
+ SOUND_LOOP_EXPIRATION_TIME))
+ return TRUE;
- stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
- for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
- stereo_volume[i] =
- (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
+#if defined(TARGET_SDL)
-#if defined(PLATFORM_HPUX)
- InitAudioDevice_HPUX();
+ 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
- FD_ZERO(&sound_fdset);
- FD_SET(audio.soundserver_pipe[0], &sound_fdset);
+ return TRUE;
+}
- while(1) /* wait for sound playing commands from client */
+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)
{
- FD_SET(audio.soundserver_pipe[0], &sound_fdset);
- select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
- if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
- continue;
- if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
- != sizeof(snd_ctrl))
- Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+ /* 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
+}
-#if defined(AUDIO_STREAMING_DSP)
+static void Mixer_StopChannel(int channel)
+{
+ if (!mixer[channel].active)
+ return;
- if (snd_ctrl.fade_sound)
- {
- if (!playing_sounds)
- continue;
+#if defined(TARGET_SDL)
+ Mix_HaltChannel(channel);
+#elif defined(TARGET_ALLEGRO)
+ voice_set_volume(mixer[channel].voice, 0);
+ deallocate_voice(mixer[channel].voice);
+#endif
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
- playlist[i].fade_sound = TRUE;
- }
- else if (snd_ctrl.stop_all_sounds)
+ 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;
+
+#if 0
+ printf("NEW SOUND %d HAS ARRIVED [%d]\n", snd_ctrl.nr, num_sounds);
+#endif
+
+#if 0
+ printf("%d ACTIVE CHANNELS\n", mixer_active_channels);
+#endif
+
+ if (IS_MUSIC(snd_ctrl))
+ {
+ if (num_music == 0)
+ return;
+
+ snd_ctrl.nr = snd_ctrl.nr % num_music;
+ }
+ else if (snd_ctrl.nr >= num_sounds)
+ return;
+
+ snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[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;
+
+ /* play music samples on a dedicated music channel */
+ if (IS_MUSIC(snd_ctrl))
+ {
+#if 0
+ printf("PLAY MUSIC WITH VOLUME/STEREO %d/%d\n",
+ snd_ctrl.volume, snd_ctrl.stereo_position);
+#endif
+
+ 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++;
+
+#if 0
+ printf("SOUND %d [CURRENTLY PLAYING %d TIMES]\n", snd_ctrl.nr, k);
+#endif
+
+ /* 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 (!playing_sounds)
- continue;
+ if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
+ {
+#if 0
+ printf("RESETTING EXPIRATION FOR SOUND %d\n", snd_ctrl.nr);
+#endif
+
+ if (IS_FADING(mixer[i]))
+ Mixer_UnFadeChannel(i);
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- playlist[i]=emptySoundControl;
- playing_sounds=0;
+ /* restore settings like volume and stereo position */
+ mixer[i].volume = snd_ctrl.volume;
+ mixer[i].stereo_position = snd_ctrl.stereo_position;
- close(audio.device_fd);
+ Mixer_SetChannelProperties(i);
+ Mixer_ResetChannelExpiration(i);
+
+#if 0
+ printf("RESETTING VOLUME/STEREO FOR SOUND %d TO %d/%d\n",
+ snd_ctrl.nr, snd_ctrl.volume, snd_ctrl.stereo_position);
+#endif
+ }
}
- else if (snd_ctrl.stop_sound)
+
+ return;
+ }
+
+#if 0
+ printf("PLAYING NEW SOUND %d\n", snd_ctrl.nr);
+#endif
+
+ /* 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++)
{
- if (!playing_sounds)
+ int playing_time = playing_current - mixer[i].playing_starttime;
+ int actual;
+
+ if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
continue;
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- if (playlist[i].nr == snd_ctrl.nr)
- {
- playlist[i]=emptySoundControl;
- playing_sounds--;
- }
+ actual = 1000 * playing_time / mixer[i].data_len;
- if (!playing_sounds)
- close(audio.device_fd);
+ if (actual >= longest)
+ {
+ longest = actual;
+ longest_nr = i;
+ }
}
- if (playing_sounds || snd_ctrl.active)
+ 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 (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;
+
+ for (i=audio.first_sound_channel; i<audio.num_channels; i++)
{
- struct timeval delay = { 0, 0 };
- byte *sample_ptr;
- long sample_size;
- static long max_sample_size = 0;
- static long fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
- int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
- boolean stereo = TRUE;
-
- if (playing_sounds ||
- (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
+ 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)
{
- if (!playing_sounds) /* we just opened the audio device */
- {
-#if defined(AUDIO_LINUX_IOCTL)
- stereo = InitAudioDevice_Linux(fragment_size, sample_rate);
-#elif defined(PLATFORM_NETBSD)
- stereo = InitAudioDevice_NetBSD(fragment_size, sample_rate);
-#endif
- max_sample_size = fragment_size / (stereo ? 2 : 1);
- }
-
- if (snd_ctrl.active) /* new sound has arrived */
- SoundServer_InsertNewSound(snd_ctrl);
-
- while(playing_sounds &&
- select(audio.soundserver_pipe[0] + 1,
- &sound_fdset, NULL, NULL, &delay) < 1)
- {
- FD_SET(audio.soundserver_pipe[0], &sound_fdset);
-
- /* first clear the last premixing buffer */
- memset(premix_last_buffer, 0, fragment_size * sizeof(int));
-
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- {
- int j;
-
- if (!playlist[i].active)
- continue;
-
- /* get pointer and size of the actual sound sample */
- sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
- sample_size =
- MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
- playlist[i].playingpos += sample_size;
-
- /* fill the first mixing buffer with original sample */
- memcpy(premix_first_buffer,sample_ptr,sample_size);
-
- /* are we about to restart a looping sound? */
- if (playlist[i].loop && sample_size<max_sample_size)
- {
- playlist[i].playingpos = max_sample_size-sample_size;
- memcpy(premix_first_buffer+sample_size,
- playlist[i].data_ptr,max_sample_size-sample_size);
- sample_size = max_sample_size;
- }
-
- /* decrease volume if sound is fading out */
- if (playlist[i].fade_sound &&
- playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
- playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
-
- /* adjust volume of actual sound sample */
- if (playlist[i].volume != PSND_MAX_VOLUME)
- for(j=0;j<sample_size;j++)
- premix_first_buffer[j] =
- (playlist[i].volume * (int)premix_first_buffer[j])
- >> PSND_MAX_VOLUME_BITS;
-
- /* fill the last mixing buffer with stereo or mono sound */
- if (stereo)
- {
- int middle_pos = PSND_MAX_LEFT2RIGHT/2;
- int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
- int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
-
- for(j=0;j<sample_size;j++)
- {
- premix_left_buffer[j] =
- (left_volume * (int)premix_first_buffer[j])
- >> PSND_MAX_LEFT2RIGHT_BITS;
- premix_right_buffer[j] =
- (right_volume * (int)premix_first_buffer[j])
- >> PSND_MAX_LEFT2RIGHT_BITS;
- premix_last_buffer[2*j+0] += premix_left_buffer[j];
- premix_last_buffer[2*j+1] += premix_right_buffer[j];
- }
- }
- else
- {
- for(j=0;j<sample_size;j++)
- premix_last_buffer[j] += (int)premix_first_buffer[j];
- }
-
- /* delete completed sound entries from the playlist */
- if (playlist[i].playingpos >= playlist[i].data_len)
- {
- if (playlist[i].loop)
- playlist[i].playingpos = 0;
- else
- {
- playlist[i] = emptySoundControl;
- playing_sounds--;
- }
- }
- else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
- {
- playlist[i] = emptySoundControl;
- playing_sounds--;
- }
- }
-
- /* put last mixing buffer to final playing buffer */
- for(i=0; i<fragment_size; i++)
- {
- if (premix_last_buffer[i]<-255)
- playing_buffer[i] = 0;
- else if (premix_last_buffer[i]>255)
- playing_buffer[i] = 255;
- else
- playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
- }
-
- /* finally play the sound fragment */
- write(audio.device_fd, playing_buffer, fragment_size);
- }
-
- /* if no sounds playing, free device for other sound programs */
- if (!playing_sounds)
- close(audio.device_fd);
+ longest = actual;
+ longest_nr = i;
}
}
-#else /* !AUDIO_STREAMING_DSP */
+ Mixer_StopChannel(longest_nr);
+ }
- if (snd_ctrl.active && !snd_ctrl.loop)
+ /* add the new sound to the mixer */
+ for(i=0; i<audio.num_channels; i++)
+ {
+#if 0
+ printf("CHECKING CHANNEL %d FOR SOUND %d ...\n", i, snd_ctrl.nr);
+#endif
+
+ /*
+ if (!mixer[i].active ||
+ (IS_MUSIC(snd_ctrl) && i == audio.music_channel))
+ */
+ if ((i == audio.music_channel && IS_MUSIC(snd_ctrl)) ||
+ (i != audio.music_channel && !mixer[i].active))
{
- struct timeval delay = { 0, 0 };
- byte *sample_ptr;
- long sample_size, max_sample_size = SND_BLOCKSIZE;
- long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
- int wait_percent = 90; /* wait 90% of the real playing time */
- int i;
+#if 0
+ printf("ADDING NEW SOUND %d TO MIXER\n", snd_ctrl.nr);
+#endif
- if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
+#if 1
+#if defined(AUDIO_UNIX_NATIVE)
+ if (snd_info->data_len == 0)
{
- playing_sounds = 1;
-
- while(playing_sounds &&
- select(audio.soundserver_pipe[0] + 1,
- &sound_fdset, NULL, NULL, &delay) < 1)
- {
- FD_SET(audio.soundserver_pipe[0], &sound_fdset);
-
- /* get pointer and size of the actual sound sample */
- sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
- sample_size =
- MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
- snd_ctrl.playingpos += sample_size;
-
- /* fill the first mixing buffer with original sample */
- memcpy(premix_first_buffer,sample_ptr,sample_size);
-
- /* adjust volume of actual sound sample */
- if (snd_ctrl.volume != PSND_MAX_VOLUME)
- for(i=0;i<sample_size;i++)
- premix_first_buffer[i] =
- (snd_ctrl.volume * (int)premix_first_buffer[i])
- >> PSND_MAX_VOLUME_BITS;
-
- for(i=0;i<sample_size;i++)
- playing_buffer[i] =
- linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
-
- if (snd_ctrl.playingpos >= snd_ctrl.data_len)
- playing_sounds = 0;
-
- /* finally play the sound fragment */
- write(audio.device_fd,playing_buffer,sample_size);
-
- delay.tv_sec = 0;
- delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
- }
- close(audio.device_fd);
+ printf("THIS SHOULD NEVER HAPPEN! [snd_info->data_len == 0]\n");
+ }
+#endif
+#endif
+
+#if 1
+ if (IS_MUSIC(snd_ctrl) && i == audio.music_channel && mixer[i].active)
+ {
+ printf("THIS SHOULD NEVER HAPPEN! [adding music twice]\n");
+
+#if 1
+ Mixer_StopChannel(i);
+#endif
}
+#endif
+
+ mixer[i] = snd_ctrl;
+ Mixer_PlayChannel(i);
+
+ break;
}
-#endif /* !AUDIO_STREAMING_DSP */
}
}
-#endif /* PLATFORM_UNIX */
-#if defined(PLATFORM_MSDOS)
-static void sound_handler(struct SoundControl snd_ctrl)
+static void HandleSoundRequest(SoundControl snd_ctrl)
+{
+ int i;
+
+#if defined(AUDIO_UNIX_NATIVE)
+ if (IS_PARENT_PROCESS(audio.mixer_pid))
+ {
+ 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_ptr)
{
+ void *sample_ptr = snd_ctrl->data_ptr;
int i;
- if (snd_ctrl.fade_sound)
- {
- if (!playing_sounds)
- return;
+ if (snd_ctrl->format == AUDIO_FORMAT_U8)
+ for (i=0; i<sample_size; i++)
+ *buffer_ptr++ =
+ ((short)(((byte *)sample_ptr)[sample_pos + i] ^ 0x80)) << 8;
+ else /* AUDIO_FORMAT_S16 */
+ for (i=0; i<sample_size; i++)
+ *buffer_ptr++ =
+ ((short *)sample_ptr)[sample_pos + i];
+}
- for (i=0; i<MAX_SOUNDS_PLAYING; i++)
- if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
- !playlist[i].fade_sound)
- {
- playlist[i].fade_sound = TRUE;
- if (voice_check(playlist[i].voice))
- voice_ramp_volume(playlist[i].voice, 1000, 0);
- playlist[i].loop = PSND_NO_LOOP;
- }
- }
- else if (snd_ctrl.stop_all_sounds)
- {
- if (!playing_sounds)
- return;
- SoundServer_StopAllSounds();
- }
- else if (snd_ctrl.stop_sound)
- {
- if (!playing_sounds)
- return;
- SoundServer_StopSound(snd_ctrl.nr);
- }
+#if defined(AUDIO_STREAMING_DSP)
+static void Mixer_Main_DSP()
+{
+ static short premix_first_buffer[SND_BLOCKSIZE];
+ static short premix_left_buffer[SND_BLOCKSIZE];
+ static short premix_right_buffer[SND_BLOCKSIZE];
+ static long premix_last_buffer[SND_BLOCKSIZE];
+ static byte playing_buffer[SND_BLOCKSIZE];
+ boolean stereo;
+ int fragment_size;
+ int sample_bytes;
+ int max_sample_size;
+ int i, j;
+
+ if (!mixer_active_channels)
+ return;
- for (i=0; i<MAX_SOUNDS_PLAYING; i++)
+ if (audio.device_fd < 0)
{
- if (!playlist[i].active || playlist[i].loop)
- continue;
+ if ((audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
+ return;
- playlist[i].playingpos = voice_get_position(playlist[i].voice);
- playlist[i].volume = voice_get_volume(playlist[i].voice);
- if (playlist[i].playingpos == -1 || !playlist[i].volume)
- {
- deallocate_voice(playlist[i].voice);
- playlist[i] = emptySoundControl;
- playing_sounds--;
- }
+ InitAudioDevice(&afmt);
}
- if (snd_ctrl.active)
- SoundServer_InsertNewSound(snd_ctrl);
-}
-#endif /* PLATFORM_MSDOS */
+ stereo = afmt.stereo;
+ fragment_size = afmt.fragment_size;
+ sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
+ max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
-#if !defined(PLATFORM_WIN32)
-static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
-{
- int i, k;
+ /* first clear the last premixing buffer */
+ memset(premix_last_buffer, 0,
+ max_sample_size * (stereo ? 2 : 1) * sizeof(long));
- /* if playlist is full, remove oldest sound */
- if (playing_sounds==MAX_SOUNDS_PLAYING)
+ for(i=0; i<audio.num_channels; i++)
{
- int longest=0, longest_nr=0;
+ void *sample_ptr;
+ int sample_len;
+ int sample_pos;
+ int sample_size;
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- {
-#if !defined(PLATFORM_MSDOS)
- int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
-#else
- int actual = playlist[i].playingpos;
-#endif
+ if (!mixer[i].active)
+ continue;
- if (!playlist[i].loop && actual>longest)
- {
- longest=actual;
- longest_nr=i;
- }
+ if (Mixer_ChannelExpired(i))
+ {
+ Mixer_StopChannel(i);
+ continue;
}
-#if defined(PLATFORM_MSDOS)
- voice_set_volume(playlist[longest_nr].voice, 0);
- deallocate_voice(playlist[longest_nr].voice);
-#endif
- playlist[longest_nr] = emptySoundControl;
- playing_sounds--;
- }
- /* check if sound is already being played (and how often) */
- for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
- {
- if (playlist[i].nr == snd_ctrl.nr)
- k++;
- }
+ /* 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;
- /* restart loop sounds only if they are just fading out */
- if (k>=1 && snd_ctrl.loop)
- {
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+ /* copy original sample to first mixing buffer */
+ CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size,
+ premix_first_buffer);
+
+ /* are we about to restart a looping sound? */
+ if (IS_LOOP(mixer[i]) && sample_size < max_sample_size)
{
- if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
+ while (sample_size < max_sample_size)
{
- playlist[i].fade_sound = FALSE;
- playlist[i].volume = PSND_MAX_VOLUME;
-#if defined(PLATFORM_MSDOS)
- playlist[i].loop = PSND_LOOP;
- voice_stop_volumeramp(playlist[i].voice);
- voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
-#endif
+ int restarted_sample_size =
+ MIN(max_sample_size - sample_size, sample_len);
+
+ if (mixer[i].format == AUDIO_FORMAT_U8)
+ for (j=0; j<restarted_sample_size; j++)
+ premix_first_buffer[sample_size + j] =
+ ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
+ else
+ for (j=0; j<restarted_sample_size; j++)
+ premix_first_buffer[sample_size + j] =
+ ((short *)sample_ptr)[j];
+
+ mixer[i].playing_pos = restarted_sample_size;
+ sample_size += restarted_sample_size;
}
}
- return;
- }
- /* don't play sound more than n times simultaneously (with n == 2 for now) */
- if (k>=2)
- {
- int longest=0, longest_nr=0;
+ /* 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;
- /* look for oldest equal sound */
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- {
- int actual;
+ /* 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;
- if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
- continue;
+ /* fill the last mixing buffer with stereo or mono sound */
+ if (stereo)
+ {
+ int left_volume = SOUND_VOLUME_LEFT(mixer[i].stereo_position);
+ int right_volume = SOUND_VOLUME_RIGHT(mixer[i].stereo_position);
-#if !defined(PLATFORM_MSDOS)
- actual = 100 * playlist[i].playingpos / playlist[i].data_len;
-#else
- actual = playlist[i].playingpos;
-#endif
- if (actual>=longest)
+ for(j=0; j<sample_size; j++)
{
- longest=actual;
- longest_nr=i;
+ premix_left_buffer[j] =
+ left_volume * premix_first_buffer[j] / SOUND_MAX_LEFT2RIGHT;
+ premix_right_buffer[j] =
+ right_volume * premix_first_buffer[j] / SOUND_MAX_LEFT2RIGHT;
+
+ premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
+ premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
}
}
+ else
+ {
+ for(j=0; j<sample_size; j++)
+ premix_last_buffer[j] += premix_first_buffer[j];
+ }
-#if defined(PLATFORM_MSDOS)
- voice_set_volume(playlist[longest_nr].voice, 0);
- deallocate_voice(playlist[longest_nr].voice);
-#endif
- playlist[longest_nr] = emptySoundControl;
- playing_sounds--;
+ /* 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);
}
- /* neuen Sound in Liste packen */
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+ /* prepare final playing buffer according to system audio format */
+ for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
{
- if (!playlist[i].active)
- {
- playlist[i] = snd_ctrl;
- playing_sounds++;
+ /* 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;
-#if defined(PLATFORM_MSDOS)
- playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr);
- if(snd_ctrl.loop)
- voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
- voice_set_volume(playlist[i].voice, snd_ctrl.volume);
- voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
- voice_start(playlist[i].voice);
-#endif
- break;
+ /* 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;
}
}
-}
-#endif /* !PLATFORM_WIN32 */
-
-/*
-void SoundServer_FadeSound(int nr)
-{
- int i;
- if (!playing_sounds)
- return;
+ /* finally play the sound fragment */
+ write(audio.device_fd, playing_buffer, fragment_size);
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
- playlist[i].fade_sound = TRUE;
+ if (!mixer_active_channels)
+ CloseAudioDevice(&audio.device_fd);
}
-*/
-
-#if !defined(PLATFORM_WIN32)
-#if defined(PLATFORM_MSDOS)
-static void SoundServer_StopSound(int nr)
-{
- int i;
- if (!playing_sounds)
- return;
+#else /* !AUDIO_STREAMING_DSP */
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- if (playlist[i].nr == nr)
- {
-#if defined(PLATFORM_MSDOS)
- voice_set_volume(playlist[i].voice, 0);
- deallocate_voice(playlist[i].voice);
+static int Mixer_Main_SimpleAudio(SoundControl snd_ctrl)
+{
+ static short premix_first_buffer[SND_BLOCKSIZE];
+ static byte playing_buffer[SND_BLOCKSIZE];
+ int max_sample_size = SND_BLOCKSIZE;
+ 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);
+
+ /* 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 */
+#if 1
+ for(j=0; j<sample_size; j++)
+ playing_buffer[j] =
+ linear_to_ulaw(premix_first_buffer[j]);
#endif
- playlist[i] = emptySoundControl;
- playing_sounds--;
- }
-#if !defined(PLATFORM_MSDOS)
- if (!playing_sounds)
- close(audio.device_fd);
-#endif
-}
+ /* delete completed sound entries from the mixer */
+ if (mixer[i].playing_pos >= mixer[i].data_len)
+ Mixer_StopChannel(i);
-static void SoundServer_StopAllSounds()
-{
- int i;
+ for(i=0; i<sample_size; i++)
+ playing_buffer[i] = (premix_first_buffer[i] >> 8) ^ 0x80;
- for(i=0;i<MAX_SOUNDS_PLAYING;i++)
- {
-#if defined(PLATFORM_MSDOS)
- voice_set_volume(playlist[i].voice, 0);
- deallocate_voice(playlist[i].voice);
-#endif
- playlist[i]=emptySoundControl;
- }
- playing_sounds = 0;
+ /* finally play the sound fragment */
+ write(audio.device_fd, playing_buffer, sample_size);
-#if !defined(PLATFORM_MSDOS)
- close(audio.device_fd);
-#endif
+ return sample_size;
}
-#endif /* PLATFORM_MSDOS */
-#endif /* !PLATFORM_WIN32 */
-
-
-/* ------------------------------------------------------------------------- */
-/* platform dependant audio initialization code */
-/* ------------------------------------------------------------------------- */
+#endif /* !AUDIO_STREAMING_DSP */
-#if defined(AUDIO_LINUX_IOCTL)
-static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
+void Mixer_Main()
{
- /* "ioctl()" expects pointer to 'int' value for stereo flag
- (boolean is defined as 'char', which will not work here) */
- int stereo = TRUE;
- unsigned long fragment_spec = 0;
+ SoundControl snd_ctrl;
+ fd_set mixer_fdset;
- /* determine logarithm (log2) of the fragment size */
- for (fragment_spec=0; (1 << fragment_spec) < fragment_size;
- fragment_spec++);
+ close(audio.mixer_pipe[1]); /* no writing into pipe needed */
- /* 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;
+ Mixer_InitChannels();
- /* 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 defined(PLATFORM_HPUX)
+ InitAudioDevice(&afmt);
+#endif
- if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
- Error(ERR_EXIT_SOUND_SERVER,
- "cannot set fragment size of /dev/dsp -- no sounds");
+ FD_ZERO(&mixer_fdset);
+ FD_SET(audio.mixer_pipe[0], &mixer_fdset);
- /* try if we can use stereo sound */
- if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
+ while(1) /* wait for sound playing commands from client */
{
-#ifdef DEBUG
- static boolean reported = FALSE;
+ struct timeval delay = { 0, 0 };
- if (!reported)
- {
- Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
- reported = TRUE;
- }
-#endif
- stereo = FALSE;
- }
+ 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;
- if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
- Error(ERR_EXIT_SOUND_SERVER,
- "cannot set sample rate of /dev/dsp -- no sounds");
+ ReadSoundControlFromMainProcess(&snd_ctrl);
- /* get the real fragmentation size; this should return 512 */
- if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size) < 0)
- Error(ERR_EXIT_SOUND_SERVER,
- "cannot get fragment size of /dev/dsp -- no sounds");
+ HandleSoundRequest(snd_ctrl);
- return (boolean)stereo;
-}
-#endif /* AUDIO_LINUX_IOCTL */
+#if defined(AUDIO_STREAMING_DSP)
-#if defined(PLATFORM_NETBSD)
-static boolean InitAudioDevice_NetBSD(long fragment_size, int sample_rate)
-{
- audio_info_t a_info;
- boolean stereo = TRUE;
+ while (mixer_active_channels &&
+ select(audio.mixer_pipe[0] + 1,
+ &mixer_fdset, NULL, NULL, &delay) < 1)
+ {
+ FD_SET(audio.mixer_pipe[0], &mixer_fdset);
- 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 = sample_rate;
- a_info.blocksize = fragment_size;
+ Mixer_Main_DSP();
+ }
- if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
- {
- /* try to disable stereo */
- a_info.play.channels = 1;
- stereo = FALSE;
+#else /* !AUDIO_STREAMING_DSP */
- if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
- Error(ERR_EXIT_SOUND_SERVER,
- "cannot set sample rate of /dev/audio -- no sounds");
- }
+ if (!snd_ctrl.active || IS_LOOP(snd_ctrl) ||
+ (audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
+ continue;
- return stereo;
-}
-#endif /* PLATFORM_NETBSD */
+ InitAudioDevice(&afmt);
-#if defined(PLATFORM_HPUX)
-static boolean InitAudioDevice_HPUX()
-{
- struct audio_describe ainfo;
- int audio_ctl;
+ delay.tv_sec = 0;
+ delay.tv_usec = 0;
- audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
- if (audio_ctl == -1)
- Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
+ 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;
- if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
- Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
+ FD_SET(audio.mixer_pipe[0], &mixer_fdset);
- if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
- Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
+ sample_size = Mixer_Main_SimpleAudio(snd_ctrl);
- ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
- ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
+ delay.tv_sec = 0;
+ delay.tv_usec =
+ ((sample_size * 10 * wait_percent) / afmt.sample_rate) * 1000;
+ }
- close(audio_ctl);
+ CloseAudioDevice(&audio.device_fd);
- return TRUE; /* to provide common interface for InitAudioDevice_...() */
+ Mixer_InitChannels(); /* remove all sounds from mixer */
+
+#endif /* !AUDIO_STREAMING_DSP */
+ }
}
-#endif /* PLATFORM_HPUX */
+#endif /* AUDIO_UNIX_NATIVE */
-#if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
+
+#if defined(AUDIO_UNIX_NATIVE) && !defined(AUDIO_STREAMING_DSP)
/* these two are stolen from "sox"... :) */
** 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;
+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 SoundInfo *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;
+ FILE *file;
+#endif
+
+ if (!audio.sound_available)
+ return NULL;
+
+#if 0
+ printf("loading WAV file '%s'\n", filename);
+#endif
+
+ 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 */
+
+ 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 (strcmp(chunk_name, "RIFF") != 0)
+ {
+ 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 (strcmp(chunk_name, "WAVE") != 0)
+ {
+ 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 (strcmp(chunk_name, "fmt ") == 0)
+ {
+ 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)
+ {
+ 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 (strcmp(chunk_name, "data") == 0)
+ {
+ snd_info->data_len = chunk_size;
+ 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 sample bytes (data chunk is word aligned) */
+ if ((chunk_size % 2) == 1)
+ ReadUnusedBytesFromFile(file, 1);
+ }
+ else /* unknown chunk -- ignore */
+ ReadUnusedBytesFromFile(file, chunk_size);
+ }
- ulawbyte = ~ ulawbyte;
- sign = ( ulawbyte & 0x80 );
- exponent = ( ulawbyte >> 4 ) & 0x07;
- mantissa = ulawbyte & 0x0F;
- sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
- if (sign != 0)
- sample = -sample;
+ fclose(file);
- return(sample);
-}
-#endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
+ 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 */
+ }
-/* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
-/* ========================================================================= */
-/* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
+#endif /* AUDIO_UNIX_NATIVE */
+ snd_info->type = SND_TYPE_WAV;
+ snd_info->source_filename = getStringCopy(filename);
-#define CHUNK_ID_LEN 4 /* IFF style chunk id length */
-#define WAV_HEADER_SIZE 20 /* size of WAV file header */
+ return snd_info;
+}
-static boolean LoadSoundExt(char *sound_name, boolean is_music)
+static void deleteSoundEntry(SoundInfo **snd_info)
{
- struct SampleInfo *snd_info;
- char filename[256];
-#if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
- byte sound_header_buffer[WAV_HEADER_SIZE];
- char chunk[CHUNK_ID_LEN + 1];
- int chunk_size, dummy;
- FILE *file;
- int i;
-#endif
+ if (*snd_info)
+ {
+ char *filename = (*snd_info)->source_filename;
- if (!audio.sound_available)
- return FALSE;
+#if 0
+ printf("[decrementing reference counter of sound '%s']\n", filename);
+#endif
- num_sounds++;
- Sound = checked_realloc(Sound, num_sounds * sizeof(struct SampleInfo));
+ if (--(*snd_info)->num_references <= 0)
+ {
+#if 0
+ printf("[deleting sound '%s']\n", filename);
+#endif
- snd_info = &Sound[num_sounds - 1];
- snd_info->name = sound_name;
+ /*
+ FreeSound(*snd_info);
+ */
+ deleteNodeFromList(&SoundFileList, filename, FreeSound);
+ }
- sprintf(filename, "%s/%s/%s", options.ro_base_directory,
- (is_music ? MUSIC_DIRECTORY : SOUNDS_DIRECTORY), snd_info->name);
+ *snd_info = NULL;
+ }
+}
-#if defined(TARGET_SDL)
+static void replaceSoundEntry(SoundInfo **snd_info, char *filename)
+{
+ ListNode *node;
- if ((snd_info->mix_chunk = Mix_LoadWAV(filename)) == NULL)
+ /* check if the old and the new sound file are the same */
+ if (*snd_info && strcmp((*snd_info)->source_filename, filename) == 0)
{
- Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
- return FALSE;
- }
+ /* The old and new sound are the same (have the same filename and path).
+ This usually means that this sound does not exist in this sound set
+ and a fallback to the existing sound is done. */
-#elif defined(PLATFORM_UNIX)
+#if 0
+ printf("[sound '%s' already exists (same list entry)]\n", filename);
+#endif
- if ((file = fopen(filename, MODE_READ)) == NULL)
- {
- Error(ERR_WARN, "cannot open sound file '%s' -- no sounds", filename);
- return FALSE;
+ return;
}
- /* read chunk "RIFF" */
- getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
- if (strcmp(chunk, "RIFF") != 0)
+ /* delete existing sound file entry */
+ deleteSoundEntry(snd_info);
+
+ /* check if the new sound file already exists in the list of sounds */
+ if ((node = getNodeFromKey(SoundFileList, filename)) != NULL)
{
- Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
- fclose(file);
- return FALSE;
- }
+#if 0
+ printf("[sound '%s' already exists (other list entry)]\n", filename);
+#endif
- /* read chunk "WAVE" */
- getFileChunk(file, chunk, &dummy, BYTE_ORDER_LITTLE_ENDIAN);
- if (strcmp(chunk, "WAVE") != 0)
+ *snd_info = (SoundInfo *)node->content;
+ (*snd_info)->num_references++;
+ }
+ else if ((*snd_info = Load_WAV(filename)) != NULL) /* load new sound */
{
- Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename);
- fclose(file);
- return FALSE;
+ (*snd_info)->num_references = 1;
+ addNodeToList(&SoundFileList, (*snd_info)->source_filename, *snd_info);
}
+}
+
+static void LoadCustomSound(SoundInfo **snd_info, char *basename)
+{
+ char *filename = getCustomSoundFilename(basename);
- /* read header information */
- for (i=0; i<WAV_HEADER_SIZE; i++)
- sound_header_buffer[i] = fgetc(file);
+#if 0
+ printf("GOT CUSTOM SOUND FILE '%s'\n", filename);
+#endif
- /* read chunk "data" */
- getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
- if (strcmp(chunk, "data") != 0)
+ if (strcmp(basename, SND_FILE_UNDEFINED) == 0)
{
- Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
- fclose(file);
- return FALSE;
+ deleteSoundEntry(snd_info);
+ return;
}
- snd_info->data_len = chunk_size;
- 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)
+ if (filename == NULL)
{
- Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
- fclose(file);
- return FALSE;
+ Error(ERR_WARN, "cannot find sound file '%s'", basename);
+ return;
}
- fclose(file);
+ replaceSoundEntry(snd_info, filename);
+}
- for (i=0; i<snd_info->data_len; i++)
- snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
+void InitSoundList(struct SoundEffectInfo *sounds_list, int num_list_entries)
+{
+ if (Sound == NULL)
+ Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
-#else /* PLATFORM_MSDOS */
+ sound_effect = sounds_list;
+ num_sounds = num_list_entries;
+}
- snd_info->sample_ptr = load_sample(filename);
- if (!snd_info->sample_ptr)
- {
- Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
- return FALSE;
- }
+void LoadSoundToList(char *basename, int list_pos)
+{
+ if (Sound == NULL || list_pos >= num_sounds)
+ return;
+#if 0
+ printf("loading sound '%s' ... [%d]\n",
+ basename, getNumNodes(SoundFileList));
#endif
- return TRUE;
-}
+ LoadCustomSound(&Sound[list_pos], basename);
-boolean LoadSound(char *sound_name)
-{
- return LoadSoundExt(sound_name, FALSE);
+#if 0
+ printf("loading sound '%s' done [%d]\n",
+ basename, getNumNodes(SoundFileList));
+#endif
}
-boolean LoadMod(char *mod_name)
+static MusicInfo *Load_MOD(char *filename)
{
#if defined(TARGET_SDL)
- struct SampleInfo *mod_info;
- char filename[256];
+ MusicInfo *mod_info;
- num_mods++;
- Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo));
-
- mod_info = &Mod[num_mods - 1];
- mod_info->name = mod_name;
+ if (!audio.sound_available)
+ return NULL;
- sprintf(filename, "%s/%s/%s", options.ro_base_directory,
- MUSIC_DIRECTORY, mod_info->name);
+ mod_info = checked_calloc(sizeof(MusicInfo));
- if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL)
+ if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
{
- Error(ERR_WARN, "cannot read music file '%s' -- no music", filename);
- return FALSE;
+ Error(ERR_WARN, "cannot read music file '%s'", filename);
+ free(mod_info);
+ return NULL;
}
- return TRUE;
+ mod_info->type = MUS_TYPE_MOD;
+ mod_info->source_filename = getStringCopy(filename);
+
+ return mod_info;
#else
- return FALSE;
+ return NULL;
#endif
}
-int LoadMusic(void)
+void LoadCustomMusic(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;
- char *music_directory = getPath2(options.ro_base_directory, MUSIC_DIRECTORY);
- int num_wav_music = 0;
- int num_mod_music = 0;
if (!audio.sound_available)
- return 0;
+ return;
+
+ if (last_music_directory != NULL &&
+ strcmp(last_music_directory, music_directory) == 0)
+ return; /* old and new music directory are the same */
+
+ last_music_directory = music_directory;
+
+ FreeAllMusic();
if ((dir = opendir(music_directory)) == NULL)
{
Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
audio.music_available = FALSE;
- free(music_directory);
- return 0;
+ return;
}
+ if (draw_init_text)
+ DrawInitText("Loading music:", 120, FC_GREEN);
+
while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
{
- char *filename = dir_entry->d_name;
+ char *basename = dir_entry->d_name;
+ char *filename = getPath2(music_directory, basename);
+ MusicInfo *mus_info = NULL;
- if (strlen(filename) > 4 &&
- strcmp(&filename[strlen(filename) - 4], ".wav") == 0)
- {
- if (LoadSoundExt(filename, TRUE))
- num_wav_music++;
- }
- else if (strlen(filename) > 4 &&
- (strcmp(&filename[strlen(filename) - 4], ".mod") == 0 ||
- strcmp(&filename[strlen(filename) - 4], ".MOD") == 0 ||
- strncmp(filename, "mod.", 4) == 0 ||
- strncmp(filename, "MOD.", 4) == 0))
+ if (draw_init_text)
+ DrawInitText(basename, 150, FC_YELLOW);
+
+ if (FileIsSound(basename))
+ mus_info = Load_WAV(filename);
+ else if (FileIsMusic(basename))
+ mus_info = Load_MOD(filename);
+
+ free(filename);
+
+ if (mus_info)
{
- if (LoadMod(filename))
- num_mod_music++;
+ num_music++;
+ Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
+ Music[num_music -1] = mus_info;
}
}
closedir(dir);
- if (num_wav_music == 0 && num_mod_music == 0)
+ draw_init_text = FALSE;
+
+ if (num_music == 0)
Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
music_directory);
-
- free(music_directory);
-
- num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music);
-
- audio.mods_available = (num_mod_music > 0);
- audio.music_available = (num_music > 0);
-
- return num_music;
}
void PlayMusic(int nr)
if (!audio.music_available)
return;
- if (!audio.mods_available)
- nr = num_sounds - num_music + nr;
-
-#if defined(TARGET_SDL)
- if (audio.mods_available) /* play MOD music */
- {
- Mix_PlayMusic(Mod[nr].mix_music, -1);
- Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
- }
- else /* play WAV music loop */
- {
- Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
- Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1);
- }
-#else
- audio.music_nr = nr;
- PlaySoundLoop(nr);
-#endif
+ PlaySoundMusic(nr);
}
void PlaySound(int nr)
{
- PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
+ PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
}
-void PlaySoundStereo(int nr, int stereo)
+void PlaySoundStereo(int nr, int stereo_position)
{
- PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
+ PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
}
void PlaySoundLoop(int nr)
{
- PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
+ PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
}
-void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
+void PlaySoundMusic(int nr)
{
- struct SoundControl snd_ctrl = emptySoundControl;
+ 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)
+ if (!audio.sound_available ||
+ !audio.sound_enabled ||
+ audio.sound_deactivated)
return;
- if (volume<PSND_MIN_VOLUME)
- volume = PSND_MIN_VOLUME;
- else if (volume>PSND_MAX_VOLUME)
- volume = PSND_MAX_VOLUME;
+ if (volume < SOUND_MIN_VOLUME)
+ volume = SOUND_MIN_VOLUME;
+ else if (volume > SOUND_MAX_VOLUME)
+ volume = SOUND_MAX_VOLUME;
- if (stereo<PSND_MAX_LEFT)
- stereo = PSND_MAX_LEFT;
- else if (stereo>PSND_MAX_RIGHT)
- stereo = PSND_MAX_RIGHT;
+ if (stereo_position < SOUND_MAX_LEFT)
+ stereo_position = SOUND_MAX_LEFT;
+ else if (stereo_position > SOUND_MAX_RIGHT)
+ stereo_position = SOUND_MAX_RIGHT;
- snd_ctrl.nr = nr;
- snd_ctrl.volume = volume;
- snd_ctrl.stereo = stereo;
- snd_ctrl.loop = loop;
- snd_ctrl.active = TRUE;
- snd_ctrl.data_ptr = Sound[nr].data_ptr;
- snd_ctrl.data_len = Sound[nr].data_len;
+ snd_ctrl.active = TRUE;
+ snd_ctrl.nr = nr;
+ snd_ctrl.volume = volume;
+ snd_ctrl.stereo_position = stereo_position;
+ snd_ctrl.state = state;
-#if defined(TARGET_SDL)
- Mix_Volume(-1, SOUND_MAX_VOLUME);
- Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
-#elif defined(PLATFORM_UNIX)
- if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
- {
- Error(ERR_WARN, "cannot pipe to child process -- no sounds");
- audio.sound_available = audio.sound_enabled = FALSE;
- return;
- }
-#elif defined(PLATFORM_MSDOS)
- sound_handler(snd_ctrl);
-#endif
+ HandleSoundRequest(snd_ctrl);
}
void FadeMusic(void)
{
-#if defined(TARGET_SDL)
- if (!audio.sound_available)
+ if (!audio.music_available)
return;
- if (audio.mods_available)
- Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
- else
- Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
-#else
- FadeSound(audio.music_nr);
-#endif
+ StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
}
void FadeSound(int nr)
{
- StopSoundExt(nr, SSND_FADE_SOUND);
+ StopSoundExt(nr, SND_CTRL_FADE_SOUND);
}
void FadeSounds()
{
FadeMusic();
- StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
+ StopSoundExt(-1, SND_CTRL_FADE_ALL);
}
void StopMusic(void)
{
-#if defined(TARGET_SDL)
- if (!audio.sound_available)
+ if (!audio.music_available)
return;
- if (audio.mods_available)
- Mix_HaltMusic();
- else
- Mix_HaltChannel(audio.music_channel);
-#else
- StopSound(audio.music_nr);
-#endif
+ StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
}
void StopSound(int nr)
{
- StopSoundExt(nr, SSND_STOP_SOUND);
+ StopSoundExt(nr, SND_CTRL_STOP_SOUND);
}
void StopSounds()
{
- StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
+ StopMusic();
+ StopSoundExt(-1, SND_CTRL_STOP_ALL);
}
-void StopSoundExt(int nr, int method)
+void StopSoundExt(int nr, int state)
{
- struct SoundControl snd_ctrl = emptySoundControl;
+ SoundControl snd_ctrl;
if (!audio.sound_available)
return;
- if (SSND_FADING(method))
- snd_ctrl.fade_sound = TRUE;
+ snd_ctrl.active = FALSE;
+ snd_ctrl.nr = nr;
+ snd_ctrl.state = state;
+
+ HandleSoundRequest(snd_ctrl);
+}
+
+ListNode *newListNode()
+{
+ return checked_calloc(sizeof(ListNode));
+}
+
+void addNodeToList(ListNode **node_first, char *key, void *content)
+{
+ ListNode *node_new = newListNode();
+
+#if 0
+ printf("LIST: adding node with key '%s'\n", key);
+#endif
+
+ 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 0
+ printf("[CHECKING LIST KEY '%s' == '%s']\n",
+ (*node_first)->key, key);
+#endif
+
+ if (strcmp((*node_first)->key, key) == 0)
+ {
+#if 0
+ printf("[DELETING LIST ENTRY]\n");
+#endif
+
+ 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 (SSND_ALL(method))
- snd_ctrl.stop_all_sounds = TRUE;
+ if (strcmp(node_first->key, key) == 0)
+ 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)
{
- snd_ctrl.nr = nr;
- snd_ctrl.stop_sound = TRUE;
+ printf("['%s' (%d)]\n", node->key,
+ ((SoundInfo *)node->content)->num_references);
+ node = node->next;
}
-#if defined(TARGET_SDL)
+ printf("[%d nodes]\n", getNumNodes(node_first));
+}
+
+static void LoadSoundsInfo()
+{
+ char *filename = getCustomSoundConfigFilename();
+ struct SetupFileList *setup_file_list;
+ int i;
+
+#if 0
+ printf("GOT CUSTOM SOUND CONFIG FILE '%s'\n", filename);
+#endif
+
+ /* always start with reliable default values */
+ for (i=0; i<num_sounds; i++)
+ sound_effect[i].filename = NULL;
+
+ if (filename == NULL)
+ return;
- if (SSND_FADING(method))
+ if ((setup_file_list = loadSetupFileList(filename)))
{
- int i;
+ for (i=0; i<num_sounds; i++)
+ sound_effect[i].filename =
+ getStringCopy(getTokenValue(setup_file_list, sound_effect[i].text));
- for (i=0; i<audio.channels; i++)
- if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
- Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
- if (snd_ctrl.stop_all_sounds)
- Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
+ freeSetupFileList(setup_file_list);
+
+#if 0
+ for (i=0; i<num_sounds; i++)
+ {
+ printf("'%s' ", sound_effect[i].text);
+ if (sound_effect[i].filename)
+ printf("-> '%s'\n", sound_effect[i].filename);
+ else
+ printf("-> UNDEFINED [-> '%s']\n", sound_effect[i].default_filename);
+ }
+#endif
}
- else
+}
+
+static void ReloadCustomSounds()
+{
+ static boolean draw_init_text = TRUE; /* only draw at startup */
+ int i;
+
+#if 0
+ printf("DEBUG: reloading sounds '%s' ...\n",artwork.sounds_set_current_name);
+#endif
+
+ LoadSoundsInfo();
+
+ if (draw_init_text)
+ DrawInitText("Loading sounds:", 120, FC_GREEN);
+
+#if 0
+ printf("DEBUG: reloading %d sounds ...\n", num_sounds);
+#endif
+
+ for(i=0; i<num_sounds; i++)
{
- int i;
+ if (draw_init_text)
+ DrawInitText(sound_effect[i].text, 150, FC_YELLOW);
- for (i=0; i<audio.channels; i++)
- if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
- Mix_HaltChannel(i);
- if (snd_ctrl.stop_all_sounds)
- Mix_HaltMusic();
+ if (sound_effect[i].filename)
+ LoadSoundToList(sound_effect[i].filename, i);
+ else
+ LoadSoundToList(sound_effect[i].default_filename, i);
}
+ draw_init_text = FALSE;
+
+ /*
+ printf("list size == %d\n", getNumNodes(SoundFileList));
+ */
+
+#if 0
+ dumpList(SoundFileList);
+#endif
+}
+
+static void ReloadCustomMusic()
+{
+#if 0
+ printf("DEBUG: reloading music '%s' ...\n", artwork.music_set_current_name);
+#endif
+
+#if 0
+ /* this is done directly in LoadCustomMusic() now */
+ FreeAllMusic();
+#endif
+
+ LoadCustomMusic();
+}
+
+void InitReloadSounds(char *set_name)
+{
+ if (!audio.sound_available)
+ return;
+
+#if defined(AUDIO_UNIX_NATIVE)
+ WriteReloadInfoToPipe(set_name, SND_CTRL_RELOAD_SOUNDS);
#else
-#if !defined(PLATFORM_MSDOS)
- if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
- {
- Error(ERR_WARN, "cannot pipe to child process -- no sounds");
- audio.sound_available = audio.sound_enabled = FALSE;
+ ReloadCustomSounds();
+#endif
+}
+
+void InitReloadMusic(char *set_name)
+{
+ if (!audio.music_available)
return;
- }
+
+#if defined(AUDIO_UNIX_NATIVE)
+ WriteReloadInfoToPipe(set_name, SND_CTRL_RELOAD_MUSIC);
#else
- sound_handler(snd_ctrl);
+ 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
+ }
+
+ if (sound->source_filename)
+ free(sound->source_filename);
+
+ free(sound);
+}
+
+void FreeMusic(MusicInfo *music)
+{
+ 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);
}
-void FreeSounds(int num_sounds)
+void FreeAllSounds()
{
int i;
- if (!audio.sound_available)
+ if (Sound == NULL)
return;
+#if 0
+ printf("%s: FREEING SOUNDS ...\n",
+ IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
+#endif
+
for(i=0; i<num_sounds; i++)
-#if defined(TARGET_SDL)
- free(Sound[i].mix_chunk);
-#elif !defined(PLATFORM_MSDOS)
- free(Sound[i].data_ptr);
-#else
- destroy_sample(Sound[i].sample_ptr);
+ deleteSoundEntry(&Sound[i]);
+ /*
+ FreeSound(Sound[i]);
+ */
+
+#if 0
+ printf("%s: FREEING SOUNDS -- DONE\n",
+ IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
#endif
+
+ free(Sound);
+
+ Sound = NULL;
+ num_sounds = 0;
+}
+
+void FreeAllMusic()
+{
+ int i;
+
+ if (Music == NULL)
+ return;
+
+ for(i=0; i<num_music; i++)
+ FreeMusic(Music[i]);
+
+ free(Music);
+
+ Music = NULL;
+ num_music = 0;
}
/* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#ifndef SOUND_H
#define SOUND_H
-#include <math.h>
-
#include "platform.h"
-#if defined(PLATFORM_LINUX)
-#include <sys/ioctl.h>
-#endif
-#if defined(PLATFORM_LINUX)
-#include <linux/soundcard.h>
-#elif defined(PLATFORM_FREEBSD)
-#include <machine/soundcard.h>
-#elif defined(PLATFORM_NETBSD)
-#include <sys/ioctl.h>
-#include <sys/audioio.h>
-#elif defined(PLATFORM_HPUX)
-#include <sys/audio.h>
+#if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
+#define AUDIO_UNIX_NATIVE
#endif
-#include "system.h"
-
-
#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) || defined(VOXWARE)
#define AUDIO_LINUX_IOCTL
#endif
#define AUDIO_STREAMING_DSP
#endif
-#define AUDIO_SAMPLE_RATE_8000 8000
-#define AUDIO_SAMPLE_RATE_22050 22050
+/* 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_MONO_CHANNEL 1
-#define AUDIO_STEREO_CHANNELS 2
-
-#if defined(TARGET_SDL)
-/* one second fading interval == 1000 ticks (milliseconds) */
-#define SOUND_FADING_INTERVAL 1000
-#define SOUND_MAX_VOLUME SDL_MIX_MAXVOLUME
-#endif
+#define AUDIO_FRAGMENT_SIZE_512 512
+#define AUDIO_FRAGMENT_SIZE_1024 1024
+#define AUDIO_FRAGMENT_SIZE_2048 2048
+#define AUDIO_FRAGMENT_SIZE_4096 4096
-#if defined(AUDIO_STREAMING_DSP)
-#define SOUND_FADING_VOLUME_STEP (PSND_MAX_VOLUME / 40)
-#define SOUND_FADING_VOLUME_THRESHOLD (SOUND_FADING_VOLUME_STEP * 2)
-#endif
+#define AUDIO_NUM_CHANNELS_MONO 1
+#define AUDIO_NUM_CHANNELS_STEREO 2
-#define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_22050
-#define DEFAULT_AUDIO_FRAGMENT_SIZE_UNIX AUDIO_FRAGMENT_SIZE_512
-#define DEFAULT_AUDIO_FRAGMENT_SIZE_WIN32 AUDIO_FRAGMENT_SIZE_2048
+#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(PLATFORM_UNIX)
-#define DEFAULT_AUDIO_FRAGMENT_SIZE DEFAULT_AUDIO_FRAGMENT_SIZE_UNIX
+#if defined(AUDIO_UNIX_NATIVE) && !defined(AUDIO_STREAMING_DSP)
+#define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_8000
#else
-#define DEFAULT_AUDIO_FRAGMENT_SIZE DEFAULT_AUDIO_FRAGMENT_SIZE_WIN32
+#define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_22050
#endif
-#if !defined(PLATFORM_MSDOS)
-#define MAX_SOUNDS_PLAYING 16
+#if defined(PLATFORM_WIN32)
+#define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_2048
#else
-#define MAX_SOUNDS_PLAYING 8
+#define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_512
#endif
-#if !defined(PLATFORM_HPUX)
-#define SND_BLOCKSIZE 4096
+#if defined(TARGET_SDL)
+#define NUM_MIXER_CHANNELS MIX_CHANNELS
#else
-#define SND_BLOCKSIZE 32768
+#define NUM_MIXER_CHANNELS 8
#endif
-/* some values for PlaySound(), StopSound() and friends */
-#if !defined(PLATFORM_MSDOS)
-#define PSND_SILENCE 0
-#define PSND_MAX_VOLUME_BITS 7
-#define PSND_MIN_VOLUME 0
-#define PSND_MAX_VOLUME (1 << PSND_MAX_VOLUME_BITS)
-#define PSND_NO_LOOP 0
-#define PSND_LOOP 1
-#define PSND_MIDDLE 0
-#define PSND_MAX_STEREO_BITS 7
-#define PSND_MAX_STEREO (1 << PSND_MAX_STEREO_BITS)
-#define PSND_MAX_LEFT (-PSND_MAX_STEREO)
-#define PSND_MAX_RIGHT (+PSND_MAX_STEREO)
-#define PSND_MAX_LEFT2RIGHT_BITS (PSND_MAX_STEREO_BITS+1)
-#define PSND_MAX_LEFT2RIGHT (1 << PSND_MAX_LEFT2RIGHT_BITS)
-#else
-#define PSND_SILENCE 0
-#define PSND_MIN_VOLUME 0
-#define PSND_MAX_VOLUME 255
-#define PSND_NO_LOOP 0
-#define PSND_LOOP 1
-#define PSND_MAX_LEFT 0
-#define PSND_MAX_RIGHT 255
-#define PSND_MIDDLE 128
-#endif
+#define MUSIC_CHANNEL 0
+#define FIRST_SOUND_CHANNEL 1
-#define SSND_FADE_SOUND (1<<0)
-#define SSND_FADE_ALL_SOUNDS (1<<1)
-#define SSND_FADING(x) (x & (SSND_FADE_SOUND | SSND_FADE_ALL_SOUNDS))
-#define SSND_STOP_SOUND (1<<2)
-#define SSND_STOP_ALL_SOUNDS (1<<3)
-#define SSND_STOPPING(x) (x & (SSND_STOP_SOUND | SSND_STOP_ALL_SOUNDS))
-#define SSND_ALL(x) (x&(SSND_FADE_ALL_SOUNDS|SSND_STOP_ALL_SOUNDS))
-
-/* settings for sound path, sound device, etc. */
-#ifndef SND_PATH
-#define SND_PATH "./sounds"
-#endif
-#define DEVICENAME_DSP "/dev/dsp"
-#define DEVICENAME_AUDIO "/dev/audio"
-#define DEVICENAME_AUDIOCTL "/dev/audioCtl"
+/* 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)
-#if 0
-#if defined(AUDIO_STREAMING_DSP)
-#define AUDIO_DEVICE DEVICENAME_DSP
-#else
-#define AUDIO_DEVICE DEVICENAME_AUDIO
-#endif
-#endif
+#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)
-#if 0
-struct SoundHeader_SUN
-{
- unsigned long magic;
- unsigned long hdr_size;
- unsigned long data_size;
- unsigned long encoding;
- unsigned long sample_rate;
- unsigned long channels;
-};
-
-struct SoundHeader_8SVX
-{
- char magic_FORM[4];
- unsigned long chunk_size;
- char magic_8SVX[4];
-};
-#endif
+#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)
-struct SampleInfo
-{
- char *name;
- byte *data_ptr;
- long data_len;
+#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)
-#if defined(PLATFORM_MSDOS)
- SAMPLE *sample_ptr;
-#endif
+#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 SOUND_MIN_VOLUME 0
#if defined(TARGET_SDL)
- Mix_Chunk *mix_chunk;
- Mix_Music *mix_music;
+#define SOUND_MAX_VOLUME SDL_MIX_MAXVOLUME
+#elif defined(TARGET_ALLEGRO)
+#define SOUND_MAX_VOLUME 255
+#else
+#define SOUND_MAX_VOLUME 128
#endif
-};
-struct SoundControl
+#define SOUND_MAX_LEFT 0
+#define SOUND_MAX_RIGHT 255
+#define SOUND_MAX_LEFT2RIGHT 255
+#define SOUND_MIDDLE (SOUND_MAX_LEFT2RIGHT / 2)
+
+/* value for undefined sound effect filename */
+#define SND_FILE_UNDEFINED "NONE"
+
+
+struct SoundEffectInfo
{
- int nr;
- int volume;
- int stereo;
- boolean active;
- boolean loop;
- boolean fade_sound;
- boolean stop_sound;
- boolean stop_all_sounds;
- int playingtime;
- long playingpos;
- long data_len;
- byte *data_ptr;
-
-#if defined(PLATFORM_MSDOS)
- int voice;
-#endif
+ char *text;
+ char *default_filename;
+
+ char *filename;
};
+
/* general sound functions */
void UnixOpenAudio(void);
void UnixCloseAudio(void);
-/* sound server functions */
-void InitPlaylist(void);
-void StartSoundserver(void);
-void SoundServer(void);
+/* mixer functions */
+void Mixer_InitChannels(void);
+void StartMixer(void);
/* sound client functions */
-boolean LoadSound(char *);
-boolean LoadMod(char *);
-int LoadMusic(void);
void PlayMusic(int);
void PlaySound(int);
void PlaySoundStereo(int, int);
void PlaySoundLoop(int);
-void PlaySoundExt(int, int, int, boolean);
+void PlaySoundMusic(int);
+void PlaySoundExt(int, int, int, int);
void FadeMusic(void);
void FadeSound(int);
void FadeSounds(void);
void StopSound(int);
void StopSounds(void);
void StopSoundExt(int, int);
-void FreeSounds(int);
+void InitSoundList(struct SoundEffectInfo *, int);
+void InitReloadSounds(char *);
+void InitReloadMusic(char *);
+void FreeAllSounds(void);
+void FreeAllMusic(void);
#endif
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "system.h"
#include "sound.h"
+#include "setup.h"
+#include "joystick.h"
#include "misc.h"
struct VideoSystemInfo video;
struct AudioSystemInfo audio;
struct GfxInfo gfx;
+struct ArtworkInfo artwork;
+struct JoystickInfo joystick;
+struct SetupInfo setup;
-struct LevelDirInfo *leveldir_first = NULL;
-struct LevelDirInfo *leveldir_current = NULL;
+LevelDirTree *leveldir_first = NULL;
+LevelDirTree *leveldir_current = NULL;
+int level_nr;
-Display *display = NULL;
-Visual *visual = NULL;
-int screen = 0;
-Colormap cmap = None;
+Display *display = NULL;
+Visual *visual = NULL;
+int screen = 0;
+Colormap cmap = None;
-DrawWindow *window = NULL;
-DrawBuffer *backbuffer = NULL;
-DrawBuffer *drawto = NULL;
+DrawWindow *window = NULL;
+DrawBuffer *backbuffer = NULL;
+DrawBuffer *drawto = NULL;
-int button_status = MB_NOT_PRESSED;
-boolean motion_status = FALSE;
+int button_status = MB_NOT_PRESSED;
+boolean motion_status = FALSE;
-int redraw_mask = REDRAW_NONE;
-int redraw_tiles = 0;
+int redraw_mask = REDRAW_NONE;
+int redraw_tiles = 0;
-int FrameCounter = 0;
+int FrameCounter = 0;
/* ========================================================================= */
void InitProgramInfo(char *unix_userdata_directory, char *program_title,
char *window_title, char *icon_title,
- char *x11_icon_basename, char *x11_iconmask_basename,
- char *msdos_pointer_basename)
+ char *x11_icon_filename, char *x11_iconmask_filename,
+ char *msdos_pointer_filename,
+ char *cookie_prefix, char *filename_prefix,
+ int program_version)
{
- char *gfx_dir = getPath2(options.ro_base_directory, GRAPHICS_DIRECTORY);
- char *x11_icon_filename = getPath2(gfx_dir, x11_icon_basename);
- char *x11_iconmask_filename = getPath2(gfx_dir, x11_iconmask_basename);
- char *msdos_pointer_filename = getPath2(gfx_dir, msdos_pointer_basename);
-
- free(gfx_dir);
-
#if defined(PLATFORM_UNIX)
program.userdata_directory = unix_userdata_directory;
#else
program.x11_icon_filename = x11_icon_filename;
program.x11_iconmask_filename = x11_iconmask_filename;
program.msdos_pointer_filename = msdos_pointer_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);
}
void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
gfx.real_sy = real_sy;
gfx.full_sxsize = full_sxsize;
gfx.full_sysize = full_sysize;
+
+ SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
}
void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
gfx.scrollbuffer_height = scrollbuffer_height;
}
+void SetDrawDeactivationMask(int draw_deactivation_mask)
+{
+ gfx.draw_deactivation_mask = draw_deactivation_mask;
+}
+
/* ========================================================================= */
/* video functions */
#if defined(TARGET_SDL)
SDL_QuitSubSystem(SDL_INIT_VIDEO);
#else
+
if (display)
XCloseDisplay(display);
#endif
return new_bitmap;
}
-inline void FreeBitmap(Bitmap *bitmap)
+inline static void FreeBitmapPointers(Bitmap *bitmap)
{
if (bitmap == NULL)
return;
SDL_FreeSurface(bitmap->surface);
if (bitmap->surface_masked)
SDL_FreeSurface(bitmap->surface_masked);
+ bitmap->surface = NULL;
+ bitmap->surface_masked = NULL;
#else
+ /* The X11 version seems to have a memory leak here -- although
+ "XFreePixmap()" is called, the correspondig 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;
#endif
+ if (bitmap->source_filename)
+ 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;
+}
+
+inline void FreeBitmap(Bitmap *bitmap)
+{
+ if (bitmap == NULL)
+ return;
+
+ FreeBitmapPointers(bitmap);
+
free(bitmap);
}
#endif
}
+inline boolean DrawingDeactivated(int x, int y, int width, int height)
+{
+ if (gfx.draw_deactivation_mask != REDRAW_NONE)
+ {
+ if ((gfx.draw_deactivation_mask & REDRAW_FIELD) &&
+ x < gfx.sx + gfx.sxsize)
+ return TRUE;
+ else if ((gfx.draw_deactivation_mask & REDRAW_DOORS) &&
+ x > gfx.dx)
+ {
+ if ((gfx.draw_deactivation_mask & REDRAW_DOOR_1) &&
+ y < gfx.dy + gfx.dysize)
+ return TRUE;
+ else if ((gfx.draw_deactivation_mask & REDRAW_DOOR_2) &&
+ y > gfx.vy)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
inline void BlitBitmap(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;
+
#ifdef TARGET_SDL
SDLCopyArea(src_bitmap, dst_bitmap,
src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
{
+ if (DrawingDeactivated(x, y, width, height))
+ return;
+
#ifdef TARGET_SDL
SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
#else
int width, int height,
int dst_x, int dst_y)
{
+ if (DrawingDeactivated(dst_x, dst_y, width, height))
+ return;
+
#ifdef TARGET_SDL
SDLCopyArea(src_bitmap, dst_bitmap,
src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
return fullscreen;
}
-Bitmap *LoadImage(char *basename)
+Bitmap *LoadImage(char *filename)
{
Bitmap *new_bitmap;
- char *filename = getPath3(options.ro_base_directory, GRAPHICS_DIRECTORY,
- basename);
#if defined(TARGET_SDL)
new_bitmap = SDLLoadImage(filename);
new_bitmap = X11LoadImage(filename);
#endif
- free(filename);
+ 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 (strcmp(filename, bitmap->source_filename) == 0)
+ {
+ /* 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 has wrong dimensions");
+ FreeBitmap(new_bitmap);
+ return;
+ }
+
+ TransferBitmapPointers(new_bitmap, bitmap);
+ free(new_bitmap);
+}
+
/* ========================================================================= */
/* audio functions */
audio.sound_available = FALSE;
audio.music_available = FALSE;
audio.loops_available = FALSE;
- audio.mods_available = FALSE;
+
audio.sound_enabled = FALSE;
+ audio.sound_deactivated = FALSE;
- audio.soundserver_pipe[0] = audio.soundserver_pipe[1] = 0;
- audio.soundserver_pid = 0;
+ audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
+ audio.mixer_pid = -1;
audio.device_name = NULL;
- audio.device_fd = 0;
+ audio.device_fd = -1;
- audio.channels = 0;
+ audio.num_channels = 0;
audio.music_channel = 0;
- audio.music_nr = 0;
+ audio.first_sound_channel = 0;
#if defined(TARGET_SDL)
SDLOpenAudio();
-#elif defined(PLATFORM_MSDOS)
- MSDOSOpenAudio();
#elif defined(PLATFORM_UNIX)
UnixOpenAudio();
+#elif defined(PLATFORM_MSDOS)
+ MSDOSOpenAudio();
#endif
}
{
#if defined(TARGET_SDL)
SDLCloseAudio();
-#elif defined(PLATFORM_MSDOS)
- MSDOSCloseAudio();
#elif defined(PLATFORM_UNIX)
UnixCloseAudio();
+#elif defined(PLATFORM_MSDOS)
+ MSDOSCloseAudio();
#endif
audio.sound_enabled = FALSE;
(int)SDL_GetModState());
#endif
- if (with_modifiers && event->keysym.unicode != 0)
+ if (with_modifiers &&
+ event->keysym.unicode > 0x0000 &&
+ event->keysym.unicode < 0x2000)
return event->keysym.unicode;
else
return event->keysym.sym;
}
-inline void dummy(void)
+/* ========================================================================= */
+/* joystick functions */
+/* ========================================================================= */
+
+inline void InitJoysticks()
{
-#ifdef TARGET_SDL
-#else
+ int i;
+
+#ifdef 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
+}
+
+inline 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
}
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "x11.h"
#endif
+#if defined(PLATFORM_MACOSX)
+/* 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
-/* contant definitions */
/* the additional 'b' is needed for Win32 to open files in binary mode */
#define MODE_READ "rb"
#define FULLSCREEN_NOT_AVAILABLE FALSE
#define FULLSCREEN_AVAILABLE TRUE
-/* values for button_status */
+/* 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
+#define DEFAULT_KEY_SNAP KSYM_Shift_L
+#define DEFAULT_KEY_BOMB KSYM_Shift_R
+#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
+
+/* values for move directions and special "button" keys */
+#define MV_NO_MOVING 0
+#define MV_LEFT (1 << 0)
+#define MV_RIGHT (1 << 1)
+#define MV_UP (1 << 2)
+#define MV_DOWN (1 << 3)
+#define KEY_BUTTON_1 (1 << 4)
+#define KEY_BUTTON_2 (1 << 5)
+#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)
+
+/* values for button status */
#define MB_NOT_PRESSED FALSE
#define MB_NOT_RELEASED TRUE
#define MB_RELEASED FALSE
#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 REDRAW_FPS (1 << 11)
#define REDRAWTILES_THRESHOLD (SCR_FIELDX * SCR_FIELDY / 2)
+/* 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 text for non-existant artwork */
+#define NOT_AVAILABLE "(not available)"
+
/* default name for new levels */
#define NAMELESS_LEVEL_NAME "nameless level"
#define RW_BASE_PATH RW_GAME_DIR
#define GRAPHICS_DIRECTORY "graphics"
-#define MUSIC_DIRECTORY "music"
#define SOUNDS_DIRECTORY "sounds"
+#define MUSIC_DIRECTORY "music"
#define LEVELS_DIRECTORY "levels"
#define TAPES_DIRECTORY "tapes"
#define SCORES_DIRECTORY "scores"
+#if !defined(PLATFORM_MSDOS)
+#define GRAPHICS_SUBDIR "gfx_classic"
+#define SOUNDS_SUBDIR "snd_classic"
+#define MUSIC_SUBDIR "mus_classic"
+#else
+#define GRAPHICS_SUBDIR "gfx_orig"
+#define SOUNDS_SUBDIR "snd_orig"
+#define MUSIC_SUBDIR "mus_orig"
+#endif
+
/* areas in bitmap PIX_DOOR */
/* meaning in PIX_DB_DOOR: (3 PAGEs)
PAGEX1: 1. buffer for DOOR_1
#define DOOR_GFX_PAGEY1 (0)
#define DOOR_GFX_PAGEY2 (gfx.dysize)
+/* functions for version handling */
+#define VERSION_IDENT(x,y,z) ((x) * 10000 + (y) * 100 + (z))
+#define VERSION_MAJOR(x) ((x) / 10000)
+#define VERSION_MINOR(x) (((x) % 10000) / 100)
+#define VERSION_PATCH(x) ((x) % 100)
+
+/* functions for parent/child process identification */
+#define IS_PARENT_PROCESS(pid) ((pid) > 0)
+#define IS_CHILD_PROCESS(pid) ((pid) == 0)
-/* type definitions */
+/* type definitions */
typedef int (*EventFilter)(const Event *);
char *program_title;
char *window_title;
char *icon_title;
+
char *x11_icon_filename;
char *x11_iconmask_filename;
char *msdos_pointer_filename;
+ char *cookie_prefix;
+ char *filename_prefix; /* prefix to cut off from DOS filenames */
+
+ int version_major;
+ int version_minor;
+ int version_patch;
+
void (*exit_function)(int);
};
char *ro_base_directory;
char *rw_base_directory;
char *level_directory;
+ char *graphics_directory;
+ char *sounds_directory;
+ char *music_directory;
boolean serveronly;
boolean network;
boolean verbose;
boolean debug;
+ char *debug_command;
};
struct VideoSystemInfo
struct AudioSystemInfo
{
boolean sound_available;
- boolean music_available;
boolean loops_available;
- boolean mods_available;
+ boolean music_available;
+
boolean sound_enabled;
+ boolean sound_deactivated; /* for temporarily disabling sound */
- int soundserver_pipe[2];
- int soundserver_pid;
+ int mixer_pipe[2];
+ int mixer_pid;
char *device_name;
int device_fd;
- int channels;
+ int num_channels;
int music_channel;
- int music_nr;
+ int first_sound_channel;
};
struct GfxInfo
int vx, vy;
int vxsize, vysize;
+
+ boolean draw_deactivation_mask;
};
-struct LevelDirInfo
+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;
+ int bomb;
+};
+
+struct SetupKeyboardInfo
+{
+ Key left;
+ Key right;
+ Key up;
+ Key down;
+ Key snap;
+ Key bomb;
+};
+
+struct SetupInputInfo
+{
+ boolean use_joystick;
+ struct SetupJoystickInfo joy;
+ struct SetupKeyboardInfo key;
+};
+
+struct SetupShortcutInfo
+{
+ Key save_game;
+ Key load_game;
+ Key toggle_pause;
+};
+
+struct SetupInfo
+{
+ char *player_name;
+
+ boolean sound;
+ boolean sound_loops;
+ boolean sound_music;
+ boolean sound_simple;
+ boolean toons;
+ boolean double_buffering;
+ boolean direct_draw; /* !double_buffering (redundant!) */
+ boolean scroll_delay;
+ boolean soft_scrolling;
+ boolean fading;
+ boolean autorecord;
+ boolean quick_doors;
+ boolean team_mode;
+ boolean handicap;
+ boolean time_limit;
+ boolean fullscreen;
+ boolean ask_on_escape;
+
+ char *graphics_set;
+ char *sounds_set;
+ char *music_set;
+ boolean override_level_graphics;
+ boolean override_level_sounds;
+ boolean override_level_music;
+
+ struct SetupShortcutInfo shortcut;
+ struct SetupInputInfo input[MAX_PLAYERS];
+};
+
+#define TREE_TYPE_GENERIC 0
+#define TREE_TYPE_LEVEL_DIR 1
+#define TREE_TYPE_GRAPHICS_DIR 2
+#define TREE_TYPE_SOUNDS_DIR 3
+#define TREE_TYPE_MUSIC_DIR 4
+
+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 *filename; /* level series single directory name */
char *fullpath; /* complete path relative to level directory */
char *basepath; /* absolute base path of level directory */
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 */
- int cl_first; /* internal control field for "choose level" screen */
- int cl_cursor; /* internal control field for "choose level" screen */
+};
+
+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 LevelDirInfo *node_parent; /* parent level directory info */
- struct LevelDirInfo *node_group; /* level group sub-directory info */
- struct LevelDirInfo *next; /* next level series structure node */
+struct ArtworkInfo
+{
+ GraphicsDirTree *gfx_first;
+ GraphicsDirTree *gfx_current;
+ SoundsDirTree *snd_first;
+ SoundsDirTree *snd_current;
+ MusicDirTree *mus_first;
+ MusicDirTree *mus_current;
+
+ char *graphics_set_current_name;
+ char *sounds_set_current_name;
+ char *music_set_current_name;
};
extern struct VideoSystemInfo video;
extern struct AudioSystemInfo audio;
extern struct GfxInfo gfx;
+extern struct ArtworkInfo artwork;
+extern struct JoystickInfo joystick;
+extern struct SetupInfo setup;
-extern struct LevelDirInfo *leveldir_first;
-extern struct LevelDirInfo *leveldir_current;
+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 Display *display;
+extern Visual *visual;
+extern int screen;
+extern Colormap cmap;
-extern DrawWindow *window;
-extern DrawBuffer *backbuffer;
-extern DrawBuffer *drawto;
+extern DrawWindow *window;
+extern DrawBuffer *backbuffer;
+extern DrawBuffer *drawto;
-extern int button_status;
-extern boolean motion_status;
+extern int button_status;
+extern boolean motion_status;
-extern int redraw_mask;
-extern int redraw_tiles;
+extern int redraw_mask;
+extern int redraw_tiles;
-extern int FrameCounter;
+extern int FrameCounter;
/* function definitions */
void InitPlatformDependantStuff(void);
void ClosePlatformDependantStuff(void);
-void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *);
+void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *,
+ char *, char *, int);
void InitGfxFieldInfo(int, int, int, int, int, int, int, int);
void InitGfxDoor1Info(int, int, int, int);
void InitGfxDoor2Info(int, int, int, int);
void InitGfxScrollbufferInfo(int, int);
+void SetDrawDeactivationMask(int );
inline void InitVideoDisplay(void);
inline void CloseVideoDisplay(void);
inline boolean ChangeVideoModeIfNeeded(boolean);
Bitmap *LoadImage(char *);
+Bitmap *LoadCustomImage(char *);
+void ReloadCustomImage(Bitmap *, char *);
inline void OpenAudio(void);
inline void CloseAudio(void);
inline Key GetEventKey(KeyEvent *, boolean);
inline boolean CheckCloseWindowEvent(ClientMessageEvent *);
+inline void InitJoysticks();
+inline boolean ReadJoystick(int, int *, int *, boolean *, boolean *);
+
#endif /* SYSTEM_H */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
c = 92;
else if (c == 'ü' || c == 'Ü')
c = 93;
+ else if (c == '[' || c == ']') /* map to normal braces */
+ c = (c == '[' ? '(' : ')');
+ else if (c == '\\') /* bad luck ... */
+ c = '/';
- if ((c >= 32 && c <= 95) || c == '°')
+ if ((c >= 32 && c <= 95) || c == '°' || c == '´')
{
int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
int dest_x = x, dest_y = y;
- if (c == '°')
+ if (c == '°' || c == '´') /* map '°' and 'TM' signs */
{
- src_x = (FONT_CHARS_PER_LINE + 1) * font_width;
- src_y = 3 * font_height + font_start;
+ src_x = FONT_CHARS_PER_LINE * font_width;
+ src_y = (c == '°' ? 1 : 2) * font_height + font_start;
}
if (print_inverse)
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1995-2002 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;
+
+void InitToonScreen(Bitmap **toon_bitmap_array,
+ 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)
+{
+ screen_info.toon_bitmap_array = toon_bitmap_array;
+ 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;
+}
+
+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 buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
+
+#if 1
+ /* special method to avoid flickering interference with BackToFront() */
+ BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
+ width+2*pad_x, height+2*pad_y, buf_x, buf_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, dest_x-pad_x, dest_y-pad_y,
+ width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
+
+ screen_info.update_function();
+
+ BlitBitmap(screen_info.save_buffer, backbuffer, buf_x, buf_y,
+ width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
+#else
+ /* normal method, causing flickering interference with BackToFront() */
+ BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
+ width+2*pad_x, height+2*pad_y, buf_x, buf_y);
+ SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
+ BlitBitmapMasked(toon_bitmap, screen_info.save_buffer,
+ src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
+ BlitBitmap(screen_info.save_buffer, window, buf_x, buf_y,
+ width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
+#endif
+
+ FlushDisplay();
+}
+
+boolean AnimateToon(int toon_nr, boolean restart)
+{
+ static int pos_x = 0, pos_y = 0;
+ static int delta_x = 0, delta_y = 0;
+ static int frame = 0, frame_step = 1;
+ 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];
+ int bitmap_nr = screen_info.toons[toon_nr].bitmap_nr;
+ Bitmap *anim_bitmap = screen_info.toon_bitmap_array[bitmap_nr];
+ GC anim_clip_gc = anim_bitmap->stored_clip_gc;
+
+ if (restart)
+ {
+ horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
+ vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
+ anim_delay_value = 1000/anim->frames_per_second;
+ frame = 0;
+
+ if (horiz_move)
+ {
+ if (anim->position == ANIMPOS_UP)
+ pos_y = 0;
+ else if (anim->position == ANIMPOS_DOWN)
+ pos_y = screen_info.height - anim->height;
+ else if (anim->position == ANIMPOS_UPPER)
+ pos_y = SimpleRND((screen_info.height - anim->height) / 2);
+ else
+ pos_y = SimpleRND(screen_info.height - anim->height);
+
+ if (anim->direction == ANIMDIR_RIGHT)
+ {
+ delta_x = anim->stepsize;
+ pos_x = -anim->width + delta_x;
+ }
+ else
+ {
+ delta_x = -anim->stepsize;
+ pos_x = screen_info.width + delta_x;
+ }
+ delta_y = 0;
+ }
+ else
+ {
+ if (anim->position == ANIMPOS_LEFT)
+ pos_x = 0;
+ else if (anim->position == ANIMPOS_RIGHT)
+ pos_x = screen_info.width - anim->width;
+ else
+ pos_x = SimpleRND(screen_info.width - anim->width);
+
+ if (anim->direction == ANIMDIR_DOWN)
+ {
+ delta_y = anim->stepsize;
+ pos_y = -anim->height + delta_y;
+ }
+ else
+ {
+ delta_y = -anim->stepsize;
+ pos_y = screen_info.width + delta_y;
+ }
+ delta_x = 0;
+ }
+ }
+
+ if (pos_x <= -anim->width - anim->stepsize ||
+ pos_x >= screen_info.width + anim->stepsize ||
+ pos_y <= -anim->height - anim->stepsize ||
+ pos_y >= screen_info.height + anim->stepsize)
+ 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->stepsize : 0);
+ pad_y = (vert_move ? anim->stepsize : 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 += frame_step;
+
+ if (frame<0 || frame>=anim->frames)
+ {
+ if (anim->pingpong)
+ {
+ frame_step *= -1;
+ frame = (frame<0 ? 1 : anim->frames-2);
+ }
+ else
+ frame = (frame<0 ? anim->frames-1 : 0);
+ }
+
+ return FALSE;
+}
+
+void HandleAnimation(int mode)
+{
+ static unsigned long animstart_delay = -1;
+ static unsigned long animstart_delay_value = 0;
+ static boolean anim_restart = TRUE;
+ static boolean reset_delay = TRUE;
+ static int toon_nr = 0;
+ int draw_mode;
+
+ if (!setup.toons)
+ return;
+
+ switch(mode)
+ {
+ case ANIM_START:
+ screen_info.prepare_backbuffer_function();
+ anim_restart = TRUE;
+ reset_delay = TRUE;
+
+ return;
+
+ case ANIM_CONTINUE:
+ break;
+
+ case ANIM_STOP:
+ redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
+
+ /* Redraw background even when in direct drawing mode */
+ draw_mode = setup.direct_draw;
+ setup.direct_draw = FALSE;
+ screen_info.update_function();
+ setup.direct_draw = draw_mode;
+
+ return;
+
+ default:
+ break;
+ }
+
+ if (reset_delay)
+ {
+ animstart_delay = Counter();
+ animstart_delay_value = SimpleRND(3000);
+ reset_delay = FALSE;
+ }
+
+ if (anim_restart)
+ {
+ if (!DelayReached(&animstart_delay, animstart_delay_value))
+ return;
+
+ toon_nr = SimpleRND(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);
+}
--- /dev/null
+/***********************************************************
+* Artsoft Retro-Game Library *
+*----------------------------------------------------------*
+* (c) 1995-2002 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"
+
+
+/* values for toon animation */
+#define ANIMDIR_LEFT 1
+#define ANIMDIR_RIGHT 2
+#define ANIMDIR_UP 4
+#define ANIMDIR_DOWN 8
+
+#define ANIMPOS_ANY 0
+#define ANIMPOS_LEFT 1
+#define ANIMPOS_RIGHT 2
+#define ANIMPOS_UP 4
+#define ANIMPOS_DOWN 8
+#define ANIMPOS_UPPER 16
+
+
+struct ToonScreenInfo
+{
+ Bitmap **toon_bitmap_array;
+ 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;
+};
+
+struct ToonInfo
+{
+ int bitmap_nr;
+ int width, height;
+ int src_x, src_y;
+ int frames;
+ int frames_per_second;
+ int stepsize;
+ boolean pingpong;
+ int direction;
+ int position;
+};
+
+
+void InitToonScreen();
+void InitAnimation(void);
+void StopAnimation(void);
+void DoAnimation(void);
+
+#endif /* TOONS_H */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#ifndef TYPES_H
#define TYPES_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
typedef unsigned char boolean;
typedef unsigned char byte;
#define SIGN(a) ((a) < 0 ? -1 : ((a)>0 ? 1 : 0))
#endif
+#define SIZEOF_ARRAY(array, type) (sizeof(array) / sizeof(type))
+#define SIZEOF_ARRAY_INT(array) SIZEOF_ARRAY(array, int)
+
#endif /* TYPES_H */
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "system.h"
#include "pcx.h"
#include "misc.h"
+#include "setup.h"
#if defined(TARGET_X11)
/* got appropriate visual? */
if (depth < 8)
- {
- printf("Sorry, displays with less than 8 bits per pixel not supported.\n");
- exit(-1);
- }
+ 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))
- {
- printf("Sorry, cannot get appropriate visual.\n");
- exit(-1);
- }
+ Error(ERR_EXIT, "X11 display not supported (inappropriate visual)");
#endif /* !PLATFORM_MSDOS */
}
PropModePrepend, (unsigned char *) &delete_atom, 1);
#if 0
- sprintf(icon_filename, "%s/%s/%s",
- options.ro_base_directory, GRAPHICS_DIRECTORY,
+ sprintf(icon_filename, "%s/%s", options.graphics_directory,
icon_pic.picture_filename);
#endif
if (XReadBitmapFile(display, new_window->drawable,
- program.x11_icon_filename,
+ 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 0
- sprintf(icon_filename, "%s/%s/%s",
- options.ro_base_directory, GRAPHICS_DIRECTORY,
+ sprintf(icon_filename, "%s/%s", options.graphics_directory,
icon_pic.picturemask_filename);
#endif
if (XReadBitmapFile(display, new_window->drawable,
- program.x11_iconmask_filename,
+ 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'",
return new_window;
}
+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;
-#if defined(PLATFORM_MSDOS)
- rest(100);
-#endif
-
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:
- Error(ERR_EXIT, "cannot open PCX file '%s'", filename);
+ SetError(error, "cannot open PCX file", filename);
+ return NULL;
case PCX_ReadFailed:
- Error(ERR_EXIT, "cannot read PCX file '%s'", filename);
+ SetError(error, "cannot read PCX file", filename);
+ return NULL;
case PCX_FileInvalid:
- Error(ERR_EXIT, "invalid PCX file '%s'", filename);
+ SetError(error, "invalid PCX file", filename);
+ return NULL;
case PCX_NoMemory:
- Error(ERR_EXIT, "not enough memory for PCX file '%s'", filename);
+ SetError(error, "not enough memory for PCX file", filename);
+ return NULL;
case PCX_ColorFailed:
- Error(ERR_EXIT, "cannot get colors for PCX file '%s'", filename);
+ SetError(error, "cannot get colors for PCX file", filename);
+ return NULL;
+ case PCX_OtherError:
+ /* this should already have called SetError() */
+ return NULL;
default:
- break;
+ SetError(error, "unknown error reading PCX file", filename);
+ return NULL;
}
if (!new_bitmap->drawable)
- Error(ERR_EXIT, "cannot get graphics for '%s'", filename);
+ {
+ SetError("X11LoadImage(): cannot get graphics for '%s'", filename);
+ return NULL;
+ }
if (!new_bitmap->clip_mask)
- Error(ERR_EXIT, "cannot get clipmask for '%s'", filename);
+ {
+ SetError("X11LoadImage(): cannot get clipmask for '%s'", filename);
+ return NULL;
+ }
/* set GraphicContext inheritated from Window */
new_bitmap->gc = window->gc;
+ /* set image width and height */
+ SetImageDimensions(new_bitmap);
+
return new_bitmap;
}
/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2001 Artsoft Entertainment *
+* (c) 1994-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
struct X11DrawableInfo
{
+ char *source_filename;
+
+ int width, height;
Drawable drawable;
Drawable clip_mask;
GC gc; /* GC for normal drawing (inheritated from 'window') */
#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)
+
/* X11 function definitions */
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "init.h"
#include "game.h"
#include "events.h"
-#include "joystick.h"
GC tile_clip_gc;
Bitmap *pix[NUM_BITMAPS];
DrawBuffer *fieldbuffer;
DrawBuffer *drawto_field;
-int joystick_device = 0;
-char *joystick_device_name[MAX_PLAYERS] =
-{
- DEV_JOYSTICK_0,
- DEV_JOYSTICK_1,
- DEV_JOYSTICK_2,
- DEV_JOYSTICK_3
-};
-
int game_status = MAINMENU;
boolean level_editor_test_game = FALSE;
boolean network_playing = FALSE;
int key_joystick_mapping = 0;
-int global_joystick_status = JOYSTICK_STATUS;
-int joystick_status = JOYSTICK_STATUS;
boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
int redraw_x1 = 0, redraw_y1 = 0;
unsigned long Elementeigenschaften1[MAX_ELEMENTS];
unsigned long Elementeigenschaften2[MAX_ELEMENTS];
-int level_nr;
int lev_fieldx,lev_fieldy, scroll_x,scroll_y;
int FX = SX, FY = SY, ScrollStepSize;
"gate.wav"
};
-/* background music */
-int background_loop[] =
+struct SoundEffectInfo sound_effects[] =
{
+ /* sounds for Boulder Dash style elements and actions */
+ { "bd_empty_space.digging", "empty.wav" },
+ { "bd_sand.digging", "schlurf.wav" },
+ { "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.changing", "quirk.wav" },
+ { "bd_magic_wall.running", "miep.wav" },
+ { "bd_amoeba.waiting", SND_FILE_UNDEFINED },
+ { "bd_amoeba.creating", "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" },
+ { "bd_exit.entering", "buing.wav" },
+
+ /* sounds for Supaplex style elements and actions */
+ { "sp_empty_space.digging", "empty.wav" },
+ { "sp_base.digging", "base.wav" },
+ { "sp_buggy_base.digging", "base.wav" },
+ { "sp_buggy_base.activating", "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.entering", "exit.wav" },
+ { "sp_element.exploding", "booom.wav" },
+ { "sp_sniksnak.moving", SND_FILE_UNDEFINED },
+ { "sp_sniksnak.waiting", SND_FILE_UNDEFINED },
+ { "sp_electron.moving", SND_FILE_UNDEFINED },
+ { "sp_electron.waiting", SND_FILE_UNDEFINED },
+ { "sp_terminal.activating", SND_FILE_UNDEFINED },
+
+ /* sounds for Sokoban style elements and actions */
+ { "sokoban_object.pushing", "pusch.wav" },
+ { "sokoban_field.filling", "deng.wav" },
+ { "sokoban_field.clearing", SND_FILE_UNDEFINED },
+ { "sokoban_game.solving", "buing.wav" },
+
+ /* sounds for Emerald Mine style elements and actions */
+ { "empty_space.digging", "empty.wav" },
+ { "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.cracking", "knack.wav" },
+ { "nut.impact", "klumpf.wav" },
+ { "dynamite.collecting", "pong.wav" },
+ { "dynamite.placing", "deng.wav" },
+ { "dynamite.burning", "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", SND_FILE_UNDEFINED },
+ { "yamyam.waiting", "njam.wav" },
+ { "yamyam.eating_diamond", SND_FILE_UNDEFINED },
+ { "robot.stepping", "schlurf.wav" },
+ { "robot.waiting", SND_FILE_UNDEFINED },
+ { "robot_wheel.activating", "deng.wav" },
+ { "robot_wheel.running", "miep.wav" },
+ { "magic_wall.activating", "quirk.wav" },
+ { "magic_wall.changing", "quirk.wav" },
+ { "magic_wall.running", "miep.wav" },
+ { "amoeba.waiting", SND_FILE_UNDEFINED },
+ { "amoeba.creating", "amoebe.wav" },
+ { "amoeba.dropping", SND_FILE_UNDEFINED },
+ { "acid.splashing", "blurb.wav" },
+ { "quicksand.filling", SND_FILE_UNDEFINED },
+ { "quicksand.slipping_through", SND_FILE_UNDEFINED },
+ { "quicksand.emptying", SND_FILE_UNDEFINED },
+ { "exit.opening", "oeffnen.wav" },
+ { "exit.entering", "buing.wav" },
+
+ /* sounds for Emerald Mine Club style elements and actions */
+ { "balloon.moving", SND_FILE_UNDEFINED },
+ { "balloon.waiting", SND_FILE_UNDEFINED },
+ { "balloon.pushing", "schlurf.wav" },
+ { "balloon_switch.activating", SND_FILE_UNDEFINED },
+ { "spring.moving", SND_FILE_UNDEFINED },
+ { "spring.pushing", "pusch.wav" },
+ { "spring.impact", "klopf.wav" },
+ { "wall.growing", SND_FILE_UNDEFINED },
+
+ /* 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" },
+ { "sand_invisible.digging", "schlurf.wav" },
+ { "shield_passive.collecting", "pong.wav" },
+ { "shield_passive.activated", SND_FILE_UNDEFINED },
+ { "shield_active.collecting", "pong.wav" },
+ { "shield_active.activated", SND_FILE_UNDEFINED },
+ { "extra_time.collecting", "gong.wav" },
+ { "mole.moving", SND_FILE_UNDEFINED },
+ { "mole.waiting", SND_FILE_UNDEFINED },
+ { "mole.eating_amoeba", "blurb.wav" },
+ { "switchgate_switch.activating", SND_FILE_UNDEFINED },
+ { "switchgate.opening", "oeffnen.wav" },
+ { "switchgate.closing", "oeffnen.wav" },
+ { "switchgate.passing", "gate.wav" },
+ { "timegate_wheel.activating", "deng.wav" },
+ { "timegate_wheel.running", "miep.wav" },
+ { "timegate.opening", "oeffnen.wav" },
+ { "timegate.closing", "oeffnen.wav" },
+ { "timegate.passing", "gate.wav" },
+ { "conveyor_belt_switch.activating", SND_FILE_UNDEFINED },
+ { "conveyor_belt.running", SND_FILE_UNDEFINED },
+ { "light_switch.activating", SND_FILE_UNDEFINED },
+ { "light_switch.deactivating", SND_FILE_UNDEFINED },
+
+ /* sounds for DX Boulderdash style elements and actions */
+ { "dx_bomb.pushing", "pusch.wav" },
+ { "trap_inactive.digging", "schlurf.wav" },
+ { "trap.activating", SND_FILE_UNDEFINED },
+ { "tube.passing", SND_FILE_UNDEFINED },
+
+ /* 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_nr.collecting", "pong.wav" },
+ { "dynabomb_sz.collecting", "pong.wav" },
+ { "dynabomb_xl.collecting", "pong.wav" },
+ { "dynabomb.placing", "deng.wav" },
+ { "dynabomb.burning", "zisch.wav" },
+ { "satellite.moving", SND_FILE_UNDEFINED },
+ { "satellite.waiting", SND_FILE_UNDEFINED },
+ { "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" },
+ { "gameoflife.waiting", SND_FILE_UNDEFINED },
+ { "gameoflife.creating", "amoebe.wav" },
+ { "biomaze.waiting", SND_FILE_UNDEFINED },
+ { "biomaze.creating", "amoebe.wav" },
+ { "pacman.moving", SND_FILE_UNDEFINED },
+ { "pacman.waiting", SND_FILE_UNDEFINED },
+ { "pacman.eating_amoeba", SND_FILE_UNDEFINED },
+ { "dark_yamyam.moving", SND_FILE_UNDEFINED },
+ { "dark_yamyam.waiting", "njam.wav" },
+ { "dark_yamyam.eating_any", SND_FILE_UNDEFINED },
+ { "penguin.moving", SND_FILE_UNDEFINED },
+ { "penguin.waiting", SND_FILE_UNDEFINED },
+ { "penguin.entering_exit", "buing.wav" },
+ { "pig.moving", SND_FILE_UNDEFINED },
+ { "pig.waiting", SND_FILE_UNDEFINED },
+ { "pig.eating_gem", SND_FILE_UNDEFINED },
+ { "dragon.moving", SND_FILE_UNDEFINED },
+ { "dragon.waiting", SND_FILE_UNDEFINED },
+ { "dragon.attacking", SND_FILE_UNDEFINED },
+
+ /* sounds for generic elements and actions */
+ { "player.dying", "autsch.wav" },
+ { "element.exploding", "roaaar.wav" },
+
+ /* sounds for other game actions */
+ { "game.starting", SND_FILE_UNDEFINED },
+ { "game.running_out_of_time", "gong.wav" },
+ { "game.leveltime_bonus", "sirr.wav" },
+ { "game.losing", "lachen.wav" },
+ { "game.winning", SND_FILE_UNDEFINED },
+
+ /* sounds for other non-game actions */
+ { "menu.door_opening", "oeffnen.wav" },
+ { "menu.door_closing", "oeffnen.wav" },
+ { "menu.hall_of_fame", "halloffame.wav" },
+ { "menu.info_screen", "rhythmloop.wav" },
+
#if 0
- SND_ALCHEMY,
- SND_CHASE,
- SND_NETWORK,
- SND_CZARDASZ,
- SND_TYGER,
- SND_VOYAGER,
- SND_TWILIGHT
+ { "[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
};
-int num_bg_loops = sizeof(background_loop)/sizeof(int);
-char *element_info[] =
+struct ElementInfo element_info[] =
{
- "empty space", /* 0 */
- "sand",
- "normal wall",
- "round wall",
- "rock",
- "key",
- "emerald",
- "closed exit",
- "player",
- "bug",
- "spaceship", /* 10 */
- "yam yam",
- "robot",
- "steel wall",
- "diamond",
- "dead amoeba",
- "empty quicksand",
- "quicksand with rock",
- "amoeba drop",
- "bomb",
- "magic wall", /* 20 */
- "speed ball",
- "acid pool",
- "dropping amoeba",
- "normal amoeba",
- "nut with emerald",
- "life wall",
- "biomaze",
- "burning dynamite",
- "unknown",
- "magic wheel", /* 30 */
- "running wire",
- "red key",
- "yellow key",
- "green key",
- "blue key",
- "red door",
- "yellow door",
- "green door",
- "blue door",
- "gray door (opened by red key)", /* 40 */
- "gray door (opened by yellow key)",
- "gray door (opened by green key)",
- "gray door (opened by blue key)",
- "dynamite",
- "pac man",
- "invisible normal wall",
- "light bulb (dark)",
- "ligh bulb (glowing)",
- "wall with emerald",
- "wall with diamond", /* 50 */
- "amoeba with content",
- "amoeba (BD style)",
- "time orb (full)",
- "time orb (empty)",
- "growing wall",
- "diamond (BD style)",
- "yellow emerald",
- "wall with BD style diamond",
- "wall with yellow emerald",
- "dark yam yam", /* 60 */
- "magic wall (BD style)",
- "invisible steel wall",
- "-",
- "increases number of bombs",
- "increases explosion size",
- "increases power of explosion",
- "sokoban object",
- "sokoban empty field",
- "sokoban field with object",
- "butterfly (starts moving right)", /* 70 */
- "butterfly (starts moving up)",
- "butterfly (starts moving left)",
- "butterfly (starts moving down)",
- "firefly (starts moving right)",
- "firefly (starts moving up)",
- "firefly (starts moving left)",
- "firefly (starts moving down)",
- "butterfly",
- "firefly",
- "yellow player", /* 80 */
- "red player",
- "green player",
- "blue player",
- "bug (starts moving right)",
- "bug (starts moving up)",
- "bug (starts moving left)",
- "bug (starts moving down)",
- "spaceship (starts moving right)",
- "spaceship (starts moving up)",
- "spaceship (starts moving left)", /* 90 */
- "spaceship (starts moving down)",
- "pac man (starts moving right)",
- "pac man (starts moving up)",
- "pac man (starts moving left)",
- "pac man (starts moving down)",
- "red emerald",
- "violet emerald",
- "wall with red emerald",
- "wall with violet emerald",
- "unknown", /* 100 */
- "unknown",
- "unknown",
- "unknown",
- "unknown",
- "normal wall (BD style)",
- "rock (BD style)",
- "open exit",
- "black orb bomb",
- "amoeba",
- "mole", /* 110 */
- "penguin",
- "satellite",
- "arrow left",
- "arrow right",
- "arrow up",
- "arrow down",
- "pig",
- "fire breathing dragon",
- "red key (EM style)",
- "letter ' '", /* 120 */
- "letter '!'",
- "letter '\"'",
- "letter '#'",
- "letter '$'",
- "letter '%'",
- "letter '&'",
- "letter '''",
- "letter '('",
- "letter ')'",
- "letter '*'", /* 130 */
- "letter '+'",
- "letter ','",
- "letter '-'",
- "letter '.'",
- "letter '/'",
- "letter '0'",
- "letter '1'",
- "letter '2'",
- "letter '3'",
- "letter '4'", /* 140 */
- "letter '5'",
- "letter '6'",
- "letter '7'",
- "letter '8'",
- "letter '9'",
- "letter ':'",
- "letter ';'",
- "letter '<'",
- "letter '='",
- "letter '>'", /* 150 */
- "letter '?'",
- "letter '@'",
- "letter 'A'",
- "letter 'B'",
- "letter 'C'",
- "letter 'D'",
- "letter 'E'",
- "letter 'F'",
- "letter 'G'",
- "letter 'H'", /* 160 */
- "letter 'I'",
- "letter 'J'",
- "letter 'K'",
- "letter 'L'",
- "letter 'M'",
- "letter 'N'",
- "letter 'O'",
- "letter 'P'",
- "letter 'Q'",
- "letter 'R'", /* 170 */
- "letter 'S'",
- "letter 'T'",
- "letter 'U'",
- "letter 'V'",
- "letter 'W'",
- "letter 'X'",
- "letter 'Y'",
- "letter 'Z'",
- "letter 'Ä'",
- "letter 'Ö'", /* 180 */
- "letter 'Ü'",
- "letter '^'",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''", /* 190 */
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "letter ''",
- "growing wall (horizontal)", /* 200 */
- "growing wall (vertical)",
- "growing wall (all directions)",
- "red door (EM style)",
- "yellow door (EM style)",
- "green door (EM style)",
- "blue door (EM style)",
- "yellow key (EM style)",
- "green key (EM style)",
- "blue key (EM style)",
- "empty space", /* 210 */
- "zonk",
- "base",
- "murphy",
- "infotron",
- "chip (single)",
- "hardware",
- "exit",
- "orange disk",
- "port (leading right)",
- "port (leading down)", /* 220 */
- "port (leading left)",
- "port (leading up)",
- "port (leading right)",
- "port (leading down)",
- "port (leading left)",
- "port (leading up)",
- "snik snak",
- "yellow disk",
- "terminal",
- "red disk", /* 230 */
- "port (vertical)",
- "port (horizontal)",
- "port (all directions)",
- "electron",
- "buggy base",
- "chip (left half)",
- "chip (right half)",
- "hardware",
- "hardware",
- "hardware", /* 240 */
- "hardware",
- "hardware",
- "hardware",
- "hardware",
- "hardware",
- "hardware",
- "hardware",
- "chip (upper half)",
- "chip (lower half)",
- "gray door (EM style, red key)", /* 250 */
- "gray door (EM style, yellow key)",
- "gray door (EM style, green key)",
- "gray door (EM style, blue key)",
- "unknown",
- "unknown",
+ { "empty_space", "empty space" }, /* 0 */
+ { "sand", "sand" },
+ { "wall", "normal wall" },
+ { "wall", "round wall" },
+ { "rock", "rock" },
+ { "key", "key" },
+ { "emerald", "emerald" },
+ { "exit", "closed exit" },
+ { "player", "player" },
+ { "bug", "bug" },
+ { "spaceship", "spaceship" }, /* 10 */
+ { "yamyam", "yam yam" },
+ { "robot", "robot" },
+ { "wall", "steel wall" },
+ { "diamond", "diamond" },
+ { "amoeba", "dead amoeba" },
+ { "quicksand", "empty quicksand" },
+ { "quicksand", "quicksand with rock" },
+ { "amoeba", "amoeba drop" },
+ { "bomb", "bomb" },
+ { "magic_wall", "magic wall" }, /* 20 */
+ { "speed_pill", "speed pill" },
+ { "acid", "acid pool" },
+ { "amoeba", "dropping amoeba" },
+ { "amoeba", "normal amoeba" },
+ { "nut", "nut with emerald" },
+ { "gameoflife", "Conway's wall of life" },
+ { "biomaze", "biomaze" },
+ { "dynamite", "burning dynamite" },
+ { NULL, "unknown" },
+ { "robot_wheel", "magic wheel" }, /* 30 */
+ { "robot_wheel", "magic wheel (running)" },
+ { "key", "red key" },
+ { "key", "yellow key" },
+ { "key", "green key" },
+ { "key", "blue key" },
+ { "gate", "red door" },
+ { "gate", "yellow door" },
+ { "gate", "green door" },
+ { "gate", "blue door" },
+ { "gate", "gray door (opened by red key)" }, /* 40 */
+ { "gate", "gray door (opened by yellow key)"},
+ { "gate", "gray door (opened by green key)"},
+ { "gate", "gray door (opened by blue key)"},
+ { "dynamite", "dynamite" },
+ { "pacman", "pac man" },
+ { "wall", "invisible normal wall" },
+ { "lamp", "lamp (off)" },
+ { "lamp", "lamp (on)" },
+ { "wall", "wall with emerald" },
+ { "wall", "wall with diamond" }, /* 50 */
+ { "amoeba", "amoeba with content" },
+ { "bd_amoeba", "amoeba (BD style)" },
+ { "time_orb_full", "time orb (full)" },
+ { "time_orb_empty", "time orb (empty)" },
+ { "wall", "growing wall" },
+ { "bd_diamond", "diamond (BD style)" },
+ { "emerald", "yellow emerald" },
+ { "wall", "wall with BD style diamond" },
+ { "wall", "wall with yellow emerald" },
+ { "dark_yamyam", "dark yam yam" }, /* 60 */
+ { "bd_magic_wall", "magic wall (BD style)" },
+ { "wall", "invisible steel wall" },
+ { NULL, "-" },
+ { "dynabomb_nr", "increases number of bombs" },
+ { "dynabomb_sz", "increases explosion size" },
+ { "dynabomb_xl", "increases power of explosion" },
+ { "sokoban_object", "sokoban object" },
+ { "sokoban_field", "sokoban empty field" },
+ { "sokoban_field", "sokoban field with object" },
+ { "bd_butterfly", "butterfly (starts moving right)"}, /* 70 */
+ { "bd_butterfly", "butterfly (starts moving up)" },
+ { "bd_butterfly", "butterfly (starts moving left)"},
+ { "bd_butterfly", "butterfly (starts moving down)"},
+ { "bd_firefly", "firefly (starts moving right)" },
+ { "bd_firefly", "firefly (starts moving up)" },
+ { "bd_firefly", "firefly (starts moving left)" },
+ { "bd_firefly", "firefly (starts moving down)" },
+ { "bd_butterfly", "butterfly" },
+ { "bd_firefly", "firefly" },
+ { "player", "yellow player" }, /* 80 */
+ { "player", "red player" },
+ { "player", "green player" },
+ { "player", "blue player" },
+ { "bug", "bug (starts moving right)" },
+ { "bug", "bug (starts moving up)" },
+ { "bug", "bug (starts moving left)" },
+ { "bug", "bug (starts moving down)" },
+ { "spaceship", "spaceship (starts moving right)"},
+ { "spaceship", "spaceship (starts moving up)" },
+ { "spaceship", "spaceship (starts moving left)"}, /* 90 */
+ { "spaceship", "spaceship (starts moving down)"},
+ { "pacman", "pac man (starts moving right)" },
+ { "pacman", "pac man (starts moving up)" },
+ { "pacman", "pac man (starts moving left)" },
+ { "pacman", "pac man (starts moving down)" },
+ { "emerald", "red emerald" },
+ { "emerald", "purple emerald" },
+ { "wall", "wall with red emerald" },
+ { "wall", "wall with purple emerald" },
+ { NULL, "unknown" }, /* 100 */
+ { NULL, "unknown" },
+ { NULL, "unknown" },
+ { NULL, "unknown" },
+ { NULL, "unknown" },
+ { NULL, "normal wall (BD style)" },
+ { "bd_rock", "rock (BD style)" },
+ { "exit", "open exit" },
+ { NULL, "black orb bomb" },
+ { "amoeba", "amoeba" },
+ { "mole", "mole" }, /* 110 */
+ { "penguin", "penguin" },
+ { "satellite", "satellite" },
+ { NULL, "arrow left" },
+ { NULL, "arrow right" },
+ { NULL, "arrow up" },
+ { NULL, "arrow down" },
+ { "pig", "pig" },
+ { "dragon", "fire breathing dragon" },
+ { "key", "red key (EM style)" },
+ { NULL, "letter ' '" }, /* 120 */
+ { NULL, "letter '!'" },
+ { NULL, "letter '\"'" },
+ { NULL, "letter '#'" },
+ { NULL, "letter '$'" },
+ { NULL, "letter '%'" },
+ { NULL, "letter '&'" },
+ { NULL, "letter '''" },
+ { NULL, "letter '('" },
+ { NULL, "letter ')'" },
+ { NULL, "letter '*'" }, /* 130 */
+ { NULL, "letter '+'" },
+ { NULL, "letter ','" },
+ { NULL, "letter '-'" },
+ { NULL, "letter '.'" },
+ { NULL, "letter '/'" },
+ { NULL, "letter '0'" },
+ { NULL, "letter '1'" },
+ { NULL, "letter '2'" },
+ { NULL, "letter '3'" },
+ { NULL, "letter '4'" }, /* 140 */
+ { NULL, "letter '5'" },
+ { NULL, "letter '6'" },
+ { NULL, "letter '7'" },
+ { NULL, "letter '8'" },
+ { NULL, "letter '9'" },
+ { NULL, "letter ':'" },
+ { NULL, "letter ';'" },
+ { NULL, "letter '<'" },
+ { NULL, "letter '='" },
+ { NULL, "letter '>'" }, /* 150 */
+ { NULL, "letter '?'" },
+ { NULL, "letter '@'" },
+ { NULL, "letter 'A'" },
+ { NULL, "letter 'B'" },
+ { NULL, "letter 'C'" },
+ { NULL, "letter 'D'" },
+ { NULL, "letter 'E'" },
+ { NULL, "letter 'F'" },
+ { NULL, "letter 'G'" },
+ { NULL, "letter 'H'" }, /* 160 */
+ { NULL, "letter 'I'" },
+ { NULL, "letter 'J'" },
+ { NULL, "letter 'K'" },
+ { NULL, "letter 'L'" },
+ { NULL, "letter 'M'" },
+ { NULL, "letter 'N'" },
+ { NULL, "letter 'O'" },
+ { NULL, "letter 'P'" },
+ { NULL, "letter 'Q'" },
+ { NULL, "letter 'R'" }, /* 170 */
+ { NULL, "letter 'S'" },
+ { NULL, "letter 'T'" },
+ { NULL, "letter 'U'" },
+ { NULL, "letter 'V'" },
+ { NULL, "letter 'W'" },
+ { NULL, "letter 'X'" },
+ { NULL, "letter 'Y'" },
+ { NULL, "letter 'Z'" },
+ { NULL, "letter 'Ä'" },
+ { NULL, "letter 'Ö'" }, /* 180 */
+ { NULL, "letter 'Ü'" },
+ { NULL, "letter '^'" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" }, /* 190 */
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { NULL, "letter ''" },
+ { "wall", "growing wall (horizontal)" }, /* 200 */
+ { "wall", "growing wall (vertical)" },
+ { "wall", "growing wall (all directions)" },
+ { "gate", "red door (EM style)" },
+ { "gate", "yellow door (EM style)" },
+ { "gate", "green door (EM style)" },
+ { "gate", "blue door (EM style)" },
+ { "key", "yellow key (EM style)" },
+ { "key", "green key (EM style)" },
+ { "key", "blue key (EM style)" },
+ { "empty_space", "empty space" }, /* 210 */
+ { "sp_zonk", "zonk" },
+ { "sp_base", "base" },
+ { "player", "murphy" },
+ { "sp_infotron", "infotron" },
+ { "wall", "chip (single)" },
+ { "wall", "hardware" },
+ { "sp_exit", "exit" },
+ { "sp_disk_orange", "orange disk" },
+ { "sp_port", "port (leading right)" },
+ { "sp_port", "port (leading down)" }, /* 220 */
+ { "sp_port", "port (leading left)" },
+ { "sp_port", "port (leading up)" },
+ { "sp_port", "port (leading right)" },
+ { "sp_port", "port (leading down)" },
+ { "sp_port", "port (leading left)" },
+ { "sp_port", "port (leading up)" },
+ { "sp_sniksnak", "snik snak" },
+ { "sp_disk_yellow", "yellow disk" },
+ { "sp_terminal", "terminal" },
+ { "sp_disk_red", "red disk" }, /* 230 */
+ { "sp_port", "port (vertical)" },
+ { "sp_port", "port (horizontal)" },
+ { "sp_port", "port (all directions)" },
+ { "sp_electron", "electron" },
+ { "sp_buggy_base", "buggy base" },
+ { "wall", "chip (left half)" },
+ { "wall", "chip (right half)" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" }, /* 240 */
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "hardware" },
+ { "wall", "chip (upper half)" },
+ { "wall", "chip (lower half)" },
+ { "gate", "gray door (EM style, red key)" }, /* 250 */
+ { "gate", "gray door (EM style, yellow key)"},
+ { "gate", "gray door (EM style, green key)"},
+ { "gate", "gray door (EM style, blue key)"},
+ { NULL, "unknown" },
+ { NULL, "unknown" },
/* 256 */
- "pearl", /* (256) */
- "crystal",
- "wall with pearl",
- "wall with crystal",
- "white door", /* 260 */
- "gray door (opened by white key)",
- "white key",
- "shield (passive)",
- "extra time",
- "switch gate (open)",
- "switch gate (closed)",
- "switch for switch gate",
- "switch for switch gate",
- "-",
- "-", /* 270 */
- "red conveyor belt (left)",
- "red conveyor belt (middle)",
- "red conveyor belt (right)",
- "switch for red conveyor belt (left)",
- "switch for red conveyor belt (middle)",
- "switch for red conveyor belt (right)",
- "yellow conveyor belt (left)",
- "yellow conveyor belt (middle)",
- "yellow conveyor belt (right)",
- "switch for yellow conveyor belt (left)", /* 280 */
- "switch for yellow conveyor belt (middle)",
- "switch for yellow conveyor belt (right)",
- "green conveyor belt (left)",
- "green conveyor belt (middle)",
- "green conveyor belt (right)",
- "switch for green conveyor belt (left)",
- "switch for green conveyor belt (middle)",
- "switch for green conveyor belt (right)",
- "blue conveyor belt (left)",
- "blue conveyor belt (middle)", /* 290 */
- "blue conveyor belt (right)",
- "switch for blue conveyor belt (left)",
- "switch for blue conveyor belt (middle)",
- "switch for blue conveyor belt (right)",
- "land mine",
- "mail envelope",
- "light switch (off)",
- "light switch (on)",
- "sign (exclamation)",
- "sign (radio activity)", /* 300 */
- "sign (stop)",
- "sign (wheel chair)",
- "sign (parking)",
- "sign (one way)",
- "sign (heart)",
- "sign (triangle)",
- "sign (round)",
- "sign (exit)",
- "sign (yin yang)",
- "sign (other)", /* 310 */
- "mole (starts moving left)",
- "mole (starts moving right)",
- "mole (starts moving up)",
- "mole (starts moving down)",
- "steel wall (slanted)",
- "invisible sand",
- "dx unknown 15",
- "dx unknown 42",
- "-",
- "-", /* 320 */
- "shield (active, kills enemies)",
- "time gate (open)",
- "time gate (closed)",
- "switch for time gate",
- "switch for time gate",
- "balloon",
- "send balloon to the left",
- "send balloon to the right",
- "send balloon up",
- "send balloon down", /* 330 */
- "send balloon in any direction",
- "steel wall",
- "steel wall",
- "steel wall",
- "steel wall",
- "normal wall",
- "normal wall",
- "normal wall",
- "normal wall",
- "normal wall", /* 340 */
- "normal wall",
- "normal wall",
- "normal wall",
- "tube (all directions)",
- "tube (vertical)",
- "tube (horizontal)",
- "tube (vertical & left)",
- "tube (vertical & right)",
- "tube (horizontal & up)",
- "tube (horizontal & down)", /* 350 */
- "tube (left & up)",
- "tube (left & down)",
- "tube (right & up)",
- "tube (right & down)",
- "spring",
- "trap",
- "stable bomb (DX style)",
- "-"
+ { "pearl", "pearl" }, /* (256) */
+ { "crystal", "crystal" },
+ { "wall", "wall with pearl" },
+ { "wall", "wall with crystal" },
+ { "gate", "white door" }, /* 260 */
+ { "gate", "gray door (opened by white key)"},
+ { "key", "white key" },
+ { "shield_passive", "shield (passive)" },
+ { "extra_time", "extra time" },
+ { "switchgate", "switch gate (open)" },
+ { "switchgate", "switch gate (closed)" },
+ { "switchgate_switch", "switch for switch gate" },
+ { "switchgate_switch", "switch for switch gate" },
+ { NULL, "-" },
+ { NULL, "-" }, /* 270 */
+ { "conveyor_belt", "red conveyor belt (left)" },
+ { "conveyor_belt", "red conveyor belt (middle)" },
+ { "conveyor_belt", "red conveyor belt (right)" },
+ { "conveyor_belt_switch", "switch for red conveyor belt (left)"},
+ { "conveyor_belt_switch", "switch for red conveyor belt (middle)"},
+ { "conveyor_belt_switch", "switch for red conveyor belt (right)"},
+ { "conveyor_belt", "yellow conveyor belt (left)" },
+ { "conveyor_belt", "yellow conveyor belt (middle)" },
+ { "conveyor_belt", "yellow conveyor belt (right)" },
+ { "conveyor_belt_switch", "switch for yellow conveyor belt (left)"},
+ { "conveyor_belt_switch", "switch for yellow conveyor belt (middle)"},
+ { "conveyor_belt_switch", "switch for yellow conveyor belt (right)"},
+ { "conveyor_belt", "green conveyor belt (left)" },
+ { "conveyor_belt", "green conveyor belt (middle)" },
+ { "conveyor_belt", "green conveyor belt (right)" },
+ { "conveyor_belt_switch", "switch for green conveyor belt (left)"},
+ { "conveyor_belt_switch", "switch for green conveyor belt (middle)"},
+ { "conveyor_belt_switch", "switch for green conveyor belt (right)"},
+ { "conveyor_belt", "blue conveyor belt (left)" },
+ { "conveyor_belt", "blue conveyor belt (middle)" },
+ { "conveyor_belt", "blue conveyor belt (right)" },
+ { "conveyor_belt_switch", "switch for blue conveyor belt (left)"},
+ { "conveyor_belt_switch", "switch for blue conveyor belt (middle)"},
+ { "conveyor_belt_switch", "switch for blue conveyor belt (right)"},
+ { "sand", "land mine" },
+ { "envelope", "mail envelope" },
+ { "light_switch", "light switch (off)" },
+ { "light_switch", "light switch (on)" },
+ { "wall", "sign (exclamation)" },
+ { "wall", "sign (radio activity)" }, /* 300 */
+ { "wall", "sign (stop)" },
+ { "wall", "sign (wheel chair)" },
+ { "wall", "sign (parking)" },
+ { "wall", "sign (one way)" },
+ { "wall", "sign (heart)" },
+ { "wall", "sign (triangle)" },
+ { "wall", "sign (round)" },
+ { "wall", "sign (exit)" },
+ { "wall", "sign (yin yang)" },
+ { "wall", "sign (other)" }, /* 310 */
+ { "mole", "mole (starts moving left)" },
+ { "mole", "mole (starts moving right)" },
+ { "mole", "mole (starts moving up)" },
+ { "mole", "mole (starts moving down)" },
+ { "wall", "steel wall (slanted)" },
+ { "sand", "invisible sand" },
+ { NULL, "dx unknown 15" },
+ { NULL, "dx unknown 42" },
+ { NULL, "-" },
+ { NULL, "-" }, /* 320 */
+ { "shield_active", "shield (active, kills enemies)"},
+ { "timegate", "time gate (open)" },
+ { "timegate", "time gate (closed)" },
+ { "timegate_wheel", "switch for time gate" },
+ { "timegate_wheel", "switch for time gate" },
+ { "balloon", "balloon" },
+ { "wall", "send balloon to the left" },
+ { "wall", "send balloon to the right" },
+ { "balloon_switch", "send balloon up" },
+ { "balloon_switch", "send balloon down" }, /* 330 */
+ { "balloon_switch", "send balloon in any direction" },
+ { "wall", "steel wall" },
+ { "wall", "steel wall" },
+ { "wall", "steel wall" },
+ { "wall", "steel wall" },
+ { "wall", "normal wall" },
+ { "wall", "normal wall" },
+ { "wall", "normal wall" },
+ { "wall", "normal wall" },
+ { "wall", "normal wall" }, /* 340 */
+ { "wall", "normal wall" },
+ { "wall", "normal wall" },
+ { "wall", "normal wall" },
+ { "tube", "tube (all directions)" },
+ { "tube", "tube (vertical)" },
+ { "tube", "tube (horizontal)" },
+ { "tube", "tube (vertical & left)" },
+ { "tube", "tube (vertical & right)" },
+ { "tube", "tube (horizontal & up)" },
+ { "tube", "tube (horizontal & down)" }, /* 350 */
+ { "tube", "tube (left & up)" },
+ { "tube", "tube (left & down)" },
+ { "tube", "tube (right & up)" },
+ { "tube", "tube (right & down)" },
+ { "spring", "spring" },
+ { "trap", "trap" },
+ { "dx_bomb", "stable bomb (DX style)" },
+ { NULL, "-" }
/*
"-------------------------------",
*/
};
-int num_element_info = sizeof(element_info)/sizeof(char *);
/* ========================================================================= */
EventLoop();
CloseAllAndExit(0);
- exit(0); /* to keep compilers happy */
+
+ return 0; /* to keep compilers happy */
}
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#define WIN_XSIZE 672
#define WIN_YSIZE 560
-#if !defined(PLATFORM_MSDOS)
-#define WIN_XPOS 0
-#define WIN_YPOS 0
-#else
-#define WIN_XPOS ((XRES - WIN_XSIZE) / 2)
-#define WIN_YPOS ((YRES - WIN_YSIZE) / 2)
-#endif
-
#define SCR_FIELDX 17
#define SCR_FIELDY 17
#define MAX_BUF_XSIZE (SCR_FIELDX + 2)
#define MAX_LEV_FIELDX 128
#define MAX_LEV_FIELDY 128
-#define MAX_PLAYERS 4
-
#define SCREENX(a) ((a) - scroll_x)
#define SCREENY(a) ((a) - scroll_y)
#define LEVELX(a) ((a) + scroll_x)
#define EP_BIT_BELT (1 << 0)
#define EP_BIT_BELT_SWITCH (1 << 1)
#define EP_BIT_TUBE (1 << 2)
-#define EP_BIT_SLIPPERY_GEMS (1 << 3)
+#define EP_BIT_EM_SLIPPERY_WALL (1 << 3)
#define IS_AMOEBALIVE(e) (Elementeigenschaften1[e] & EP_BIT_AMOEBALIVE)
#define IS_AMOEBOID(e) (Elementeigenschaften1[e] & EP_BIT_AMOEBOID)
#define IS_BELT(e) (Elementeigenschaften2[e] & EP_BIT_BELT)
#define IS_BELT_SWITCH(e) (Elementeigenschaften2[e] & EP_BIT_BELT_SWITCH)
#define IS_TUBE(e) (Elementeigenschaften2[e] & EP_BIT_TUBE)
-#define IS_SLIPPERY_GEMS(e) (Elementeigenschaften2[e] & EP_BIT_SLIPPERY_GEMS)
+#define IS_EM_SLIPPERY_WALL(e) (Elementeigenschaften2[e] & EP_BIT_EM_SLIPPERY_WALL)
#define IS_PLAYER(x,y) (ELEM_IS_PLAYER(StorePlayer[x][y]))
#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 &&!(x).pausing)
+#define TAPE_IS_STOPPED(x) (!(x).recording && !(x).playing)
#define PLAYERINFO(x,y) (&stored_player[StorePlayer[x][y]-EL_SPIELER1])
#define SHIELD_ON(p) ((p)->shield_passive_time_left > 0)
#define NUM_BITMAPS 12
/* boundaries of arrays etc. */
-#define MAX_PLAYER_NAME_LEN 10
#define MAX_LEVEL_NAME_LEN 32
#define MAX_LEVEL_AUTHOR_LEN 32
#define MAX_TAPELEN (1000 * 50) /* max. time * framerate */
int Score;
};
-struct SetupJoystickInfo
-{
- char *device_name;
- int xleft, xmiddle, xright;
- int yupper, ymiddle, ylower;
- int snap;
- int bomb;
-};
-
-struct SetupKeyboardInfo
-{
- Key left;
- Key right;
- Key up;
- Key down;
- Key snap;
- Key bomb;
-};
-
-struct SetupInputInfo
-{
- boolean use_joystick;
- struct SetupJoystickInfo joy;
- struct SetupKeyboardInfo key;
-};
-
-struct SetupInfo
-{
- char *player_name;
-
- boolean sound;
- boolean sound_loops;
- boolean sound_music;
- boolean sound_simple;
- boolean toons;
- boolean double_buffering;
- boolean direct_draw; /* !double_buffering (redundant!) */
- boolean scroll_delay;
- boolean soft_scrolling;
- boolean fading;
- boolean autorecord;
- boolean quick_doors;
- boolean team_mode;
- boolean handicap;
- boolean time_limit;
- boolean fullscreen;
-
- struct SetupInputInfo input[MAX_PLAYERS];
-};
-
struct PlayerInfo
{
boolean present; /* player present in level playfield */
byte programmed_action; /* action forced by game itself (like moving
through doors); overrides other actions */
- int joystick_fd; /* file descriptor of player's joystick */
-
int jx,jy, last_jx,last_jy;
int MovDir, MovPos, GfxPos;
int Frame;
boolean LevelSolved, GameOver;
boolean snapped;
- unsigned long move_delay;
- int move_delay_value;
-
int last_move_dir;
int is_moving;
+ unsigned long move_delay;
+ int move_delay_value;
+
unsigned long push_delay;
unsigned long push_delay_value;
struct LevelInfo
{
- int file_version; /* version of file the level was stored with */
- int game_version; /* version of game engine to play this level */
- boolean encoding_16bit_field; /* level contains 16-bit elements */
+ int file_version; /* file format version the level is stored with */
+ int game_version; /* game release version the level was created with */
+
+ 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 time_timegate;
boolean double_speed;
boolean gravity;
+ boolean em_slippery_gems; /* EM style "gems slip from wall" behaviour */
};
struct TapeInfo
{
- int file_version; /* version of file this level tape was stored with */
- int game_version; /* version of game engine to play this tape´s level */
- int version;
+ 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 */
+
int level_nr;
unsigned long random_seed;
unsigned long date;
boolean pause_before_death;
boolean recording, playing, pausing;
boolean fast_forward;
+ boolean index_search;
+ boolean quick_resume;
+ boolean single_step;
boolean changed;
boolean player_participates[MAX_PLAYERS];
int num_participating_players;
+
struct
{
byte action[MAX_PLAYERS];
struct GameInfo
{
- int version;
+ /* constant within running game */
+ int engine_version;
int emulation;
+ int initial_move_delay;
+ int initial_move_delay_value;
+
+ /* variable within running game */
int yam_content_nr;
boolean magic_wall_active;
int magic_wall_time_left;
int fps_slowdown_factor;
};
+struct ElementInfo
+{
+ char *sound_class_name;
+ char *editor_description;
+};
+
extern GC tile_clip_gc;
extern Bitmap *pix[];
extern Pixmap tile_clipmask[];
extern DrawBuffer *fieldbuffer;
extern DrawBuffer *drawto_field;
-extern int joystick_device;
-extern char *joystick_device_name[];
-
extern int game_status;
extern boolean level_editor_test_game;
extern boolean network_playing;
extern int key_joystick_mapping;
-extern int global_joystick_status, joystick_status;
extern boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
extern int redraw_x1, redraw_y1;
extern unsigned long Elementeigenschaften1[MAX_ELEMENTS];
extern unsigned long Elementeigenschaften2[MAX_ELEMENTS];
-extern int level_nr;
extern int lev_fieldx,lev_fieldy, scroll_x,scroll_y;
extern int FX,FY, ScrollStepSize;
extern struct PlayerInfo stored_player[], *local_player;
extern struct HiScore highscore[];
extern struct TapeInfo tape;
-extern struct JoystickInfo joystick[];
-extern struct SetupInfo setup;
extern struct GameInfo game;
extern struct GlobalInfo global;
-
-extern char *sound_name[];
-extern int background_loop[];
-extern int num_bg_loops;
-extern char *element_info[];
-extern int num_element_info;
+extern struct ElementInfo element_info[];
+extern struct SoundEffectInfo sound_effects[];
/* often used screen positions */
#define SX 8
#define EL_TRAP_INACTIVE 356
#define EL_DX_SUPABOMB 357
+#define NUM_LEVEL_ELEMENTS 358
+
+
/* "real" (and therefore drawable) runtime elements */
#define EL_FIRST_RUNTIME_EL 500
#define NUM_SOUNDS 55
-/* 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
-#define DEFAULT_KEY_SNAP KSYM_Shift_L
-#define DEFAULT_KEY_BOMB KSYM_Shift_R
-#define DEFAULT_KEY_OKAY KSYM_Return
-#define DEFAULT_KEY_CANCEL KSYM_Escape
-
-/* directions for moving */
-#define MV_NO_MOVING 0
-#define MV_LEFT (1 << 0)
-#define MV_RIGHT (1 << 1)
-#define MV_UP (1 << 2)
-#define MV_DOWN (1 << 3)
+
+/* values for sound effects */
+#define SND_BD_EMPTY_SPACE_DIGGING 0
+#define SND_BD_SAND_DIGGING 1
+#define SND_BD_DIAMOND_COLLECTING 2
+#define SND_BD_DIAMOND_IMPACT 3
+#define SND_BD_ROCK_PUSHING 4
+#define SND_BD_ROCK_IMPACT 5
+#define SND_BD_MAGIC_WALL_ACTIVATING 6
+#define SND_BD_MAGIC_WALL_CHANGING 7
+#define SND_BD_MAGIC_WALL_RUNNING 8
+#define SND_BD_AMOEBA_WAITING 9
+#define SND_BD_AMOEBA_CREATING 10
+#define SND_BD_AMOEBA_TURNING_TO_GEM 11
+#define SND_BD_AMOEBA_TURNING_TO_ROCK 12
+#define SND_BD_BUTTERFLY_MOVING 13
+#define SND_BD_BUTTERFLY_WAITING 14
+#define SND_BD_FIREFLY_MOVING 15
+#define SND_BD_FIREFLY_WAITING 16
+#define SND_BD_EXIT_ENTERING 17
+#define SND_SP_EMPTY_SPACE_DIGGING 18
+#define SND_SP_BASE_DIGGING 19
+#define SND_SP_BUGGY_BASE_DIGGING 20
+#define SND_SP_BUGGY_BASE_ACTIVATING 21
+#define SND_SP_INFOTRON_COLLECTING 22
+#define SND_SP_INFOTRON_IMPACT 23
+#define SND_SP_ZONK_PUSHING 24
+#define SND_SP_ZONK_IMPACT 25
+#define SND_SP_DISK_RED_COLLECTING 26
+#define SND_SP_DISK_ORANGE_PUSHING 27
+#define SND_SP_DISK_YELLOW_PUSHING 28
+#define SND_SP_PORT_PASSING 29
+#define SND_SP_EXIT_ENTERING 30
+#define SND_SP_ELEMENT_EXPLODING 31
+#define SND_SP_SNIKSNAK_MOVING 32
+#define SND_SP_SNIKSNAK_WAITING 33
+#define SND_SP_ELECTRON_MOVING 34
+#define SND_SP_ELECTRON_WAITING 35
+#define SND_SP_TERMINAL_ACTIVATING 36
+#define SND_SOKOBAN_OBJECT_PUSHING 37
+#define SND_SOKOBAN_FIELD_FILLING 38
+#define SND_SOKOBAN_FIELD_CLEARING 39
+#define SND_SOKOBAN_GAME_SOLVING 40
+#define SND_EMPTY_SPACE_DIGGING 41
+#define SND_SAND_DIGGING 42
+#define SND_EMERALD_COLLECTING 43
+#define SND_EMERALD_IMPACT 44
+#define SND_DIAMOND_COLLECTING 45
+#define SND_DIAMOND_IMPACT 46
+#define SND_DIAMOND_BREAKING 47
+#define SND_ROCK_PUSHING 48
+#define SND_ROCK_IMPACT 49
+#define SND_BOMB_PUSHING 50
+#define SND_NUT_PUSHING 51
+#define SND_NUT_CRACKING 52
+#define SND_NUT_IMPACT 53
+#define SND_DYNAMITE_COLLECTING 54
+#define SND_DYNAMITE_PLACING 55
+#define SND_DYNAMITE_BURNING 56
+#define SND_KEY_COLLECTING 57
+#define SND_GATE_PASSING 58
+#define SND_BUG_MOVING 59
+#define SND_BUG_WAITING 60
+#define SND_SPACESHIP_MOVING 61
+#define SND_SPACESHIP_WAITING 62
+#define SND_YAMYAM_MOVING 63
+#define SND_YAMYAM_WAITING 64
+#define SND_YAMYAM_EATING_DIAMOND 65
+#define SND_ROBOT_STEPPING 66
+#define SND_ROBOT_WAITING 67
+#define SND_ROBOT_WHEEL_ACTIVATING 68
+#define SND_ROBOT_WHEEL_RUNNING 69
+#define SND_MAGIC_WALL_ACTIVATING 70
+#define SND_MAGIC_WALL_CHANGING 71
+#define SND_MAGIC_WALL_RUNNING 72
+#define SND_AMOEBA_WAITING 73
+#define SND_AMOEBA_CREATING 74
+#define SND_AMOEBA_DROPPING 75
+#define SND_ACID_SPLASHING 76
+#define SND_QUICKSAND_FILLING 77
+#define SND_QUICKSAND_SLIPPING_THROUGH 78
+#define SND_QUICKSAND_EMPTYING 79
+#define SND_EXIT_OPENING 80
+#define SND_EXIT_ENTERING 81
+#define SND_BALLOON_MOVING 82
+#define SND_BALLOON_WAITING 83
+#define SND_BALLOON_PUSHING 84
+#define SND_BALLOON_SWITCH_ACTIVATING 85
+#define SND_SPRING_MOVING 86
+#define SND_SPRING_PUSHING 87
+#define SND_SPRING_IMPACT 88
+#define SND_WALL_GROWING 89
+#define SND_PEARL_COLLECTING 90
+#define SND_PEARL_BREAKING 91
+#define SND_PEARL_IMPACT 92
+#define SND_CRYSTAL_COLLECTING 93
+#define SND_CRYSTAL_IMPACT 94
+#define SND_ENVELOPE_COLLECTING 95
+#define SND_SAND_INVISIBLE_DIGGING 96
+#define SND_SHIELD_PASSIVE_COLLECTING 97
+#define SND_SHIELD_PASSIVE_ACTIVATED 98
+#define SND_SHIELD_ACTIVE_COLLECTING 99
+#define SND_SHIELD_ACTIVE_ACTIVATED 100
+#define SND_EXTRA_TIME_COLLECTING 101
+#define SND_MOLE_MOVING 102
+#define SND_MOLE_WAITING 103
+#define SND_MOLE_EATING_AMOEBA 104
+#define SND_SWITCHGATE_SWITCH_ACTIVATING 105
+#define SND_SWITCHGATE_OPENING 106
+#define SND_SWITCHGATE_CLOSING 107
+#define SND_SWITCHGATE_PASSING 108
+#define SND_TIMEGATE_WHEEL_ACTIVATING 109
+#define SND_TIMEGATE_WHEEL_RUNNING 110
+#define SND_TIMEGATE_OPENING 111
+#define SND_TIMEGATE_CLOSING 112
+#define SND_TIMEGATE_PASSING 113
+#define SND_CONVEYOR_BELT_SWITCH_ACTIVATING 114
+#define SND_CONVEYOR_BELT_RUNNING 115
+#define SND_LIGHT_SWITCH_ACTIVATING 116
+#define SND_LIGHT_SWITCH_DEACTIVATING 117
+#define SND_DX_BOMB_PUSHING 118
+#define SND_TRAP_INACTIVE_DIGGING 119
+#define SND_TRAP_ACTIVATING 120
+#define SND_TUBE_PASSING 121
+#define SND_AMOEBA_TURNING_TO_GEM 122
+#define SND_AMOEBA_TURNING_TO_ROCK 123
+#define SND_SPEED_PILL_COLLECTING 124
+#define SND_DYNABOMB_NR_COLLECTING 125
+#define SND_DYNABOMB_SZ_COLLECTING 126
+#define SND_DYNABOMB_XL_COLLECTING 127
+#define SND_DYNABOMB_PLACING 128
+#define SND_DYNABOMB_BURNING 129
+#define SND_SATELLITE_MOVING 130
+#define SND_SATELLITE_WAITING 131
+#define SND_SATELLITE_PUSHING 132
+#define SND_LAMP_ACTIVATING 133
+#define SND_LAMP_DEACTIVATING 134
+#define SND_TIME_ORB_FULL_COLLECTING 135
+#define SND_TIME_ORB_FULL_IMPACT 136
+#define SND_TIME_ORB_EMPTY_PUSHING 137
+#define SND_TIME_ORB_EMPTY_IMPACT 138
+#define SND_GAMEOFLIFE_WAITING 139
+#define SND_GAMEOFLIFE_CREATING 140
+#define SND_BIOMAZE_WAITING 141
+#define SND_BIOMAZE_CREATING 142
+#define SND_PACMAN_MOVING 143
+#define SND_PACMAN_WAITING 144
+#define SND_PACMAN_EATING_AMOEBA 145
+#define SND_DARK_YAMYAM_MOVING 146
+#define SND_DARK_YAMYAM_WAITING 147
+#define SND_DARK_YAMYAM_EATING_ANY 148
+#define SND_PENGUIN_MOVING 149
+#define SND_PENGUIN_WAITING 150
+#define SND_PENGUIN_ENTERING_EXIT 151
+#define SND_PIG_MOVING 152
+#define SND_PIG_WAITING 153
+#define SND_PIG_EATING_GEM 154
+#define SND_DRAGON_MOVING 155
+#define SND_DRAGON_WAITING 156
+#define SND_DRAGON_ATTACKING 157
+#define SND_PLAYER_DYING 158
+#define SND_ELEMENT_EXPLODING 159
+#define SND_GAME_STARTING 160
+#define SND_GAME_RUNNING_OUT_OF_TIME 161
+#define SND_GAME_LEVELTIME_BONUS 162
+#define SND_GAME_LOSING 163
+#define SND_GAME_WINNING 164
+#define SND_MENU_DOOR_OPENING 165
+#define SND_MENU_DOOR_CLOSING 166
+#define SND_MENU_HALL_OF_FAME 167
+#define SND_MENU_INFO_SCREEN 168
+
+#define NUM_SOUND_EFFECTS 169
+
/* values for game_status */
#define EXITGAME 0
#define TYPENAME 6
#define HALLOFFAME 7
#define SETUP 8
-#define SETUPINPUT 9
-#define CALIBRATION 10
#define PROGRAM_VERSION_MAJOR 2
-#define PROGRAM_VERSION_MINOR 0
-#define PROGRAM_VERSION_PATCH 1
-#define PROGRAM_VERSION_STRING "2.0.1"
+#define PROGRAM_VERSION_MINOR 1
+#define PROGRAM_VERSION_PATCH 0
+#define PROGRAM_VERSION_STRING "2.1.0"
#define PROGRAM_TITLE_STRING "Rocks'n'Diamonds"
#define PROGRAM_AUTHOR_STRING "Holger Schemel"
-#define PROGRAM_RIGHTS_STRING "Copyright ^1995-2001 by"
+#define PROGRAM_RIGHTS_STRING "Copyright ^1995-2002 by"
#define PROGRAM_DOS_PORT_STRING "DOS port done by Guido Schulz"
#define PROGRAM_IDENT_STRING PROGRAM_VERSION_STRING " " TARGET_STRING
#define WINDOW_TITLE_STRING PROGRAM_TITLE_STRING " " PROGRAM_IDENT_STRING
#define WINDOW_SUBTITLE_STRING PROGRAM_RIGHTS_STRING " " PROGRAM_AUTHOR_STRING
#define ICON_TITLE_STRING PROGRAM_TITLE_STRING
#define UNIX_USERDATA_DIRECTORY ".rocksndiamonds"
+#define COOKIE_PREFIX "ROCKSNDIAMONDS"
+#define FILENAME_PREFIX "Rocks"
#define X11_ICON_FILENAME "rocks_icon.xbm"
#define X11_ICONMASK_FILENAME "rocks_iconmask.xbm"
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
* network.c *
***********************************************************/
-#include "libgame/libgame.h"
+#include "libgame/platform.h"
#if defined(PLATFORM_UNIX)
#include <arpa/inet.h>
#include <netdb.h>
-#if 0
#include "libgame/libgame.h"
-#endif
#include "netserv.h"
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
* network.c *
***********************************************************/
-#include "libgame/libgame.h"
+#include "libgame/platform.h"
#if defined(PLATFORM_UNIX)
#include <arpa/inet.h>
#include <netdb.h>
-#if 0
#include "libgame/libgame.h"
-#endif
#include "network.h"
#include "netserv.h"
static void Handle_OP_START_PLAYING()
{
- struct LevelDirInfo *new_leveldir;
+ LevelDirTree *new_leveldir;
int new_level_nr;
int dummy; /* !!! HAS NO MEANING ANYMORE !!! */
unsigned long new_random_seed;
(buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]);
new_leveldir_filename = (char *)&buffer[10];
- new_leveldir = getLevelDirInfoFromFilename(new_leveldir_filename);
+ new_leveldir = getTreeInfoFromFilename(leveldir_first,new_leveldir_filename);
if (new_leveldir == NULL)
{
Error(ERR_WARN, "no such level directory: '%s'", new_leveldir_filename);
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "editor.h"
#include "files.h"
#include "tape.h"
-#include "joystick.h"
#include "cartoons.h"
#include "network.h"
#include "init.h"
-/* for DrawSetupScreen(), HandleSetupScreen() */
-#define SETUP_SCREEN_POS_START 2
-#define SETUP_SCREEN_POS_END (SCR_FIELDY - 1)
-#define SETUP_SCREEN_POS_EMPTY1 (SETUP_SCREEN_POS_END - 2)
-#define SETUP_SCREEN_POS_EMPTY2 (SETUP_SCREEN_POS_END - 2)
-
-/* for HandleSetupInputScreen() */
-#define SETUPINPUT_SCREEN_POS_START 2
-#define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 2)
+/* screens in the setup menu */
+#define SETUP_MODE_MAIN 0
+#define SETUP_MODE_GAME 1
+#define SETUP_MODE_INPUT 2
+#define SETUP_MODE_SHORTCUT 3
+#define SETUP_MODE_GRAPHICS 4
+#define SETUP_MODE_SOUND 5
+#define SETUP_MODE_ARTWORK 6
+#define SETUP_MODE_CHOOSE_GRAPHICS 7
+#define SETUP_MODE_CHOOSE_SOUNDS 8
+#define SETUP_MODE_CHOOSE_MUSIC 9
+
+#define MAX_SETUP_MODES 10
+
+/* 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 HandleChooseLevel() */
-#define MAX_LEVEL_SERIES_ON_SCREEN (SCR_FIELDY - 2)
+/* for various menu stuff */
+#define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - 2)
+#define MENU_SCREEN_START_YPOS 2
+#define MENU_SCREEN_VALUE_XPOS 14
/* buttons and scrollbars identifiers */
#define SCREEN_CTRL_ID_SCROLL_UP 0
#define NUM_SCREEN_SCROLLBARS 1
#define NUM_SCREEN_GADGETS 3
-/* forward declaration for internal use */
+/* 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 execSetupArtwork(void);
+static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
+static int setup_mode = SETUP_MODE_MAIN;
+
+static void drawCursorExt(int pos, int color, int graphic)
+{
+ static int cursor_array[SCR_FIELDY];
+
+ if (graphic)
+ cursor_array[pos] = graphic;
+
+ graphic = cursor_array[pos];
+
+ if (color == FC_RED)
+ graphic = (graphic == GFX_ARROW_BLUE_LEFT ? GFX_ARROW_RED_LEFT :
+ graphic == GFX_ARROW_BLUE_RIGHT ? GFX_ARROW_RED_RIGHT :
+ GFX_KUGEL_ROT);
+
+ DrawGraphic(0, MENU_SCREEN_START_YPOS + pos, graphic);
+}
+
+static void initCursor(int pos, int graphic)
+{
+ drawCursorExt(pos, FC_BLUE, graphic);
+}
+
+static void drawCursor(int pos, int color)
+{
+ drawCursorExt(pos, color, 0);
+}
void DrawHeadline()
{
void DrawMainMenu()
{
- static struct LevelDirInfo *leveldir_last_valid = NULL;
+ static LevelDirTree *leveldir_last_valid = NULL;
int i;
char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:");
UnmapAllGadgets();
FadeSounds();
KeyboardAutoRepeatOn();
+ ActivateJoystick();
+ SetDrawDeactivationMask(REDRAW_NONE);
+ audio.sound_deactivated = FALSE;
/* needed if last screen was the playing screen, invoked from level editor */
if (level_editor_test_game)
/* needed if last screen was the setup screen and fullscreen state changed */
ToggleFullscreenIfNeeded();
+ /* needed if last screen (level choice) changed graphics, sounds or music */
+ ReloadCustomArtwork();
+
#ifdef TARGET_SDL
SetDrawtoField(DRAW_BACKBUFFER);
#endif
/* leveldir_current may be invalid (level group, parent link) */
if (!validLevelSeries(leveldir_current))
- leveldir_current = getFirstValidLevelSeries(leveldir_last_valid);
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
/* store valid level series information */
leveldir_last_valid = leveldir_current;
DrawTextF(15*32 + 6, 3*32 + 9 + 7, FC_RED, "ONLY");
}
- for(i=2; i<10; i++)
- DrawGraphic(0, i, GFX_KUGEL_BLAU);
+ for(i=0; i<8; i++)
+ initCursor(i, (i == 1 || i == 6 ? GFX_ARROW_BLUE_RIGHT : GFX_KUGEL_BLAU));
+
DrawGraphic(10, 3, GFX_ARROW_BLUE_LEFT);
DrawGraphic(14, 3, GFX_ARROW_BLUE_RIGHT);
#if 0
ClearEventQueue();
#endif
-
}
static void gotoTopLevelDir()
/* 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 = numLevelDirInfoInGroup(leveldir_current);
- int leveldir_pos = posLevelDirInfo(leveldir_current);
+ int num_leveldirs = numTreeInfoInGroup(leveldir_current);
+ int leveldir_pos = posTreeInfo(leveldir_current);
int num_page_entries;
int cl_first, cl_cursor;
- if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN)
+ if (num_leveldirs <= MAX_MENU_ENTRIES_ON_SCREEN)
num_page_entries = num_leveldirs;
else
- num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
- cl_cursor = leveldir_pos - cl_first + 3;
+ 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;
void HandleMainMenu(int mx, int my, int dx, int dy, int button)
{
- static int choice = 3;
- static int redraw = TRUE;
- int x = (mx + 32 - SX) / 32, y = (my + 32 - SY) / 32;
-
- if (redraw || button == MB_MENU_INITIALIZE)
- {
- DrawGraphic(0, choice - 1, GFX_KUGEL_ROT);
- redraw = FALSE;
- }
+ static int choice = 0;
+ int x = 0;
+ int y = choice;
if (button == MB_MENU_INITIALIZE)
+ {
+ drawCursor(choice, FC_RED);
return;
+ }
- if (dx || dy)
+ if (mx || my) /* mouse input */
{
- if (dx && choice == 4)
- {
- x = (dx < 0 ? 11 : 15);
- y = 4;
- }
- else if (dy)
- {
- x = 1;
- y = choice + dy;
- }
- else
- x = y = 0;
-
- if (y < 3)
- y = 3;
- else if (y > 10)
- y = 10;
+ x = (mx - SX) / 32;
+ y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
}
-
- if (!mx && !my && !dx && !dy)
+ else if (dx || dy) /* keyboard input */
{
- x = 1;
- y = choice;
+ if (dx && choice == 1)
+ x = (dx < 0 ? 10 : 14);
+ else if (dy)
+ y = choice + dy;
}
- if (y == 4 && ((x == 11 && level_nr > leveldir_current->first_level) ||
- (x == 15 && level_nr < leveldir_current->last_level)) &&
+ if (y == 1 && ((x == 10 && level_nr > leveldir_current->first_level) ||
+ (x == 14 && level_nr < leveldir_current->last_level)) &&
button)
{
static unsigned long level_delay = 0;
int new_level_nr, old_level_nr = level_nr;
int font_color = (leveldir_current->readonly ? FC_RED : FC_YELLOW);
- new_level_nr = level_nr + (x == 11 ? -step : +step);
+ new_level_nr = level_nr + (x == 10 ? -step : +step);
if (new_level_nr < leveldir_current->first_level)
new_level_nr = leveldir_current->first_level;
if (new_level_nr > leveldir_current->last_level)
SyncDisplay();
DelayReached(&level_delay, 0); /* reset delay counter */
}
- else if (x == 1 && y >= 3 && y <= 10)
+ else if (x == 0 && y >= 0 && y <= 7)
{
if (button)
{
if (y != choice)
{
- DrawGraphic(0, y - 1, GFX_KUGEL_ROT);
- DrawGraphic(0, choice - 1, GFX_KUGEL_BLAU);
+ drawCursor(y, FC_RED);
+ drawCursor(choice, FC_BLUE);
choice = y;
}
}
else
{
- if (y == 3)
+ if (y == 0)
{
game_status = TYPENAME;
HandleTypeName(strlen(setup.player_name), 0);
}
- else if (y == 4)
+ else if (y == 1)
{
if (leveldir_first)
{
DrawChooseLevel();
}
}
- else if (y == 5)
+ else if (y == 2)
{
game_status = HALLOFFAME;
DrawHallOfFame(-1);
}
- else if (y == 6)
+ else if (y == 3)
{
if (leveldir_current->readonly &&
strcmp(setup.player_name, "Artsoft") != 0)
game_status = LEVELED;
DrawLevelEd();
}
- else if (y == 7)
+ else if (y == 4)
{
game_status = HELPSCREEN;
DrawHelpScreen();
}
- else if (y == 8)
+ else if (y == 5)
{
if (setup.autorecord)
TapeStartRecording();
InitGame();
}
}
- else if (y == 9)
+ else if (y == 6)
{
game_status = SETUP;
+ setup_mode = SETUP_MODE_MAIN;
DrawSetupScreen();
}
- else if (y == 10)
+ else if (y == 7)
{
SaveLevelSetup_LastSeries();
SaveLevelSetup_SeriesInfo();
if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
game_status = EXITGAME;
}
-
- redraw = TRUE;
}
}
+
BackToFront();
out:
}
}
+
#define MAX_HELPSCREEN_ELS 10
#define HA_NEXT -999
#define HA_END -1000
FadeToFront();
InitAnimation();
- PlaySoundLoop(SND_RHYTHMLOOP);
+ PlaySoundLoop(SND_MENU_INFO_SCREEN);
}
void HandleHelpScreen(int button)
for(i=0;i<MAX_HELPSCREEN_ELS;i++)
helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
helpscreen_state++;
- DrawHelpScreenElText(helpscreen_state*MAX_HELPSCREEN_ELS);
- DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
+ DrawHelpScreenElText(helpscreen_state * MAX_HELPSCREEN_ELS);
+ DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
}
else if (helpscreen_state <
num_helpscreen_els_pages + num_helpscreen_music - 1)
}
else
{
- if (DelayReached(&hs_delay,GAME_FRAME_DELAY * 2))
+ if (DelayReached(&hs_delay, GAME_FRAME_DELAY * 2))
{
- if (helpscreen_state<num_helpscreen_els_pages)
- DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
+ if (helpscreen_state < num_helpscreen_els_pages)
+ DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
}
+
+ /* !!! workaround for playing "music" that is really a sound loop (and
+ must therefore periodically be reactivated with the current sound
+ engine !!! */
+ PlaySoundLoop(SND_MENU_INFO_SCREEN);
+
DoAnimation();
}
BackToFront();
}
-static void drawCursorExt(int ypos, int color, int graphic)
-{
- static int cursor_array[SCR_FIELDY];
-
- if (graphic)
- cursor_array[ypos] = graphic;
-
- graphic = cursor_array[ypos];
-
- if (color == FC_RED)
- graphic = (graphic == GFX_ARROW_BLUE_LEFT ? GFX_ARROW_RED_LEFT :
- graphic == GFX_ARROW_BLUE_RIGHT ? GFX_ARROW_RED_RIGHT :
- GFX_KUGEL_ROT);
-
- DrawGraphic(0, ypos, graphic);
-}
-
-static void initCursor(int ypos, int graphic)
-{
- drawCursorExt(ypos, FC_BLUE, graphic);
-}
-
-static void drawCursor(int ypos, int color)
-{
- drawCursorExt(ypos, color, 0);
-}
-
-void DrawChooseLevel()
+static void DrawChooseTree(TreeInfo **ti_ptr)
{
UnmapAllGadgets();
CloseDoor(DOOR_CLOSE_2);
ClearWindow();
- HandleChooseLevel(0,0, 0,0, MB_MENU_INITIALIZE);
- MapChooseLevelGadgets();
+ HandleChooseTree(0,0, 0,0, MB_MENU_INITIALIZE, ti_ptr);
+ MapChooseTreeGadgets(*ti_ptr);
FadeToFront();
InitAnimation();
}
-static void AdjustChooseLevelScrollbar(int id, int first_entry)
+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 = numLevelDirInfoInGroup(leveldir_current);
- items_visible = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ items_max = numTreeInfoInGroup(ti);
+ items_visible = MAX_MENU_ENTRIES_ON_SCREEN - 1;
item_position = first_entry;
if (item_position > items_max - items_visible)
GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
}
-static void drawChooseLevelList(int first_entry, int num_page_entries)
+static void drawChooseTreeList(int first_entry, int num_page_entries,
+ TreeInfo *ti)
{
int i;
char buffer[SCR_FIELDX * 2];
int max_buffer_len = (SCR_FIELDX - 2) * 2;
- int num_leveldirs = numLevelDirInfoInGroup(leveldir_current);
+ int num_entries = numTreeInfoInGroup(ti);
+ char *title_string = NULL;
+ int offset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : 16);
ClearRectangle(backbuffer, SX, SY, SXSIZE - 32, SYSIZE);
redraw_mask |= REDRAW_FIELD;
- DrawText(SX, SY, "Level Directories", FS_BIG, FC_GREEN);
+ title_string =
+ (ti->type == TREE_TYPE_LEVEL_DIR ? "Level Directories" :
+ ti->type == TREE_TYPE_GRAPHICS_DIR ? "Custom Graphics" :
+ ti->type == TREE_TYPE_SOUNDS_DIR ? "Custom Sounds" :
+ ti->type == TREE_TYPE_MUSIC_DIR ? "Custom Music" : "");
+
+ DrawText(SX + offset, SY + offset, title_string, FS_BIG,
+ (ti->type == TREE_TYPE_LEVEL_DIR ? FC_GREEN : FC_YELLOW));
for(i=0; i<num_page_entries; i++)
{
- struct LevelDirInfo *node, *node_first;
- int leveldir_pos = first_entry + i;
- int ypos = i + 2;
+ TreeInfo *node, *node_first;
+ int entry_pos = first_entry + i;
+ int ypos = MENU_SCREEN_START_YPOS + i;
- node_first = getLevelDirInfoFirstGroupEntry(leveldir_current);
- node = getLevelDirInfoFromPos(node_first, leveldir_pos);
+ node_first = getTreeInfoFirstGroupEntry(ti);
+ node = getTreeInfoFromPos(node_first, entry_pos);
strncpy(buffer, node->name , max_buffer_len);
buffer[max_buffer_len] = '\0';
DrawText(SX + 32, SY + ypos * 32, buffer, FS_MEDIUM, node->color);
if (node->parent_link)
- initCursor(ypos, GFX_ARROW_BLUE_LEFT);
+ initCursor(i, GFX_ARROW_BLUE_LEFT);
else if (node->level_group)
- initCursor(ypos, GFX_ARROW_BLUE_RIGHT);
+ initCursor(i, GFX_ARROW_BLUE_RIGHT);
else
- initCursor(ypos, GFX_KUGEL_BLAU);
+ initCursor(i, GFX_KUGEL_BLAU);
}
if (first_entry > 0)
DrawGraphic(0, 1, GFX_ARROW_BLUE_UP);
- if (first_entry + num_page_entries < num_leveldirs)
- DrawGraphic(0, MAX_LEVEL_SERIES_ON_SCREEN + 1, GFX_ARROW_BLUE_DOWN);
+ if (first_entry + num_page_entries < num_entries)
+ DrawGraphic(0, MAX_MENU_ENTRIES_ON_SCREEN + 1, GFX_ARROW_BLUE_DOWN);
}
-static void drawChooseLevelInfo(int leveldir_pos)
+static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
{
- struct LevelDirInfo *node, *node_first;
+ TreeInfo *node, *node_first;
int x, last_redraw_mask = redraw_mask;
- node_first = getLevelDirInfoFirstGroupEntry(leveldir_current);
- node = getLevelDirInfoFromPos(node_first, leveldir_pos);
+ if (ti->type != TREE_TYPE_LEVEL_DIR)
+ return;
+
+ node_first = getTreeInfoFirstGroupEntry(ti);
+ node = getTreeInfoFromPos(node_first, entry_pos);
ClearRectangle(drawto, SX + 32, SY + 32, SXSIZE - 64, 32);
DrawTextFCentered(40, FC_RED, "leave group \"%s\"", node->class_desc);
else if (node->level_group)
DrawTextFCentered(40, FC_RED, "enter group \"%s\"", node->class_desc);
- else
+ else if (ti->type == TREE_TYPE_LEVEL_DIR)
DrawTextFCentered(40, FC_RED, "%3d levels (%s)",
node->levels, node->class_desc);
MarkTileDirty(x, 1);
}
-void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
+static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
+ TreeInfo **ti_ptr)
{
static unsigned long choose_delay = 0;
- static int redraw = TRUE;
- int x = (mx + 32 - SX) / 32, y = (my + 32 - SY) / 32;
+ TreeInfo *ti = *ti_ptr;
+ int x = 0;
+ int y = ti->cl_cursor;
int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
- int num_leveldirs = numLevelDirInfoInGroup(leveldir_current);
+ int num_entries = numTreeInfoInGroup(ti);
int num_page_entries;
- if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN)
- num_page_entries = num_leveldirs;
+ if (num_entries <= MAX_MENU_ENTRIES_ON_SCREEN)
+ num_page_entries = num_entries;
else
- num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
if (button == MB_MENU_INITIALIZE)
{
- int leveldir_pos = posLevelDirInfo(leveldir_current);
+ int entry_pos = posTreeInfo(ti);
- if (leveldir_current->cl_first == -1)
+ if (ti->cl_first == -1)
{
- leveldir_current->cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
- leveldir_current->cl_cursor =
- leveldir_pos - leveldir_current->cl_first + 3;
+ ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
+ ti->cl_cursor =
+ entry_pos - ti->cl_first;
}
if (dx == 999) /* first entry is set by scrollbar position */
- leveldir_current->cl_first = dy;
+ ti->cl_first = dy;
else
- AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
- leveldir_current->cl_first);
+ AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
+ ti->cl_first, ti);
- drawChooseLevelList(leveldir_current->cl_first, num_page_entries);
- drawChooseLevelInfo(leveldir_pos);
- redraw = TRUE;
+ drawChooseTreeList(ti->cl_first, num_page_entries, ti);
+ drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
+ drawCursor(ti->cl_cursor, FC_RED);
+ return;
}
-
- if (redraw)
+ else if (button == MB_MENU_LEAVE)
{
- drawCursor(leveldir_current->cl_cursor - 1, FC_RED);
- redraw = FALSE;
- }
+ if (ti->node_parent)
+ {
+ *ti_ptr = ti->node_parent;
+ DrawChooseTree(ti_ptr);
+ }
+ else if (game_status == SETUP)
+ {
+ execSetupArtwork();
+ }
+ else
+ {
+ game_status = MAINMENU;
+ DrawMainMenu();
+ }
- if (button == MB_MENU_INITIALIZE)
return;
+ }
- if (dx || dy)
+ if (mx || my) /* mouse input */
+ {
+ x = (mx - SX) / 32;
+ y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
+ }
+ else if (dx || dy) /* keyboard input */
{
if (dy)
- {
- x = 1;
- y = leveldir_current->cl_cursor + dy;
- }
- else
- x = y = 0; /* no action */
+ y = ti->cl_cursor + dy;
if (ABS(dy) == SCR_FIELDY) /* handle KSYM_Page_Up, KSYM_Page_Down */
{
dy = SIGN(dy);
step = num_page_entries - 1;
- x = 1;
- y = (dy < 0 ? 2 : num_page_entries + 3);
+ y = (dy < 0 ? -1 : num_page_entries);
}
}
- if (x == 1 && y == 2)
+ if (x == 0 && y == -1)
{
- if (leveldir_current->cl_first > 0 &&
+ if (ti->cl_first > 0 &&
(dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY)))
{
- leveldir_current->cl_first -= step;
- if (leveldir_current->cl_first < 0)
- leveldir_current->cl_first = 0;
-
- drawChooseLevelList(leveldir_current->cl_first, num_page_entries);
- drawChooseLevelInfo(leveldir_current->cl_first +
- leveldir_current->cl_cursor - 3);
- drawCursor(leveldir_current->cl_cursor - 1, FC_RED);
- AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
- leveldir_current->cl_first);
+ 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);
+ drawCursor(ti->cl_cursor, FC_RED);
+ AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
+ ti->cl_first, ti);
return;
}
}
- else if (x == 1 && y > num_page_entries + 2)
+ else if (x == 0 && y > num_page_entries - 1)
{
- if (leveldir_current->cl_first + num_page_entries < num_leveldirs &&
+ if (ti->cl_first + num_page_entries < num_entries &&
(dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY)))
{
- leveldir_current->cl_first += step;
- if (leveldir_current->cl_first + num_page_entries > num_leveldirs)
- leveldir_current->cl_first = MAX(0, num_leveldirs - num_page_entries);
-
- drawChooseLevelList(leveldir_current->cl_first, num_page_entries);
- drawChooseLevelInfo(leveldir_current->cl_first +
- leveldir_current->cl_cursor - 3);
- drawCursor(leveldir_current->cl_cursor - 1, FC_RED);
- AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
- leveldir_current->cl_first);
+ 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);
+ drawCursor(ti->cl_cursor, FC_RED);
+ AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
+ ti->cl_first, ti);
return;
}
}
- if (!mx && !my && !dx && !dy)
- {
- x = 1;
- y = leveldir_current->cl_cursor;
- }
-
if (dx == 1)
{
- struct LevelDirInfo *node_first, *node_cursor;
- int leveldir_pos =
- leveldir_current->cl_first + leveldir_current->cl_cursor - 3;
+ TreeInfo *node_first, *node_cursor;
+ int entry_pos = ti->cl_first + y;
- node_first = getLevelDirInfoFirstGroupEntry(leveldir_current);
- node_cursor = getLevelDirInfoFromPos(node_first, leveldir_pos);
+ node_first = getTreeInfoFirstGroupEntry(ti);
+ node_cursor = getTreeInfoFromPos(node_first, entry_pos);
if (node_cursor->node_group)
{
- node_cursor->cl_first = leveldir_current->cl_first;
- node_cursor->cl_cursor = leveldir_current->cl_cursor;
- leveldir_current = node_cursor->node_group;
- DrawChooseLevel();
+ 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 && leveldir_current->node_parent)
+ else if (dx == -1 && ti->node_parent)
{
- leveldir_current = leveldir_current->node_parent;
- DrawChooseLevel();
+ *ti_ptr = ti->node_parent;
+ DrawChooseTree(ti_ptr);
+ return;
}
- if (x == 1 && y >= 3 && y <= num_page_entries + 2)
+ if (x == 0 && y >= 0 && y < num_page_entries)
{
if (button)
{
- if (y != leveldir_current->cl_cursor)
+ if (y != ti->cl_cursor)
{
- drawCursor(y - 1, FC_RED);
- drawCursor(leveldir_current->cl_cursor - 1, FC_BLUE);
- drawChooseLevelInfo(leveldir_current->cl_first + y - 3);
- leveldir_current->cl_cursor = y;
+ drawCursor(y, FC_RED);
+ drawCursor(ti->cl_cursor, FC_BLUE);
+ drawChooseTreeInfo(ti->cl_first + y, ti);
+ ti->cl_cursor = y;
}
}
else
{
- struct LevelDirInfo *node_first, *node_cursor;
- int leveldir_pos = leveldir_current->cl_first + y - 3;
+ TreeInfo *node_first, *node_cursor;
+ int entry_pos = ti->cl_first + y;
- node_first = getLevelDirInfoFirstGroupEntry(leveldir_current);
- node_cursor = getLevelDirInfoFromPos(node_first, leveldir_pos);
+ node_first = getTreeInfoFirstGroupEntry(ti);
+ node_cursor = getTreeInfoFromPos(node_first, entry_pos);
if (node_cursor->node_group)
{
- node_cursor->cl_first = leveldir_current->cl_first;
- node_cursor->cl_cursor = leveldir_current->cl_cursor;
- leveldir_current = node_cursor->node_group;
-
- DrawChooseLevel();
+ 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)
{
- leveldir_current = node_cursor->node_parent;
-
- DrawChooseLevel();
+ *ti_ptr = node_cursor->node_parent;
+ DrawChooseTree(ti_ptr);
}
else
{
- node_cursor->cl_first = leveldir_current->cl_first;
- node_cursor->cl_cursor = leveldir_current->cl_cursor;
- leveldir_current = node_cursor;
+ node_cursor->cl_first = ti->cl_first;
+ node_cursor->cl_cursor = ti->cl_cursor;
+ *ti_ptr = node_cursor;
- LoadLevelSetup_SeriesInfo();
+ if (ti->type == TREE_TYPE_LEVEL_DIR)
+ {
+ LoadLevelSetup_SeriesInfo();
- SaveLevelSetup_LastSeries();
- SaveLevelSetup_SeriesInfo();
- TapeErase();
+ SaveLevelSetup_LastSeries();
+ SaveLevelSetup_SeriesInfo();
+ TapeErase();
+ }
- game_status = MAINMENU;
- DrawMainMenu();
+ if (game_status == SETUP)
+ {
+ execSetupArtwork();
+ }
+ else
+ {
+ game_status = MAINMENU;
+ DrawMainMenu();
+ }
}
}
}
BackToFront();
- if (game_status == CHOOSELEVEL)
+ if (game_status == CHOOSELEVEL || game_status == SETUP)
DoAnimation();
}
+void DrawChooseLevel()
+{
+ DrawChooseTree(&leveldir_current);
+}
+
+void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
+{
+ HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
+}
+
void DrawHallOfFame(int highlight_position)
{
UnmapAllGadgets();
FadeToFront();
InitAnimation();
HandleHallOfFame(highlight_position,0, 0,0, MB_MENU_INITIALIZE);
- PlaySound(SND_HALLOFFAME);
+ PlaySound(SND_MENU_HALL_OF_FAME);
}
static void drawHallOfFameList(int first_entry, int highlight_position)
DrawText(SX + 80, SY + 8, "Hall Of Fame", FS_BIG, FC_YELLOW);
DrawTextFCentered(46, FC_RED, "HighScores of Level %d", level_nr);
- for(i=0; i<MAX_LEVEL_SERIES_ON_SCREEN; i++)
+ for(i=0; i<MAX_MENU_ENTRIES_ON_SCREEN; i++)
{
int entry = first_entry + i;
int color = (entry == highlight_position ? FC_RED : FC_GREEN);
}
if (ABS(dy) == SCR_FIELDY) /* handle KSYM_Page_Up, KSYM_Page_Down */
- step = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ step = MAX_MENU_ENTRIES_ON_SCREEN - 1;
if (dy < 0)
{
}
else if (dy > 0)
{
- if (first_entry + MAX_LEVEL_SERIES_ON_SCREEN < MAX_SCORE_ENTRIES)
+ if (first_entry + MAX_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
{
first_entry += step;
- if (first_entry + MAX_LEVEL_SERIES_ON_SCREEN > MAX_SCORE_ENTRIES)
- first_entry = MAX(0, MAX_SCORE_ENTRIES - MAX_LEVEL_SERIES_ON_SCREEN);
+ if (first_entry + MAX_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
+ first_entry = MAX(0, MAX_SCORE_ENTRIES - MAX_MENU_ENTRIES_ON_SCREEN);
drawHallOfFameList(first_entry, highlight_position);
return;
if (button_released)
{
- FadeSound(SND_HALLOFFAME);
+ FadeSound(SND_MENU_HALL_OF_FAME);
game_status = MAINMENU;
DrawMainMenu();
}
DoAnimation();
}
-void DrawSetupScreen()
+
+/* ========================================================================= */
+/* setup screen functions */
+/* ========================================================================= */
+
+static struct TokenInfo *setup_info;
+static int num_setup_info;
+
+static void execSetupMain()
{
- int i;
- static struct setup
- {
- boolean *value;
- char *text;
- } setup_info[] =
- {
- { &setup.sound, "Sound:", },
- { &setup.sound_loops, " Sound Loops:" },
- { &setup.sound_music, " Game Music:" },
-#if 0
- { &setup.toons, "Toons:" },
- { &setup.double_buffering, "Buffered gfx:" },
-#endif
- { &setup.scroll_delay, "Scroll Delay:" },
- { &setup.soft_scrolling, "Soft Scroll.:" },
+ setup_mode = SETUP_MODE_MAIN;
+ DrawSetupScreen();
+}
+
+static void execSetupGame()
+{
+ setup_mode = SETUP_MODE_GAME;
+ DrawSetupScreen();
+}
+
+static void execSetupGraphics()
+{
+ setup_mode = SETUP_MODE_GRAPHICS;
+ DrawSetupScreen();
+}
+
+static void execSetupSound()
+{
+ setup_mode = SETUP_MODE_SOUND;
+ DrawSetupScreen();
+}
+
+static void execSetupArtwork()
+{
+ /* needed if last screen (setup choice) changed graphics, sounds or music */
+ ReloadCustomArtwork();
+
+ setup.graphics_set = artwork.gfx_current->name;
+ setup.sounds_set = artwork.snd_current->name;
+ setup.music_set = 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 execSetupShortcut()
+{
+ setup_mode = SETUP_MODE_SHORTCUT;
+ DrawSetupScreen();
+}
+
+static void execExitSetup()
+{
+ game_status = MAINMENU;
+ DrawMainMenu();
+}
+
+static void execSaveAndExitSetup()
+{
+ SaveSetup();
+ execExitSetup();
+}
+
+static struct TokenInfo setup_info_main[] =
+{
+ { TYPE_ENTER_MENU, execSetupGame, "Game Settings" },
+ { 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, execSetupShortcut, "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:" },
+ { TYPE_SWITCH, &setup.handicap, "Handicap:" },
+ { TYPE_SWITCH, &setup.time_limit, "Timelimit:" },
+ { TYPE_SWITCH, &setup.autorecord, "Auto-Record:" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_LEAVE_MENU, execSetupMain, "Exit" },
+ { 0, NULL, NULL }
+};
+
+static struct TokenInfo setup_info_graphics[] =
+{
+ { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
+ { TYPE_SWITCH, &setup.scroll_delay, "Scroll Delay:" },
+ { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scroll.:" },
#if 0
- { &setup.fading, "Fading:" },
+ { TYPE_SWITCH, &setup.double_buffering,"Buffered gfx:" },
+ { TYPE_SWITCH, &setup.fading, "Fading:" },
#endif
- { &setup.fullscreen, "Fullscreen:" },
- { &setup.quick_doors, "Quick Doors:" },
- { &setup.autorecord, "Auto-Record:" },
- { &setup.team_mode, "Team-Mode:" },
- { &setup.handicap, "Handicap:" },
- { &setup.time_limit, "Timelimit:" },
- { NULL, "Input Devices" },
- { NULL, "" },
- { NULL, "Exit" },
- { NULL, "Save and exit" }
- };
+ { TYPE_SWITCH, &setup.quick_doors, "Quick Doors:" },
+ { TYPE_SWITCH, &setup.toons, "Toons:" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_LEAVE_MENU, execSetupMain, "Exit" },
+ { 0, NULL, NULL }
+};
- UnmapAllGadgets();
- CloseDoor(DOOR_CLOSE_2);
- ClearWindow();
+static struct TokenInfo setup_info_sound[] =
+{
+ { TYPE_SWITCH, &setup.sound, "Sound:", },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_SWITCH, &setup.sound_simple, "Simple Sound:" },
+ { TYPE_SWITCH, &setup.sound_loops, "Sound Loops:" },
+ { TYPE_SWITCH, &setup.sound_music, "Game Music:" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_LEAVE_MENU, execSetupMain, "Exit" },
+ { 0, NULL, NULL }
+};
- DrawText(SX + 16, SY + 16, "SETUP",FS_BIG,FC_YELLOW);
+static struct TokenInfo setup_info_artwork[] =
+{
+ { TYPE_ENTER_MENU, execSetupChooseGraphics,"Custom Graphics" },
+ { TYPE_STRING, &setup.graphics_set, "" },
+ { TYPE_ENTER_MENU, execSetupChooseSounds, "Custom Sounds" },
+ { TYPE_STRING, &setup.sounds_set, "" },
+ { TYPE_ENTER_MENU, execSetupChooseMusic, "Custom Music" },
+ { TYPE_STRING, &setup.music_set, "" },
+ { TYPE_EMPTY, NULL, "" },
+ { 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:" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_LEAVE_MENU, execSetupMain, "Exit" },
+ { 0, NULL, NULL }
+};
- for(i=SETUP_SCREEN_POS_START;i<=SETUP_SCREEN_POS_END;i++)
- {
- int base = i - SETUP_SCREEN_POS_START;
+static struct TokenInfo setup_info_shortcut[] =
+{
+ { TYPE_KEYTEXT, NULL, "Quick Save Game:", },
+ { TYPE_KEY, &setup.shortcut.save_game, "" },
+ { TYPE_KEYTEXT, NULL, "Quick Load Game:", },
+ { TYPE_KEY, &setup.shortcut.load_game, "" },
+ { TYPE_KEYTEXT, NULL, "Toggle Pause:", },
+ { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_YES_NO, &setup.ask_on_escape, "Ask on Esc:" },
+ { TYPE_EMPTY, NULL, "" },
+ { TYPE_LEAVE_MENU, execSetupMain, "Exit" },
+ { 0, NULL, NULL }
+};
+
+static Key getSetupKey()
+{
+ Key key = KSYM_UNDEFINED;
+ boolean got_key_event = FALSE;
- if (!(i >= SETUP_SCREEN_POS_EMPTY1 && i <= SETUP_SCREEN_POS_EMPTY2))
+ while (!got_key_event)
+ {
+ if (PendingEvent()) /* got event */
{
- DrawText(SX+32,SY+i*32, setup_info[base].text, FS_BIG,FC_GREEN);
+ Event event;
- if (strcmp(setup_info[base].text, "Input Devices") == 0)
- initCursor(i, GFX_ARROW_BLUE_RIGHT);
- else
- initCursor(i, GFX_KUGEL_BLAU);
- }
+ NextEvent(&event);
- if (setup_info[base].value)
- {
- int setting_value = *setup_info[base].value;
+ switch(event.type)
+ {
+ case EVENT_KEYPRESS:
+ {
+ key = GetEventKey((KeyEvent *)&event, TRUE);
- DrawText(SX+14*32, SY+i*32, (setting_value ? "on" : "off"),
- FS_BIG, (setting_value ? FC_YELLOW : FC_BLUE));
+ /* 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;
+ }
}
+
+ BackToFront();
+ DoAnimation();
+
+ /* don't eat all CPU time */
+ Delay(10);
}
- FadeToFront();
- InitAnimation();
- HandleSetupScreen(0,0,0,0,MB_MENU_INITIALIZE);
+ return key;
}
-void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
+static void drawSetupValue(int pos)
{
- static int choice = 3;
- static int redraw = TRUE;
- int x = (mx+32-SX)/32, y = (my+32-SY)/32;
- int pos_start = SETUP_SCREEN_POS_START + 1;
- int pos_empty1 = SETUP_SCREEN_POS_EMPTY1 + 1;
- int pos_empty2 = SETUP_SCREEN_POS_EMPTY2 + 1;
- int pos_end = SETUP_SCREEN_POS_END + 1;
+ int xpos = MENU_SCREEN_VALUE_XPOS;
+ int ypos = MENU_SCREEN_START_YPOS + pos;
+ int font_size = FS_BIG;
+ int font_color = FC_YELLOW;
+ char *value_string = getSetupValue(setup_info[pos].type & ~TYPE_GHOSTED,
+ setup_info[pos].value);
+
+ if (value_string == NULL)
+ return;
- if (button == MB_MENU_INITIALIZE)
- redraw = TRUE;
+ if (setup_info[pos].type & TYPE_KEY)
+ {
+ xpos = 3;
- if (redraw)
+ if (setup_info[pos].type & TYPE_QUERY)
+ {
+ value_string = "<press key>";
+ font_color = FC_RED;
+ }
+ }
+ else if (setup_info[pos].type & TYPE_STRING)
{
- drawCursor(choice - 1, FC_RED);
- redraw = FALSE;
+ int max_value_len = (SCR_FIELDX - 2) * 2;
+
+ xpos = 1;
+ font_size = FS_MEDIUM;
+
+ if (strlen(value_string) > max_value_len)
+ value_string[max_value_len] = '\0';
}
+ else if (setup_info[pos].type & TYPE_BOOLEAN_STYLE &&
+ !*(boolean *)(setup_info[pos].value))
+ font_color = FC_BLUE;
- if (button == MB_MENU_INITIALIZE)
- return;
+ DrawText(SX + xpos * 32, SY + ypos * 32,
+ (xpos == 3 ? " " : " "), FS_BIG, FC_YELLOW);
+ DrawText(SX + xpos * 32, SY + ypos * 32, value_string, font_size,font_color);
+}
- if (dx || dy)
+static void changeSetupValue(int pos)
+{
+ if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
{
- if (dy)
- {
- x = 1;
- y = choice+dy;
- }
- else
- x = y = 0;
+ *(boolean *)setup_info[pos].value ^= TRUE;
+ }
+ else if (setup_info[pos].type & TYPE_KEY)
+ {
+ Key key;
- if (y >= pos_empty1 && y <= pos_empty2)
- y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
+ setup_info[pos].type |= TYPE_QUERY;
+ drawSetupValue(pos);
+ setup_info[pos].type &= ~TYPE_QUERY;
- if (y < pos_start)
- y = pos_start;
- else if (y > pos_end)
- y = pos_end;
+ key = getSetupKey();
+ if (key != KSYM_UNDEFINED)
+ *(Key *)setup_info[pos].value = key;
}
- if (!mx && !my && !dx && !dy)
+ drawSetupValue(pos);
+}
+
+static void DrawSetupScreen_Generic()
+{
+ char *title_string = NULL;
+ int i;
+
+ UnmapAllGadgets();
+ CloseDoor(DOOR_CLOSE_2);
+ ClearWindow();
+
+ 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_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)
{
- x = 1;
- y = choice;
+ setup_info = setup_info_artwork;
+ title_string = "Custom Artwork";
}
+ else if (setup_mode == SETUP_MODE_SHORTCUT)
+ {
+ setup_info = setup_info_shortcut;
+ title_string = "Setup Shortcuts";
+ }
+
+ DrawText(SX + 16, SY + 16, title_string, FS_BIG, FC_YELLOW);
- if (dx == 1 && choice == 14)
+ num_setup_info = 0;
+ for(i=0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
{
- game_status = SETUPINPUT;
- DrawSetupInputScreen();
- redraw = TRUE;
+ void *value_ptr = setup_info[i].value;
+ int ypos = MENU_SCREEN_START_YPOS + i;
+ int font_size = FS_BIG;
+
+ /* set some entries to "unchangeable" according to other variables */
+ if ((value_ptr == &setup.sound && !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))
+ setup_info[i].type |= TYPE_GHOSTED;
+
+ if (setup_info[i].type & TYPE_STRING)
+ font_size = FS_MEDIUM;
+
+ DrawText(SX + 32, SY + ypos * 32, setup_info[i].text, font_size, FC_GREEN);
+
+ if (setup_info[i].type & TYPE_ENTER_MENU)
+ initCursor(i, GFX_ARROW_BLUE_RIGHT);
+ else if (setup_info[i].type & TYPE_LEAVE_MENU)
+ initCursor(i, GFX_ARROW_BLUE_LEFT);
+ else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
+ initCursor(i, GFX_KUGEL_BLAU);
+
+ if (setup_info[i].type & TYPE_VALUE)
+ drawSetupValue(i);
+
+ num_setup_info++;
}
- if (x==1 && y >= pos_start && y <= pos_end &&
- !(y >= pos_empty1 && y <= pos_empty2))
+ FadeToFront();
+ InitAnimation();
+ HandleSetupScreen_Generic(0,0,0,0,MB_MENU_INITIALIZE);
+}
+
+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];
+ int x = 0;
+ int y = choice;
+
+ if (button == MB_MENU_INITIALIZE)
{
- if (button)
+ drawCursor(choice, FC_RED);
+ return;
+ }
+ else if (button == MB_MENU_LEAVE)
+ {
+ for (y=0; y<num_setup_info; y++)
{
- if (y!=choice)
+ if (setup_info[y].type & TYPE_LEAVE_MENU)
{
- drawCursor(y - 1, FC_RED);
- drawCursor(choice - 1, FC_BLUE);
+ void (*menu_callback_function)(void) = setup_info[y].value;
+
+ menu_callback_function();
+ break; /* absolutely needed because function changes 'setup_info'! */
}
- choice = y;
}
- else
+
+ return;
+ }
+
+ if (mx || my) /* mouse input */
+ {
+ x = (mx - SX) / 32;
+ y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
+ }
+ else if (dx || dy) /* keyboard input */
+ {
+ if (dx)
{
- int yy = y-1;
+ int menu_navigation_type = (dx < 0 ? TYPE_LEAVE_MENU : TYPE_ENTER_MENU);
- if (y == 3 && audio.sound_available)
- {
- if (setup.sound)
- {
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- DrawText(SX+14*32, SY+(yy+1)*32,"off",FS_BIG,FC_BLUE);
- DrawText(SX+14*32, SY+(yy+2)*32,"off",FS_BIG,FC_BLUE);
- setup.sound_loops = FALSE;
- setup.sound_music = FALSE;
- }
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.sound = !setup.sound;
- }
- else if (y == 4 && audio.loops_available)
- {
- if (setup.sound_loops)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- {
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- DrawText(SX+14*32, SY+(yy-1)*32,"on ",FS_BIG,FC_YELLOW);
- setup.sound = TRUE;
- }
- setup.sound_loops = !setup.sound_loops;
- }
- else if (y == 5 && audio.loops_available)
- {
- if (setup.sound_music)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- {
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- DrawText(SX+14*32, SY+(yy-2)*32,"on ",FS_BIG,FC_YELLOW);
- setup.sound = TRUE;
- }
- setup.sound_music = !setup.sound_music;
- }
+ if ((setup_info[choice].type & menu_navigation_type) ||
+ (setup_info[choice].type & TYPE_BOOLEAN_STYLE))
+ button = MB_MENU_CHOICE;
+ }
+ else if (dy)
+ y = choice + dy;
-#if 0
- else if (y == 6)
- {
- if (setup.toons)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.toons = !setup.toons;
- }
- else if (y == 7)
- {
-#if 0
- if (setup.double_buffering)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.double_buffering = !setup.double_buffering;
- setup.direct_draw = !setup.double_buffering;
-#else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.double_buffering = TRUE;
- setup.direct_draw = !setup.double_buffering;
-#endif
- }
-#endif
+ /* 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;
+ }
- else if (y == 6)
- {
- if (setup.scroll_delay)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.scroll_delay = !setup.scroll_delay;
- }
- else if (y == 7)
- {
- if (setup.soft_scrolling)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.soft_scrolling = !setup.soft_scrolling;
- }
-#if 0
- else if (y == 8)
- {
- if (setup.fading)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.fading = !setup.fading;
- }
-#endif
- else if (y == 8 && video.fullscreen_available)
- {
- if (setup.fullscreen)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.fullscreen = !setup.fullscreen;
- }
- else if (y == 9)
- {
- if (setup.quick_doors)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.quick_doors = !setup.quick_doors;
- }
- else if (y == 10)
- {
- if (setup.autorecord)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.autorecord = !setup.autorecord;
- }
- else if (y == 11)
- {
- if (setup.team_mode)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.team_mode = !setup.team_mode;
- }
- else if (y == 12)
- {
- if (setup.handicap)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.handicap = !setup.handicap;
- }
- else if (y == 13)
+ if (x == 0 && y >= 0 && y < num_setup_info &&
+ (setup_info[y].type & ~TYPE_SKIP_ENTRY))
+ {
+ if (button)
+ {
+ if (y != choice)
{
- if (setup.time_limit)
- DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
- else
- DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
- setup.time_limit = !setup.time_limit;
+ drawCursor(y, FC_RED);
+ drawCursor(choice, FC_BLUE);
+ choice = choice_store[setup_mode] = y;
}
- else if (y == 14)
+ }
+ else if (!(setup_info[y].type & TYPE_GHOSTED))
+ {
+ if (setup_info[y].type & TYPE_ENTER_OR_LEAVE_MENU)
{
- game_status = SETUPINPUT;
- DrawSetupInputScreen();
- redraw = TRUE;
+ void (*menu_callback_function)(void) = setup_info[choice].value;
+
+ menu_callback_function();
}
- else if (y==pos_end-1 || y==pos_end)
+ else
{
- if (y==pos_end)
- {
- SaveSetup();
-
- /*
- SaveJoystickData();
- */
+ if ((setup_info[y].type & TYPE_KEYTEXT) &&
+ (setup_info[y + 1].type & TYPE_KEY))
+ y++;
-#if defined(PLATFORM_MSDOS)
- save_joystick_data(JOYSTICK_FILENAME);
-#endif
-
-
- }
-
- game_status = MAINMENU;
- DrawMainMenu();
- redraw = TRUE;
+ if (setup_info[y].type & TYPE_VALUE)
+ changeSetupValue(y);
}
}
}
+
BackToFront();
- if (game_status==SETUP)
+ if (game_status == SETUP)
DoAnimation();
}
-void DrawSetupInputScreen()
+void DrawSetupScreen_Input()
{
ClearWindow();
- DrawText(SX+16, SY+16, "SETUP INPUT", FS_BIG, FC_YELLOW);
+ DrawText(SX+16, SY+16, "Setup Input", FS_BIG, FC_YELLOW);
- initCursor(2, GFX_KUGEL_BLAU);
- initCursor(3, GFX_KUGEL_BLAU);
- initCursor(4, GFX_ARROW_BLUE_RIGHT);
- initCursor(15, GFX_KUGEL_BLAU);
+ initCursor(0, GFX_KUGEL_BLAU);
+ initCursor(1, GFX_KUGEL_BLAU);
+ initCursor(2, GFX_ARROW_BLUE_RIGHT);
+ initCursor(13, GFX_ARROW_BLUE_LEFT);
- DrawGraphic(10, 2, GFX_ARROW_BLUE_LEFT);
- DrawGraphic(12, 2, GFX_ARROW_BLUE_RIGHT);
+ DrawGraphic(10, MENU_SCREEN_START_YPOS, GFX_ARROW_BLUE_LEFT);
+ DrawGraphic(12, MENU_SCREEN_START_YPOS, GFX_ARROW_BLUE_RIGHT);
DrawText(SX+32, SY+2*32, "Player:", FS_BIG, FC_GREEN);
DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN);
DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN);
+#if 0
+ DeactivateJoystickForCalibration();
DrawTextFCentered(SYSIZE - 20, FC_BLUE,
"Joysticks deactivated on this screen");
+#endif
- HandleSetupInputScreen(0,0, 0,0, MB_MENU_INITIALIZE);
+ HandleSetupScreen_Input(0,0, 0,0, MB_MENU_INITIALIZE);
FadeToFront();
InitAnimation();
}
device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
}
else
- strncpy(device_name, joystick_device_name[device_nr], strlen(device_name));
+ strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
+ strlen(device_name));
}
static void drawPlayerSetupInputInfo(int player_nr)
}
}
-void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button)
+void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
{
- static int choice = 3;
+ static int choice = 0;
static int player_nr = 0;
- static int redraw = TRUE;
- int x = (mx+32-SX)/32, y = (my+32-SY)/32;
- int pos_start = SETUPINPUT_SCREEN_POS_START + 1;
- int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1 + 1;
- int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2 + 1;
- int pos_end = SETUPINPUT_SCREEN_POS_END + 1;
+ 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(player_nr);
- redraw = TRUE;
+ drawCursor(choice, FC_RED);
+ return;
}
-
- if (redraw)
+ else if (button == MB_MENU_LEAVE)
{
- drawCursor(choice - 1, FC_RED);
- redraw = FALSE;
+ setup_mode = SETUP_MODE_MAIN;
+ DrawSetupScreen();
+ InitJoysticks();
}
- if (button == MB_MENU_INITIALIZE)
- return;
-
- if (dx || dy)
+ if (mx || my) /* mouse input */
{
- if (dx && choice == 3)
- {
- x = (dx < 0 ? 11 : 13);
- y = 3;
- }
- else if (dx && choice == 4)
- {
+ x = (mx - SX) / 32;
+ y = (my - SY) / 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;
- x = 1;
- y = 4;
- }
else if (dy)
- {
- x = 1;
y = choice + dy;
- }
- else
- x = y = 0;
if (y >= pos_empty1 && y <= pos_empty2)
y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
-
- if (y < pos_start)
- y = pos_start;
- else if (y > pos_end)
- y = pos_end;
- }
-
- if (!mx && !my && !dx && !dy)
- {
- x = 1;
- y = choice;
}
- if (y == 3 && ((x == 1 && !button) || ((x == 11 || x == 13) && button)))
+ if (y == 0 && ((x == 0 && !button) || ((x == 10 || x == 12) && button)))
{
static unsigned long delay = 0;
if (!DelayReached(&delay, GADGET_FRAME_DELAY))
goto out;
- player_nr = (player_nr + (x == 11 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
+ player_nr = (player_nr + (x == 10 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
drawPlayerSetupInputInfo(player_nr);
}
- else if (x==1 && y >= pos_start && y <= pos_end &&
+ else if (x == 0 && y >= pos_start && y <= pos_end &&
!(y >= pos_empty1 && y <= pos_empty2))
{
if (button)
{
if (y != choice)
{
- drawCursor(y - 1, FC_RED);
- drawCursor(choice - 1, FC_BLUE);
+ drawCursor(y, FC_RED);
+ drawCursor(choice, FC_BLUE);
+ choice = y;
}
- choice = y;
}
else
{
- if (y == 4)
+ if (y == 1)
{
char *device_name = setup.input[player_nr].joy.device_name;
setJoystickDeviceToNr(device_name, new_device_nr);
}
-
- /*
- InitJoysticks();
- */
-
-
-#if 0
- int one_joystick_nr = (dx >= 0 ? 0 : 1);
- int the_other_joystick_nr = (dx >= 0 ? 1 : 0);
-
- if (setup.input[player_nr].use_joystick)
- {
- if (setup.input[player_nr].joystick_nr == one_joystick_nr)
- setup.input[player_nr].joystick_nr = the_other_joystick_nr;
- else
- setup.input[player_nr].use_joystick = FALSE;
- }
- else
- {
- setup.input[player_nr].use_joystick = TRUE;
- setup.input[player_nr].joystick_nr = one_joystick_nr;
- }
-#endif
-
drawPlayerSetupInputInfo(player_nr);
}
- else if (y == 5)
+ else if (y == 2)
{
if (setup.input[player_nr].use_joystick)
{
InitJoysticks();
- game_status = CALIBRATION;
CalibrateJoystick(player_nr);
- game_status = SETUPINPUT;
}
else
CustomizeKeyboard(player_nr);
-
- redraw = TRUE;
}
else if (y == pos_end)
{
InitJoysticks();
- game_status = SETUP;
+ setup_mode = SETUP_MODE_MAIN;
DrawSetupScreen();
- redraw = TRUE;
}
}
}
+
BackToFront();
out:
- if (game_status == SETUPINPUT)
+ if (game_status == SETUP)
DoAnimation();
}
{
case EVENT_KEYPRESS:
{
- Key key = GetEventKey((KeyEvent *)&event, TRUE);
+ Key key = GetEventKey((KeyEvent *)&event, FALSE);
if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
{
setup.input[player_nr].key = custom_key;
StopAnimation();
- DrawSetupInputScreen();
+ DrawSetupScreen_Input();
}
-void CalibrateJoystick(int player_nr)
+static boolean CalibrateJoystickMain(int player_nr)
{
-#ifdef __FreeBSD__
- struct joystick joy_ctrl;
-#else
- struct joystick_control
- {
- int buttons;
- int x;
- int y;
- } joy_ctrl;
-#endif
-
-#if !defined(PLATFORM_MSDOS)
- int new_joystick_xleft = 128, new_joystick_xright = 128;
- int new_joystick_yupper = 128, new_joystick_ylower = 128;
+ 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;
-#else
- int calibration_step = 1;
-#endif
- int joystick_fd = stored_player[player_nr].joystick_fd;
+ 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;
+ int check_remaining = 3 * 3;
+ int joy_x, joy_y;
int joy_value;
int result = -1;
- if (joystick_status == JOYSTICK_OFF ||
- joystick_fd < 0 ||
- !setup.input[player_nr].use_joystick)
- goto error_out;
+ if (joystick.status == JOYSTICK_NOT_AVAILABLE)
+ return FALSE;
- ClearWindow();
+ if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
+ return FALSE;
-#if !defined(PLATFORM_MSDOS)
- DrawText(SX, SY + 6*32, " ROTATE JOYSTICK ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 7*32, "IN ALL DIRECTIONS", FS_BIG, FC_YELLOW);
- DrawText(SX + 16, SY + 9*32, " IF ALL BALLS ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 10*32, " ARE YELLOW, ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 11*32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW);
- check_remaining = 3 * 3;
-#else
- DrawText(SX, SY + 7*32, " MOVE JOYSTICK ", FS_BIG, FC_YELLOW);
- DrawText(SX + 16, SY + 8*32, " TO ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 9*32, " CENTER POSITION ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 10*32, " AND ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 11*32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW);
- check_remaining = 0;
-#endif
+ ClearWindow();
for(y=0; y<3; y++)
{
}
}
+ DrawText(SX, SY + 6 * 32, " ROTATE JOYSTICK ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 7 * 32, "IN ALL DIRECTIONS", FS_BIG, FC_YELLOW);
+ DrawText(SX + 16, SY + 9 * 32, " IF ALL BALLS ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 10 * 32, " ARE YELLOW, ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 11 * 32, " CENTER JOYSTICK ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 12 * 32, " AND ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 13 * 32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW);
+
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);
- DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_ROT);
- BackToFront();
+ /* eventually uncalibrated center position (joystick could be uncentered) */
+ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
+ return FALSE;
-#ifdef __FreeBSD__
- joy_ctrl.b1 = joy_ctrl.b2 = 0;
-#else
- joy_ctrl.buttons = 0;
-#endif
+ new_joystick_xmiddle = joy_x;
+ new_joystick_ymiddle = joy_y;
- while(Joystick(player_nr) & JOY_BUTTON);
+ DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_ROT);
+ BackToFront();
+ while(Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
InitAnimation();
while(result < 0)
}
}
-#if !defined(PLATFORM_MSDOS)
-
-#if defined(TARGET_SDL)
- joy_ctrl.x = Get_SDL_Joystick_Axis(joystick_fd, 0);
- joy_ctrl.y = Get_SDL_Joystick_Axis(joystick_fd, 1);
-#else
- if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
- {
- joystick_status = JOYSTICK_OFF;
- goto error_out;
- }
-#endif
-
- new_joystick_xleft = MIN(new_joystick_xleft, joy_ctrl.x);
- new_joystick_xright = MAX(new_joystick_xright, joy_ctrl.x);
- new_joystick_yupper = MIN(new_joystick_yupper, joy_ctrl.y);
- new_joystick_ylower = MAX(new_joystick_ylower, joy_ctrl.y);
+ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
+ return FALSE;
- new_joystick_xmiddle =
- new_joystick_xleft + (new_joystick_xright - new_joystick_xleft) / 2;
- new_joystick_ymiddle =
- new_joystick_yupper + (new_joystick_ylower - new_joystick_yupper) / 2;
+ 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.ymiddle = new_joystick_ymiddle;
CheckJoystickData();
-#endif
joy_value = Joystick(player_nr);
if (joy_value & JOY_BUTTON && check_remaining == 0)
- {
result = 1;
-#if defined(PLATFORM_MSDOS)
- if (calibration_step == 1)
- {
- remove_joystick();
- InitJoysticks();
- }
- else if (calibrate_joystick(joystick_fd) != 0)
- {
- joystick_status = JOYSTICK_OFF;
- goto error_out;
- }
-
- if (joy[joystick_fd].flags & JOYFLAG_CALIBRATE)
- {
- calibration_step++;
- result = -1;
-
- DrawText(SX, SY + 7*32, " MOVE JOYSTICK ", FS_BIG, FC_YELLOW);
- DrawText(SX + 16, SY + 8*32, " TO ", FS_BIG, FC_YELLOW);
-
- if (calibration_step == 2)
- DrawText(SX + 16, SY + 9*32," THE UPPER LEFT ", FS_BIG, FC_YELLOW);
- else
- DrawText(SX, SY + 9*32," THE LOWER RIGHT ", FS_BIG, FC_YELLOW);
-
- DrawText(SX, SY + 10*32, " AND ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 11*32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW);
-
- BackToFront();
-
- while(Joystick(player_nr) & JOY_BUTTON)
- DoAnimation();
- }
-#endif
- }
-
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)
{
-#if !defined(PLATFORM_MSDOS)
DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_GELB);
-#else
- DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_BLAU);
-#endif
DrawGraphic(xpos + x, ypos + y, GFX_KUGEL_ROT);
last_x = x;
}
#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.yupper,
setup.input[player_nr].joy.ymiddle,
setup.input[player_nr].joy.ylower);
+#endif
#endif
}
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();
- DrawSetupInputScreen();
+ DrawSetupScreen_Input();
/* wait until the last pressed button was released */
- while(Joystick(player_nr) & JOY_BUTTON)
+ while (Joystick(player_nr) & JOY_BUTTON)
{
if (PendingEvent()) /* got event */
{
Delay(10);
}
}
- return;
- error_out:
+ return TRUE;
+}
- ClearWindow();
- DrawText(SX + 16, SY + 6*32, " JOYSTICK NOT ", FS_BIG, FC_YELLOW);
- DrawText(SX, SY + 7*32, " AVAILABLE ", FS_BIG, FC_YELLOW);
- BackToFront();
- Delay(2000);
- DrawSetupInputScreen();
+void CalibrateJoystick(int player_nr)
+{
+ if (!CalibrateJoystickMain(player_nr))
+ {
+ ClearWindow();
+
+ DrawText(SX + 16, SY + 6*32, " JOYSTICK NOT ", FS_BIG, FC_YELLOW);
+ DrawText(SX, SY + 7*32, " AVAILABLE ", FS_BIG, FC_YELLOW);
+ BackToFront();
+ Delay(2000); /* show error message for two seconds */
+ }
+}
+
+void DrawSetupScreen()
+{
+ DeactivateJoystick();
+
+ if (setup_mode == SETUP_MODE_INPUT)
+ DrawSetupScreen_Input();
+ 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();
+}
+
+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_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);
}
void HandleGameActions()
SC_SCROLLBUTTON_XPOS + 0 * SC_SCROLLBUTTON_XSIZE, SC_SCROLLBUTTON_YPOS,
SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
SCREEN_CTRL_ID_SCROLL_UP,
- "scroll level series up"
+ "scroll up"
},
{
SC_SCROLLBUTTON_XPOS + 1 * SC_SCROLLBUTTON_XSIZE, SC_SCROLLBUTTON_YPOS,
SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
SCREEN_CTRL_ID_SCROLL_DOWN,
- "scroll level series down"
+ "scroll down"
}
};
struct GadgetInfo *gi;
int items_max, items_visible, item_position;
unsigned long event_mask;
- int num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ int num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
#if 0
- if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN)
+ if (num_leveldirs <= MAX_MENU_ENTRIES_ON_SCREEN)
num_page_entries = num_leveldirs;
else
- num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1;
+ num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
items_max = MAX(num_leveldirs, num_page_entries);
items_visible = num_page_entries;
CreateScreenScrollbars();
}
-void MapChooseLevelGadgets()
+void MapChooseTreeGadgets(TreeInfo *ti)
{
- int num_leveldirs = numLevelDirInfoInGroup(leveldir_current);
+ int num_entries = numTreeInfoInGroup(ti);
int i;
- if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN)
+ if (num_entries <= MAX_MENU_ENTRIES_ON_SCREEN)
return;
for (i=0; i<NUM_SCREEN_GADGETS; i++)
MapGadget(screen_gadget[i]);
}
-void UnmapChooseLevelGadgets()
+void UnmapChooseTreeGadgets()
{
int i;
{
int id = gi->custom_id;
- if (game_status != CHOOSELEVEL)
+ if (game_status != CHOOSELEVEL && game_status != SETUP)
return;
switch (id)
{
case SCREEN_CTRL_ID_SCROLL_UP:
- HandleChooseLevel(SX,SY + 32, 0,0, MB_MENU_MARK);
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(SX,SY + 32, 0,0, MB_MENU_MARK);
+ else if (game_status == SETUP)
+ HandleSetupScreen(SX,SY + 32, 0,0, MB_MENU_MARK);
break;
case SCREEN_CTRL_ID_SCROLL_DOWN:
- HandleChooseLevel(SX,SY + SYSIZE - 32, 0,0, MB_MENU_MARK);
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(SX,SY + SYSIZE - 32, 0,0, MB_MENU_MARK);
+ else if (game_status == SETUP)
+ HandleSetupScreen(SX,SY + SYSIZE - 32, 0,0, MB_MENU_MARK);
break;
case SCREEN_CTRL_ID_SCROLL_VERTICAL:
- HandleChooseLevel(0,0, 999,gi->event.item_position, MB_MENU_INITIALIZE);
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
+ else if (game_status == SETUP)
+ HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
break;
default:
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "main.h"
void DrawHeadline(void);
+
void DrawMainMenu(void);
void HandleMainMenu(int, int, int, int, int);
+
void DrawHelpScreenElAction(int);
void DrawHelpScreenElText(int);
void DrawHelpScreenMusicText(int);
void DrawHelpScreenCreditsText(void);
void DrawHelpScreen(void);
void HandleHelpScreen(int);
+
void HandleTypeName(int, Key);
+
void DrawChooseLevel(void);
void HandleChooseLevel(int, int, int, int, int);
+
void DrawHallOfFame(int);
void HandleHallOfFame(int, int, int, int, int);
+
void DrawSetupScreen(void);
void HandleSetupScreen(int, int, int, int, int);
-void DrawSetupInputScreen(void);
-void HandleSetupInputScreen(int, int, int, int, int);
-void CustomizeKeyboard(int);
-void CalibrateJoystick(int);
+
void HandleGameActions(void);
void CreateScreenGadgets();
-void MapChooseLevelGadgets();
-void UnmapChooseLevelGadgets();
+void MapChooseTreeGadgets(TreeInfo *);
+void UnmapChooseTreeGadgets();
#endif /* SCREENS_H */
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
/* tape button identifiers */
#define TAPE_CTRL_ID_EJECT 0
-#define TAPE_CTRL_ID_STOP 1
-#define TAPE_CTRL_ID_PAUSE 2
-#define TAPE_CTRL_ID_RECORD 3
-#define TAPE_CTRL_ID_PLAY 4
+#define TAPE_CTRL_ID_INDEX 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 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 TapeStopIndexSearch();
static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
/* tape control functions */
/* ========================================================================= */
-void TapeStartRecording()
+void TapeErase()
{
- time_t zeit1 = time(NULL);
- struct tm *zeit2 = localtime(&zeit1);
+ time_t epoch_seconds = time(NULL);
+ struct tm *time = localtime(&epoch_seconds);
int i;
- if (!TAPE_IS_STOPPED(tape))
- TapeStop();
-
- tape.level_nr = level_nr;
tape.length = 0;
tape.counter = 0;
+
+ tape.level_nr = level_nr;
tape.pos[tape.counter].delay = 0;
- tape.recording = TRUE;
- tape.playing = FALSE;
- tape.pausing = FALSE;
tape.changed = TRUE;
- tape.date = 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
+
+ tape.date = 10000*(time->tm_year % 100) + 100*time->tm_mon + time->tm_mday;
tape.random_seed = InitRND(NEW_RANDOMIZE);
+ tape.file_version = FILE_VERSION_ACTUAL;
+ tape.game_version = GAME_VERSION_ACTUAL;
+ tape.engine_version = level.game_version;
+
for(i=0; i<MAX_PLAYERS; i++)
tape.player_participates[i] = 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.index_search = FALSE;
+ tape.quick_resume = FALSE;
+ tape.single_step = FALSE;
+
+ InitRND(tape.random_seed);
+}
+
+void TapeStartRecording()
+{
+ if (!TAPE_IS_STOPPED(tape))
+ TapeStop();
+
+ TapeErase();
+ TapeRewind();
+
+ tape.recording = TRUE;
DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
+ MapTapeIndexButton();
+
+ SetDrawDeactivationMask(REDRAW_NONE);
+ audio.sound_deactivated = FALSE;
}
-void TapeStopRecording()
+static void TapeStartGameRecording()
{
-#if 0
- int i;
+ TapeStartRecording();
+
+#if defined(PLATFORM_UNIX)
+ if (options.network)
+ SendToServer_StartPlaying();
+ else
#endif
+ {
+ game_status = PLAYING;
+ StopAnimation();
+ InitGame();
+ }
+}
- if (!tape.recording)
+static void TapeAppendRecording()
+{
+ if (!tape.playing || !tape.pausing)
return;
-#if 0
- for(i=0; i<MAX_PLAYERS; i++)
- tape.pos[tape.counter].action[i] = 0;
-#endif
+ tape.pos[tape.counter].delay = tape.delay_played;
+ tape.playing = FALSE;
+ tape.recording = TRUE;
+ tape.changed = TRUE;
+
+ DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
+}
+
+void TapeHaltRecording()
+{
+ if (!tape.recording)
+ return;
tape.counter++;
+ tape.pos[tape.counter].delay = 0;
+
tape.length = tape.counter;
tape.length_seconds = GetTapeLength();
- tape.recording = FALSE;
- tape.pausing = FALSE;
- DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
}
-#if 0
-void TapeRecordAction(byte joy[MAX_PLAYERS])
+void TapeStopRecording()
{
- int i;
-
- if (!tape.recording || tape.pausing)
+ if (!tape.recording)
return;
- if (tape.counter >= MAX_TAPELEN-1)
- {
- TapeStopRecording();
- return;
- }
+ TapeHaltRecording();
- for(i=0; i<MAX_PLAYERS; i++)
- tape.pos[tape.counter].action[i] = joy[i];
+ tape.recording = FALSE;
+ tape.pausing = FALSE;
- tape.counter++;
- tape.pos[tape.counter].delay = 0;
+ DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
+ MapTapeEjectButton();
}
-#else
-
void TapeRecordAction(byte action[MAX_PLAYERS])
{
int i;
if (!tape.recording || tape.pausing)
return;
- if (tape.counter >= MAX_TAPELEN-1)
+ if (tape.counter >= MAX_TAPELEN - 1)
{
TapeStopRecording();
return;
tape.pos[tape.counter].delay++;
}
}
-#endif
-#if 0
-void TapeRecordDelay()
-{
- int i;
-
- if (!tape.recording || tape.pausing)
- return;
-
- if (tape.counter >= MAX_TAPELEN)
- {
- TapeStopRecording();
- return;
- }
-
- tape.pos[tape.counter].delay++;
-
- if (tape.pos[tape.counter].delay >= 255)
- {
- for(i=0; i<MAX_PLAYERS; i++)
- tape.pos[tape.counter].action[i] = 0;
-
- tape.counter++;
- tape.pos[tape.counter].delay = 0;
- }
-}
-
-#else
-
-void TapeRecordDelay()
-{
-}
-#endif
-
-void TapeTogglePause()
+void TapeTogglePause(boolean toggle_manual)
{
unsigned long state;
+#if 0
if (!tape.recording && !tape.playing)
return;
+#endif
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_PBEND_OFF;
DrawVideoDisplay(state, 0);
+
+ if (tape.index_search)
+ {
+ TapeStopIndexSearch();
+
+ if (tape.quick_resume)
+ {
+ tape.quick_resume = FALSE;
+
+ TapeAppendRecording();
+ TapeTogglePause(toggle_manual);
+ }
+ }
}
void TapeStartPlaying()
if (!TAPE_IS_STOPPED(tape))
TapeStop();
- tape.counter = 0;
- tape.delay_played = 0;
- tape.pause_before_death = FALSE;
- tape.recording = FALSE;
+ TapeRewind();
+
tape.playing = TRUE;
- tape.pausing = FALSE;
- tape.fast_forward = FALSE;
- InitRND(tape.random_seed);
DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
+ MapTapeIndexButton();
+
+ SetDrawDeactivationMask(REDRAW_NONE);
+ audio.sound_deactivated = FALSE;
+}
+
+static void TapeStartGamePlaying()
+{
+ TapeStartPlaying();
+
+ game_status = PLAYING;
+ StopAnimation();
+ InitGame();
}
void TapeStopPlaying()
tape.playing = FALSE;
tape.pausing = FALSE;
- DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
-}
-#if 0
-byte *TapePlayAction()
-{
- static byte joy[MAX_PLAYERS];
- int i;
+ if (tape.index_search)
+ TapeStopIndexSearch();
- if (!tape.playing || tape.pausing)
- return(NULL);
-
- if (tape.counter >= tape.length)
- {
- TapeStop();
- return(NULL);
- }
-
- if (tape.delay_played == tape.pos[tape.counter].delay)
- {
- tape.delay_played = 0;
- tape.counter++;
-
- for(i=0; i<MAX_PLAYERS; i++)
- joy[i] = tape.pos[tape.counter-1].action[i];
- }
- else
- {
- for(i=0; i<MAX_PLAYERS; i++)
- joy[i] = 0;
- }
-
- return(joy);
+ DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
+ MapTapeEjectButton();
}
-#else
-
byte *TapePlayAction()
{
static byte action[MAX_PLAYERS];
if (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
{
- TapeTogglePause();
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
return NULL;
}
}
- if (tape.counter >= tape.length)
+ if (tape.counter >= tape.length) /* end of tape reached */
{
- TapeStop();
+ if (tape.index_search)
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
+ else
+ TapeStop();
+
return NULL;
}
return action;
}
-#endif
-
-#if 0
-boolean TapePlayDelay()
-{
- if (!tape.playing || tape.pausing)
- return(FALSE);
-
- if (tape.pause_before_death) /* STOP 10s 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 (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
- {
- TapeTogglePause();
- return(FALSE);
- }
- }
-
- if (tape.counter >= tape.length)
- {
- TapeStop();
- return(TRUE);
- }
-
- if (tape.delay_played < tape.pos[tape.counter].delay)
- {
- tape.delay_played++;
- return(TRUE);
- }
- else
- return(FALSE);
-}
-
-#else
-
-boolean TapePlayDelay()
-{
- return TRUE|FALSE; /* ...it doesn't matter at all */
-}
-#endif
void TapeStop()
{
}
}
-void TapeErase()
-{
- tape.length = 0;
-}
-
unsigned int GetTapeLength()
{
unsigned int tape_length = 0;
return(tape_length * GAME_FRAME_DELAY / 1000);
}
+static void TapeStartIndexSearch()
+{
+ tape.index_search = TRUE;
+
+ if (!tape.fast_forward || tape.pause_before_death)
+ {
+ tape.pausing = FALSE;
+
+ SetDrawDeactivationMask(REDRAW_FIELD | REDRAW_DOOR_1);
+ audio.sound_deactivated = TRUE;
+ }
+}
+
+static void TapeStopIndexSearch()
+{
+ tape.index_search = FALSE;
+
+ SetDrawDeactivationMask(REDRAW_NONE);
+ audio.sound_deactivated = FALSE;
+
+ RedrawPlayfield(TRUE, 0,0,0,0);
+ DrawGameDoorValues();
+}
+
+static void TapeSingleStep()
+{
+ if (options.network)
+ return;
+
+ if (!tape.pausing)
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
+ tape.single_step = !tape.single_step;
+}
+
+void TapeQuickSave()
+{
+ if (game_status == PLAYING)
+ {
+ 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);
+ else
+ SaveTape(tape.level_nr);
+ }
+ else if (game_status == MAINMENU)
+ Request("No game that can be saved !", REQ_CONFIRM);
+}
+
+void TapeQuickLoad()
+{
+ if (game_status == PLAYING || game_status == MAINMENU)
+ {
+ TapeStop();
+ TapeErase();
+
+ LoadTape(level_nr);
+ if (!TAPE_IS_EMPTY(tape))
+ {
+ TapeStartGamePlaying();
+ TapeStartIndexSearch();
+
+ tape.quick_resume = TRUE;
+ }
+ else
+ Request("No tape for this level !", REQ_CONFIRM);
+ }
+}
+
+
/* ---------- new tape button stuff ---------------------------------------- */
/* graphic position values for tape buttons */
#define TAPE_BUTTON_YPOS 77
#define TAPE_BUTTON_EJECT_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
+#define TAPE_BUTTON_INDEX_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)
TAPE_CTRL_ID_EJECT,
"eject tape"
},
+ {
+ TAPE_BUTTON_INDEX_XPOS, TAPE_BUTTON_YPOS,
+ TAPE_CTRL_ID_INDEX,
+ "index mark"
+ },
{
TAPE_BUTTON_STOP_XPOS, TAPE_BUTTON_YPOS,
TAPE_CTRL_ID_STOP,
gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
gd_y = DOOR_GFX_PAGEY2 + gd_yoffset;
+ if (i == TAPE_CTRL_ID_INDEX)
+ {
+ 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,
}
}
+void MapTapeEjectButton()
+{
+ UnmapGadget(tape_gadget[TAPE_CTRL_ID_INDEX]);
+ MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
+}
+
+void MapTapeIndexButton()
+{
+ UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
+ MapGadget(tape_gadget[TAPE_CTRL_ID_INDEX]);
+}
+
void MapTapeButtons()
{
int i;
for (i=0; i<NUM_TAPE_BUTTONS; i++)
- MapGadget(tape_gadget[i]);
+ if (i != TAPE_CTRL_ID_INDEX)
+ MapGadget(tape_gadget[i]);
+
+ if (tape.recording || tape.playing)
+ MapTapeIndexButton();
}
void UnmapTapeButtons()
DrawCompleteVideoDisplay();
break;
+ case TAPE_CTRL_ID_INDEX:
+ if (tape.playing)
+ TapeStartIndexSearch();
+ else if (tape.recording)
+ TapeSingleStep();
+ break;
+
case TAPE_CTRL_ID_STOP:
TapeStop();
break;
case TAPE_CTRL_ID_PAUSE:
- TapeTogglePause();
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
break;
case TAPE_CTRL_ID_RECORD:
if (TAPE_IS_STOPPED(tape))
- {
- TapeStartRecording();
-
-#if defined(PLATFORM_UNIX)
- if (options.network)
- SendToServer_StartPlaying();
- else
-#endif
- {
- game_status = PLAYING;
- StopAnimation();
- InitGame();
- }
- }
+ TapeStartGameRecording();
else if (tape.pausing)
{
if (tape.playing) /* PLAYING -> PAUSING -> RECORDING */
- {
- tape.pos[tape.counter].delay = tape.delay_played;
- tape.playing = FALSE;
- tape.recording = TRUE;
- tape.changed = TRUE;
-
- DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
- }
+ TapeAppendRecording();
else
- TapeTogglePause();
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
}
break;
if (TAPE_IS_STOPPED(tape))
{
- TapeStartPlaying();
-
- game_status = PLAYING;
- StopAnimation();
- InitGame();
+ TapeStartGamePlaying();
}
else if (tape.playing)
{
if (tape.pausing) /* PAUSE -> PLAY */
- TapeTogglePause();
+ {
+ 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 */
+ else if (!tape.pause_before_death) /* FFWD PLAY -> AUTO PAUSE */
{
tape.pause_before_death = TRUE;
DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
}
- else /* -> NORMAL PLAY */
+ else /* AUTO PAUSE -> NORMAL PLAY */
{
tape.fast_forward = FALSE;
tape.pause_before_death = FALSE;
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "main.h"
-#define TAPE_PAUSE_SECONDS_BEFORE_DEATH 3
+
+/* values for TapeTogglePause() */
+#define TAPE_TOGGLE_MANUAL TRUE
+#define TAPE_TOGGLE_AUTOMATIC FALSE
/* some positions in the video tape control window */
#define VIDEO_DISPLAY1_XPOS 5
void DrawCompleteVideoDisplay(void);
void TapeStartRecording(void);
+void TapeHaltRecording(void);
void TapeStopRecording(void);
void TapeRecordAction(byte *);
-void TapeRecordDelay(void);
-void TapeTogglePause(void);
+void TapeTogglePause(boolean);
void TapeStartPlaying(void);
void TapeStopPlaying(void);
byte *TapePlayAction(void);
-boolean TapePlayDelay(void);
void TapeStop(void);
void TapeErase(void);
unsigned int GetTapeLength(void);
+void TapeQuickSave(void);
+void TapeQuickLoad(void);
void CreateTapeButtons();
+void MapTapeEjectButton();
+void MapTapeIndexButton();
void MapTapeButtons();
void UnmapTapeButtons();
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
* tools.c *
***********************************************************/
-#include <stdarg.h>
-
-#if defined(PLATFORM_FREEBSD)
-#include <machine/joystick.h>
-#endif
-
#include "libgame/libgame.h"
#include "tools.h"
#include "game.h"
#include "events.h"
-#include "joystick.h"
#include "cartoons.h"
#include "network.h"
#include "tape.h"
-#if defined(PLATFORM_MSDOS)
-extern boolean wait_for_vsync;
-#endif
-
/* tool button identifiers */
#define TOOL_CTRL_ID_YES 0
#define TOOL_CTRL_ID_NO 1
}
}
+void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
+{
+ if (game_status == PLAYING)
+ {
+ if (force_redraw)
+ {
+ x = gfx.sx - TILEX;
+ y = gfx.sy - TILEY;
+ width = gfx.sxsize + 2 * TILEX;
+ height = gfx.sysize + 2 * TILEY;
+ }
+
+ if (force_redraw || setup.direct_draw)
+ {
+ int xx, yy;
+ int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
+ int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
+
+ if (setup.direct_draw)
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+ 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.direct_draw)
+ SetDrawtoField(DRAW_DIRECT);
+ }
+
+ 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);
+ }
+ }
+
+ BlitBitmap(drawto, window, x, y, width, height, x, y);
+}
+
void BackToFront()
{
int x,y;
if (redraw_mask & REDRAW_FIELD)
redraw_mask &= ~REDRAW_TILES;
- if (!redraw_mask)
+ if (redraw_mask == REDRAW_NONE)
return;
if (global.fps_slowdown && game_status == PLAYING)
for(y=0; y<MAX_BUF_YSIZE; y++)
redraw[x][y] = 0;
redraw_tiles = 0;
- redraw_mask = 0;
+ redraw_mask = REDRAW_NONE;
}
void FadeToFront()
return 0;
}
+#define MAX_REQUEST_LINES 13
+#define MAX_REQUEST_LINE_LEN 7
+
boolean Request(char *text, unsigned int req_state)
{
int mx, my, ty, result = -1;
ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
/* write text for request */
- for(ty=0; ty<13; ty++)
+ for(ty=0; ty < MAX_REQUEST_LINES; ty++)
{
+ char text_line[MAX_REQUEST_LINE_LEN + 1];
int tx, tl, tc;
- char txt[256];
if (!*text)
break;
- for(tl=0,tx=0; tx<7; tl++,tx++)
+ for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
{
tc = *(text + tx);
- if (!tc || tc == 32)
+ if (!tc || tc == ' ')
break;
}
+
if (!tl)
{
text++;
ty--;
continue;
}
- sprintf(txt, text);
- txt[tl] = 0;
- DrawTextExt(drawto, DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
- txt, FS_SMALL, FC_YELLOW);
- text += tl + (tc == 32 ? 1 : 0);
+
+ strncpy(text_line, text, tl);
+ text_line[tl] = 0;
+
+ DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
+ text_line, FS_SMALL, FC_YELLOW);
+
+ text += tl + (tc == ' ' ? 1 : 0);
}
if (req_state & REQ_ASK)
break;
case EVENT_KEYRELEASE:
- key_joystick_mapping = 0;
+ ClearPlayerAction();
break;
default:
unsigned int GetDoorState()
{
- return(MoveDoor(DOOR_GET_STATE));
+ 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)
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 (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)
{
stepsize = 20;
door_delay_value = 0;
- StopSound(SND_OEFFNEN);
+ StopSound(SND_MENU_DOOR_OPENING);
+ StopSound(SND_MENU_DOOR_CLOSING);
}
if (door_state & DOOR_ACTION)
{
if (!(door_state & DOOR_NO_DELAY))
- PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
+ {
+ /* opening door sound has priority over simultaneously closing door */
+ if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
+ PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
+ else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
+ PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
+ }
start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
}
if (setup.quick_doors)
- StopSound(SND_OEFFNEN);
+ {
+ StopSound(SND_MENU_DOOR_OPENING);
+ StopSound(SND_MENU_DOOR_CLOSING);
+ }
if (door_state & DOOR_ACTION_1)
door1 = door_state & DOOR_ACTION_1;
}
};
-#if 0
-static void DoNotDisplayInfoText(void *ptr)
-{
- return;
-}
-#endif
-
void CreateToolButtons()
{
int i;
GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
GDI_DECORATION_SHIFTING, 1, 1,
GDI_EVENT_MASK, event_mask,
-
-#if 0
- GDI_CALLBACK_INFO, DoNotDisplayInfoText,
-#endif
-
GDI_CALLBACK_ACTION, HandleToolButtons,
GDI_END);
/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment *
+* (c) 1995-2002 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#ifndef TOOLS_H
#define TOOLS_H
-#include <sys/time.h>
#include "main.h"
/* for SetDrawtoField */
#define DOOR_COPY_BACK (1 << 4)
#define DOOR_NO_DELAY (1 << 5)
#define DOOR_GET_STATE (1 << 6)
+#define DOOR_SET_STATE (1 << 7)
/* for Request */
#define REQ_ASK (1 << 0)
#define REQUEST_WAIT_FOR (REQ_ASK | REQ_CONFIRM | REQ_PLAYER)
void SetDrawtoField(int);
+void RedrawPlayfield(boolean, int, int, int, int);
void BackToFront();
void FadeToFront();
void ClearWindow();
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();