OpenTyrian: Sources uploaded
git-svn-id: svn://kolibrios.org@9169 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[*.sln]
|
||||
charset = utf-8-bom
|
||||
indent_style = tab
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{vcxproj,props.template}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
[*.rc]
|
||||
charset = latin1
|
||||
end_of_line = crlf
|
||||
@@ -0,0 +1,36 @@
|
||||
/data/
|
||||
|
||||
opentyrian.cfg
|
||||
tyrian.cfg
|
||||
tyrian.sav
|
||||
|
||||
# Text editor detritus
|
||||
*~
|
||||
*.swp
|
||||
|
||||
# Make build output
|
||||
/obj/
|
||||
/src/*.gch
|
||||
/opentyrian
|
||||
|
||||
# Windows build output
|
||||
/opentyrian.exe
|
||||
/SDL.dll
|
||||
/SDL_net.dll
|
||||
|
||||
# Windows runtime output
|
||||
/stderr.txt
|
||||
/stdout.txt
|
||||
|
||||
# MSVC build output and project
|
||||
/opentyrian-*.exe
|
||||
/opentyrian-*.ilk
|
||||
/opentyrian-*.pdb
|
||||
/opentyrian-*.iobj
|
||||
/opentyrian-*.ipdb
|
||||
/visualc/.vs/
|
||||
/visualc/*.props
|
||||
/visualc/*.user
|
||||
|
||||
# Doxygen output
|
||||
/doc/doxygen/
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
CC = kos32-gcc
|
||||
LD = kos32-ld
|
||||
OBJCOPY = kos32-objcopy
|
||||
KPACK = kpack
|
||||
|
||||
TYRIAN = opentyrian
|
||||
|
||||
SDK_DIR = $(abspath ../../sdk)
|
||||
|
||||
CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident \
|
||||
-U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -D_KOLIBRI \
|
||||
-DTYRIAN_DIR='"/kolibrios/games/tyrian"' -DSDL_strlcpy=strncpy \
|
||||
-D_GNU_SOURCE=1 -D_REENTRANT -DNDEBUG -Wno-missing-field-initializers
|
||||
|
||||
LDFLAGS = -static -S -nostdlib -T $(SDK_DIR)/sources/newlib/app.lds -Map=output.map --image-base 0 --subsystem native
|
||||
|
||||
INCLUDES = -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/SDL-1.2.2_newlib/include -Isrc
|
||||
LIBPATH = -L$(SDK_DIR)/lib -L /home/autobuild/tools/win32/mingw32/lib -L $(SDK_DIR)/lib
|
||||
|
||||
OBJS = ./src/scroller.o \
|
||||
./src/config.o \
|
||||
./src/game_menu.o \
|
||||
./src/file.o \
|
||||
./src/opentyr.o \
|
||||
./src/sndmast.o \
|
||||
./src/sizebuf.o \
|
||||
./src/video_scale.o \
|
||||
./src/loudness.o \
|
||||
./src/palette.o \
|
||||
./src/joystick.o \
|
||||
./src/lds_play.o \
|
||||
./src/font.o \
|
||||
./src/config_file.o \
|
||||
./src/network.o \
|
||||
./src/helptext.o \
|
||||
./src/xmas.o \
|
||||
./src/keyboard.o \
|
||||
./src/jukebox.o \
|
||||
./src/picload.o \
|
||||
./src/shots.o \
|
||||
./src/setup.o \
|
||||
./src/mouse.o \
|
||||
./src/musmast.o \
|
||||
./src/nortvars.o \
|
||||
./src/backgrnd.o \
|
||||
./src/destruct.o \
|
||||
./src/lvllib.o \
|
||||
./src/video_scale_hqNx.o \
|
||||
./src/std_support.o \
|
||||
./src/mtrand.o \
|
||||
./src/sprite.o \
|
||||
./src/episodes.o \
|
||||
./src/arg_parse.o \
|
||||
./src/opl.o \
|
||||
./src/video.o \
|
||||
./src/editship.o \
|
||||
./src/vga_palette.o \
|
||||
./src/pcxload.o \
|
||||
./src/fonthand.o \
|
||||
./src/mainint.o \
|
||||
./src/tyrian2.o \
|
||||
./src/lvlmast.o \
|
||||
./src/animlib.o \
|
||||
./src/pcxmast.o \
|
||||
./src/menus.o \
|
||||
./src/starlib.o \
|
||||
./src/player.o \
|
||||
./src/nortsong.o \
|
||||
./src/vga256d.o \
|
||||
./src/varz.o \
|
||||
./src/params.o \
|
||||
./SDL/joystick_stub.o \
|
||||
./SDL/SDL_wave.o \
|
||||
./SDL/SDL_audiocvt.o \
|
||||
./SDL/uSDL.o
|
||||
|
||||
LIBS = -lgcc -lSDLn -lsound -lc.dll
|
||||
|
||||
$(TYRIAN): $(OBJS)
|
||||
$(LD) $(LDFLAGS) $(LIBPATH) $(OBJS) -o $(TYRIAN) $(LIBS)
|
||||
$(OBJCOPY) $(TYRIAN) -O binary
|
||||
$(KPACK) --nologo $(TYRIAN)
|
||||
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm src/*.o
|
||||
@@ -0,0 +1,141 @@
|
||||
# BUILD SETTINGS ###############################################################
|
||||
|
||||
ifneq ($(filter Msys Cygwin, $(shell uname -o)), )
|
||||
PLATFORM := WIN32
|
||||
TYRIAN_DIR = C:\\TYRIAN
|
||||
else
|
||||
PLATFORM := UNIX
|
||||
TYRIAN_DIR = $(gamesdir)/tyrian
|
||||
endif
|
||||
|
||||
WITH_NETWORK := true
|
||||
|
||||
################################################################################
|
||||
|
||||
# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
CC ?= gcc
|
||||
INSTALL ?= install
|
||||
PKG_CONFIG ?= pkg-config
|
||||
|
||||
VCS_IDREV ?= (git describe --tags || git rev-parse --short HEAD)
|
||||
|
||||
INSTALL_PROGRAM ?= $(INSTALL)
|
||||
INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
|
||||
prefix ?= /usr/local
|
||||
exec_prefix ?= $(prefix)
|
||||
|
||||
bindir ?= $(exec_prefix)/bin
|
||||
datarootdir ?= $(prefix)/share
|
||||
datadir ?= $(datarootdir)
|
||||
docdir ?= $(datarootdir)/doc/opentyrian
|
||||
mandir ?= $(datarootdir)/man
|
||||
man6dir ?= $(mandir)/man6
|
||||
man6ext ?= .6
|
||||
|
||||
# see http://www.pathname.com/fhs/pub/fhs-2.3.html
|
||||
|
||||
gamesdir ?= $(datadir)/games
|
||||
|
||||
###
|
||||
|
||||
TARGET := opentyrian
|
||||
|
||||
SRCS := $(wildcard src/*.c)
|
||||
OBJS := $(SRCS:src/%.c=obj/%.o)
|
||||
DEPS := $(SRCS:src/%.c=obj/%.d)
|
||||
|
||||
###
|
||||
|
||||
ifeq ($(WITH_NETWORK), true)
|
||||
EXTRA_CPPFLAGS += -DWITH_NETWORK
|
||||
endif
|
||||
|
||||
OPENTYRIAN_VERSION := $(shell $(VCS_IDREV) 2>/dev/null && \
|
||||
touch src/opentyrian_version.h)
|
||||
ifneq ($(OPENTYRIAN_VERSION), )
|
||||
EXTRA_CPPFLAGS += -DOPENTYRIAN_VERSION='"$(OPENTYRIAN_VERSION)"'
|
||||
endif
|
||||
|
||||
CPPFLAGS := -DNDEBUG
|
||||
CFLAGS := -pedantic
|
||||
CFLAGS += -MMD
|
||||
CFLAGS += -Wall \
|
||||
-Wextra \
|
||||
-Wno-missing-field-initializers
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -DuSDL_Delay=SDL_Delay
|
||||
|
||||
LDFLAGS :=
|
||||
LDLIBS :=
|
||||
|
||||
ifeq ($(WITH_NETWORK), true)
|
||||
SDL_CPPFLAGS := $(shell $(PKG_CONFIG) sdl SDL_net --cflags)
|
||||
SDL_LDFLAGS := $(shell $(PKG_CONFIG) sdl SDL_net --libs-only-L --libs-only-other)
|
||||
SDL_LDLIBS := $(shell $(PKG_CONFIG) sdl SDL_net --libs-only-l)
|
||||
else
|
||||
SDL_CPPFLAGS := $(shell $(PKG_CONFIG) sdl --cflags)
|
||||
SDL_LDFLAGS := $(shell $(PKG_CONFIG) sdl --libs-only-L --libs-only-other)
|
||||
SDL_LDLIBS := $(shell $(PKG_CONFIG) sdl --libs-only-l)
|
||||
endif
|
||||
|
||||
ALL_CPPFLAGS = -DTARGET_$(PLATFORM) \
|
||||
-DTYRIAN_DIR='"$(TYRIAN_DIR)"' \
|
||||
$(EXTRA_CPPFLAGS) \
|
||||
$(SDL_CPPFLAGS) \
|
||||
$(CPPFLAGS)
|
||||
ALL_CFLAGS = -std=iso9899:1999 \
|
||||
$(CFLAGS)
|
||||
ALL_LDFLAGS = $(SDL_LDFLAGS) \
|
||||
$(LDFLAGS)
|
||||
ALL_LDLIBS = -lm \
|
||||
$(SDL_LDLIBS) \
|
||||
$(LDLIBS)
|
||||
|
||||
###
|
||||
|
||||
.PHONY : all
|
||||
all : $(TARGET)
|
||||
|
||||
.PHONY : debug
|
||||
debug : CPPFLAGS += -UNDEBUG
|
||||
debug : CFLAGS += -Werror
|
||||
debug : CFLAGS += -O0
|
||||
debug : CFLAGS += -g3
|
||||
debug : all
|
||||
|
||||
.PHONY : installdirs
|
||||
installdirs :
|
||||
mkdir -p $(DESTDIR)$(bindir)
|
||||
mkdir -p $(DESTDIR)$(docdir)
|
||||
mkdir -p $(DESTDIR)$(man6dir)
|
||||
|
||||
.PHONY : install
|
||||
install : $(TARGET) installdirs
|
||||
$(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(bindir)/
|
||||
$(INSTALL_DATA) CREDITS NEWS README $(DESTDIR)$(docdir)/
|
||||
$(INSTALL_DATA) linux/man/opentyrian.6 $(DESTDIR)$(man6dir)/opentyrian$(man6ext)
|
||||
|
||||
.PHONY : uninstall
|
||||
uninstall :
|
||||
rm -f $(DESTDIR)$(bindir)/$(TARGET)
|
||||
rm -f $(DESTDIR)$(docdir)/{CREDITS,NEWS,README}
|
||||
rm -f $(DESTDIR)$(man6dir)/opentyrian$(man6ext)
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm -f $(OBJS)
|
||||
rm -f $(DEPS)
|
||||
rm -f $(TARGET)
|
||||
|
||||
$(TARGET) : $(OBJS)
|
||||
$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(ALL_LDLIBS)
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
obj/%.o : src/%.c
|
||||
@mkdir -p "$(dir $@)"
|
||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c -o $@ $<
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@devolution.com
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id: SDL_audiocvt.c,v 1.2 2001/04/26 16:50:17 hercules Exp $";
|
||||
#endif
|
||||
|
||||
/* Functions for audio drivers to perform runtime conversion of audio format */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_audio.h"
|
||||
|
||||
|
||||
/* Effectively mix right and left channels into a single channel */
|
||||
void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Sint32 sample;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting to mono\n");
|
||||
#endif
|
||||
switch (format&0x8018) {
|
||||
|
||||
case AUDIO_U8: {
|
||||
Uint8 *src, *dst;
|
||||
|
||||
src = cvt->buf;
|
||||
dst = cvt->buf;
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
sample = src[0] + src[1];
|
||||
if ( sample > 255 ) {
|
||||
*dst = 255;
|
||||
} else {
|
||||
*dst = sample;
|
||||
}
|
||||
src += 2;
|
||||
dst += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_S8: {
|
||||
Sint8 *src, *dst;
|
||||
|
||||
src = (Sint8 *)cvt->buf;
|
||||
dst = (Sint8 *)cvt->buf;
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
sample = src[0] + src[1];
|
||||
if ( sample > 127 ) {
|
||||
*dst = 127;
|
||||
} else
|
||||
if ( sample < -128 ) {
|
||||
*dst = -128;
|
||||
} else {
|
||||
*dst = sample;
|
||||
}
|
||||
src += 2;
|
||||
dst += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_U16: {
|
||||
Uint8 *src, *dst;
|
||||
|
||||
src = cvt->buf;
|
||||
dst = cvt->buf;
|
||||
if ( (format & 0x1000) == 0x1000 ) {
|
||||
for ( i=cvt->len_cvt/4; i; --i ) {
|
||||
sample = (Uint16)((src[0]<<8)|src[1])+
|
||||
(Uint16)((src[2]<<8)|src[3]);
|
||||
if ( sample > 65535 ) {
|
||||
dst[0] = 0xFF;
|
||||
dst[1] = 0xFF;
|
||||
} else {
|
||||
dst[1] = (sample&0xFF);
|
||||
sample >>= 8;
|
||||
dst[0] = (sample&0xFF);
|
||||
}
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
} else {
|
||||
for ( i=cvt->len_cvt/4; i; --i ) {
|
||||
sample = (Uint16)((src[1]<<8)|src[0])+
|
||||
(Uint16)((src[3]<<8)|src[2]);
|
||||
if ( sample > 65535 ) {
|
||||
dst[0] = 0xFF;
|
||||
dst[1] = 0xFF;
|
||||
} else {
|
||||
dst[0] = (sample&0xFF);
|
||||
sample >>= 8;
|
||||
dst[1] = (sample&0xFF);
|
||||
}
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_S16: {
|
||||
Uint8 *src, *dst;
|
||||
|
||||
src = cvt->buf;
|
||||
dst = cvt->buf;
|
||||
if ( (format & 0x1000) == 0x1000 ) {
|
||||
for ( i=cvt->len_cvt/4; i; --i ) {
|
||||
sample = (Sint16)((src[0]<<8)|src[1])+
|
||||
(Sint16)((src[2]<<8)|src[3]);
|
||||
if ( sample > 32767 ) {
|
||||
dst[0] = 0x7F;
|
||||
dst[1] = 0xFF;
|
||||
} else
|
||||
if ( sample < -32768 ) {
|
||||
dst[0] = 0x80;
|
||||
dst[1] = 0x00;
|
||||
} else {
|
||||
dst[1] = (sample&0xFF);
|
||||
sample >>= 8;
|
||||
dst[0] = (sample&0xFF);
|
||||
}
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
} else {
|
||||
for ( i=cvt->len_cvt/4; i; --i ) {
|
||||
sample = (Sint16)((src[1]<<8)|src[0])+
|
||||
(Sint16)((src[3]<<8)|src[2]);
|
||||
if ( sample > 32767 ) {
|
||||
dst[1] = 0x7F;
|
||||
dst[0] = 0xFF;
|
||||
} else
|
||||
if ( sample < -32768 ) {
|
||||
dst[1] = 0x80;
|
||||
dst[0] = 0x00;
|
||||
} else {
|
||||
dst[0] = (sample&0xFF);
|
||||
sample >>= 8;
|
||||
dst[1] = (sample&0xFF);
|
||||
}
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
cvt->len_cvt /= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Duplicate a mono channel to both stereo channels */
|
||||
void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting to stereo\n");
|
||||
#endif
|
||||
if ( (format & 0xFF) == 16 ) {
|
||||
Uint16 *src, *dst;
|
||||
|
||||
src = (Uint16 *)(cvt->buf+cvt->len_cvt);
|
||||
dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2);
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
dst -= 2;
|
||||
src -= 1;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
}
|
||||
} else {
|
||||
Uint8 *src, *dst;
|
||||
|
||||
src = cvt->buf+cvt->len_cvt;
|
||||
dst = cvt->buf+cvt->len_cvt*2;
|
||||
for ( i=cvt->len_cvt; i; --i ) {
|
||||
dst -= 2;
|
||||
src -= 1;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
}
|
||||
}
|
||||
cvt->len_cvt *= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert 8-bit to 16-bit - LSB */
|
||||
void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *src, *dst;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting to 16-bit LSB\n");
|
||||
#endif
|
||||
src = cvt->buf+cvt->len_cvt;
|
||||
dst = cvt->buf+cvt->len_cvt*2;
|
||||
for ( i=cvt->len_cvt; i; --i ) {
|
||||
src -= 1;
|
||||
dst -= 2;
|
||||
dst[1] = *src;
|
||||
dst[0] = 0;
|
||||
}
|
||||
format = ((format & ~0x0008) | AUDIO_U16LSB);
|
||||
cvt->len_cvt *= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
/* Convert 8-bit to 16-bit - MSB */
|
||||
void SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *src, *dst;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting to 16-bit MSB\n");
|
||||
#endif
|
||||
src = cvt->buf+cvt->len_cvt;
|
||||
dst = cvt->buf+cvt->len_cvt*2;
|
||||
for ( i=cvt->len_cvt; i; --i ) {
|
||||
src -= 1;
|
||||
dst -= 2;
|
||||
dst[0] = *src;
|
||||
dst[1] = 0;
|
||||
}
|
||||
format = ((format & ~0x0008) | AUDIO_U16MSB);
|
||||
cvt->len_cvt *= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert 16-bit to 8-bit */
|
||||
void SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *src, *dst;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting to 8-bit\n");
|
||||
#endif
|
||||
src = cvt->buf;
|
||||
dst = cvt->buf;
|
||||
if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
|
||||
++src;
|
||||
}
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
*dst = *src;
|
||||
src += 2;
|
||||
dst += 1;
|
||||
}
|
||||
format = ((format & ~0x9010) | AUDIO_U8);
|
||||
cvt->len_cvt /= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle signed/unsigned */
|
||||
void SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *data;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting audio signedness\n");
|
||||
#endif
|
||||
data = cvt->buf;
|
||||
if ( (format & 0xFF) == 16 ) {
|
||||
if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
|
||||
++data;
|
||||
}
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
*data ^= 0x80;
|
||||
data += 2;
|
||||
}
|
||||
} else {
|
||||
for ( i=cvt->len_cvt; i; --i ) {
|
||||
*data++ ^= 0x80;
|
||||
}
|
||||
}
|
||||
format = (format ^ 0x8000);
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle endianness */
|
||||
void SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *data, tmp;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting audio endianness\n");
|
||||
#endif
|
||||
data = cvt->buf;
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
tmp = data[0];
|
||||
data[0] = data[1];
|
||||
data[1] = tmp;
|
||||
data += 2;
|
||||
}
|
||||
format = (format ^ 0x1000);
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert rate up by multiple of 2 */
|
||||
void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *src, *dst;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting audio rate * 2\n");
|
||||
#endif
|
||||
src = cvt->buf+cvt->len_cvt;
|
||||
dst = cvt->buf+cvt->len_cvt*2;
|
||||
switch (format & 0xFF) {
|
||||
case 8:
|
||||
for ( i=cvt->len_cvt; i; --i ) {
|
||||
src -= 1;
|
||||
dst -= 2;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
src -= 2;
|
||||
dst -= 4;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
dst[3] = src[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
cvt->len_cvt *= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert rate down by multiple of 2 */
|
||||
void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
int i;
|
||||
Uint8 *src, *dst;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting audio rate / 2\n");
|
||||
#endif
|
||||
src = cvt->buf;
|
||||
dst = cvt->buf;
|
||||
switch (format & 0xFF) {
|
||||
case 8:
|
||||
for ( i=cvt->len_cvt/2; i; --i ) {
|
||||
dst[0] = src[0];
|
||||
src += 2;
|
||||
dst += 1;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
for ( i=cvt->len_cvt/4; i; --i ) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cvt->len_cvt /= 2;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
/* Very slow rate conversion routine */
|
||||
void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
|
||||
{
|
||||
double ipos;
|
||||
int i, clen;
|
||||
|
||||
#ifdef DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr);
|
||||
#endif
|
||||
clen = (int)((double)cvt->len_cvt / cvt->rate_incr);
|
||||
if ( cvt->rate_incr > 1.0 ) {
|
||||
switch (format & 0xFF) {
|
||||
case 8: {
|
||||
Uint8 *output;
|
||||
|
||||
output = cvt->buf;
|
||||
ipos = 0.0;
|
||||
for ( i=clen; i; --i ) {
|
||||
*output = cvt->buf[(int)ipos];
|
||||
ipos += cvt->rate_incr;
|
||||
output += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16: {
|
||||
Uint16 *output;
|
||||
|
||||
clen &= ~1;
|
||||
output = (Uint16 *)cvt->buf;
|
||||
ipos = 0.0;
|
||||
for ( i=clen/2; i; --i ) {
|
||||
*output=((Uint16 *)cvt->buf)[(int)ipos];
|
||||
ipos += cvt->rate_incr;
|
||||
output += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (format & 0xFF) {
|
||||
case 8: {
|
||||
Uint8 *output;
|
||||
|
||||
output = cvt->buf+clen;
|
||||
ipos = (double)cvt->len_cvt;
|
||||
for ( i=clen; i; --i ) {
|
||||
ipos -= cvt->rate_incr;
|
||||
output -= 1;
|
||||
*output = cvt->buf[(int)ipos];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16: {
|
||||
Uint16 *output;
|
||||
|
||||
clen &= ~1;
|
||||
output = (Uint16 *)(cvt->buf+clen);
|
||||
ipos = (double)cvt->len_cvt/2;
|
||||
for ( i=clen/2; i; --i ) {
|
||||
ipos -= cvt->rate_incr;
|
||||
output -= 1;
|
||||
*output=((Uint16 *)cvt->buf)[(int)ipos];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cvt->len_cvt = clen;
|
||||
if ( cvt->filters[++cvt->filter_index] ) {
|
||||
cvt->filters[cvt->filter_index](cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
int SDL_ConvertAudio(SDL_AudioCVT *cvt)
|
||||
{
|
||||
/* Make sure there's data to convert */
|
||||
if ( cvt->buf == NULL ) {
|
||||
SDL_SetError("No buffer allocated for conversion");
|
||||
return(-1);
|
||||
}
|
||||
/* Return okay if no conversion is necessary */
|
||||
cvt->len_cvt = cvt->len;
|
||||
if ( cvt->filters[0] == NULL ) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Set up the conversion and go! */
|
||||
cvt->filter_index = 0;
|
||||
cvt->filters[0](cvt, cvt->src_format);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Creates a set of audio filters to convert from one format to another.
|
||||
Returns -1 if the format conversion is not supported, or 1 if the
|
||||
audio filter is set up.
|
||||
*/
|
||||
|
||||
int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
|
||||
Uint16 src_format, Uint8 src_channels, int src_rate,
|
||||
Uint16 dst_format, Uint8 dst_channels, int dst_rate)
|
||||
{
|
||||
/* Start off with no conversion necessary */
|
||||
cvt->needed = 0;
|
||||
cvt->filter_index = 0;
|
||||
cvt->filters[0] = NULL;
|
||||
cvt->len_mult = 1;
|
||||
cvt->len_ratio = 1.0;
|
||||
|
||||
/* First filter: Endian conversion from src to dst */
|
||||
if ( (src_format & 0x1000) != (dst_format & 0x1000)
|
||||
&& ((src_format & 0xff) != 8) ) {
|
||||
cvt->filters[cvt->filter_index++] = SDL_ConvertEndian;
|
||||
}
|
||||
|
||||
/* Second filter: Sign conversion -- signed/unsigned */
|
||||
if ( (src_format & 0x8000) != (dst_format & 0x8000) ) {
|
||||
cvt->filters[cvt->filter_index++] = SDL_ConvertSign;
|
||||
}
|
||||
|
||||
/* Next filter: Convert 16 bit <--> 8 bit PCM */
|
||||
if ( (src_format & 0xFF) != (dst_format & 0xFF) ) {
|
||||
switch (dst_format&0x10FF) {
|
||||
case AUDIO_U8:
|
||||
cvt->filters[cvt->filter_index++] =
|
||||
SDL_Convert8;
|
||||
cvt->len_ratio /= 2;
|
||||
break;
|
||||
case AUDIO_U16LSB:
|
||||
cvt->filters[cvt->filter_index++] =
|
||||
SDL_Convert16LSB;
|
||||
cvt->len_mult *= 2;
|
||||
cvt->len_ratio *= 2;
|
||||
break;
|
||||
case AUDIO_U16MSB:
|
||||
cvt->filters[cvt->filter_index++] =
|
||||
SDL_Convert16MSB;
|
||||
cvt->len_mult *= 2;
|
||||
cvt->len_ratio *= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Last filter: Mono/Stereo conversion */
|
||||
if ( src_channels != dst_channels ) {
|
||||
while ( (src_channels*2) <= dst_channels ) {
|
||||
cvt->filters[cvt->filter_index++] =
|
||||
SDL_ConvertStereo;
|
||||
cvt->len_mult *= 2;
|
||||
src_channels *= 2;
|
||||
cvt->len_ratio *= 2;
|
||||
}
|
||||
/* This assumes that 4 channel audio is in the format:
|
||||
Left {front/back} + Right {front/back}
|
||||
so converting to L/R stereo works properly.
|
||||
*/
|
||||
while ( ((src_channels%2) == 0) &&
|
||||
((src_channels/2) >= dst_channels) ) {
|
||||
cvt->filters[cvt->filter_index++] =
|
||||
SDL_ConvertMono;
|
||||
src_channels /= 2;
|
||||
cvt->len_ratio /= 2;
|
||||
}
|
||||
if ( src_channels != dst_channels ) {
|
||||
/* Uh oh.. */;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do rate conversion */
|
||||
cvt->rate_incr = 0.0;
|
||||
if ( (src_rate/100) != (dst_rate/100) ) {
|
||||
Uint32 hi_rate, lo_rate;
|
||||
int len_mult;
|
||||
double len_ratio;
|
||||
void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
|
||||
|
||||
if ( src_rate > dst_rate ) {
|
||||
hi_rate = src_rate;
|
||||
lo_rate = dst_rate;
|
||||
rate_cvt = SDL_RateDIV2;
|
||||
len_mult = 1;
|
||||
len_ratio = 0.5;
|
||||
} else {
|
||||
hi_rate = dst_rate;
|
||||
lo_rate = src_rate;
|
||||
rate_cvt = SDL_RateMUL2;
|
||||
len_mult = 2;
|
||||
len_ratio = 2.0;
|
||||
}
|
||||
/* If hi_rate = lo_rate*2^x then conversion is easy */
|
||||
while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {
|
||||
cvt->filters[cvt->filter_index++] = rate_cvt;
|
||||
cvt->len_mult *= len_mult;
|
||||
lo_rate *= 2;
|
||||
cvt->len_ratio *= len_ratio;
|
||||
}
|
||||
/* We may need a slow conversion here to finish up */
|
||||
if ( (lo_rate/100) != (hi_rate/100) ) {
|
||||
#if 1
|
||||
/* The problem with this is that if the input buffer is
|
||||
say 1K, and the conversion rate is say 1.1, then the
|
||||
output buffer is 1.1K, which may not be an acceptable
|
||||
buffer size for the audio driver (not a power of 2)
|
||||
*/
|
||||
/* For now, punt and hope the rate distortion isn't great.
|
||||
*/
|
||||
#else
|
||||
if ( src_rate < dst_rate ) {
|
||||
cvt->rate_incr = (double)lo_rate/hi_rate;
|
||||
cvt->len_mult *= 2;
|
||||
cvt->len_ratio /= cvt->rate_incr;
|
||||
} else {
|
||||
cvt->rate_incr = (double)hi_rate/lo_rate;
|
||||
cvt->len_ratio *= cvt->rate_incr;
|
||||
}
|
||||
cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the filter information */
|
||||
if ( cvt->filter_index != 0 ) {
|
||||
cvt->needed = 1;
|
||||
cvt->src_format = src_format;
|
||||
cvt->dst_format = dst_format;
|
||||
cvt->len = 0;
|
||||
cvt->buf = NULL;
|
||||
cvt->filters[cvt->filter_index] = NULL;
|
||||
}
|
||||
return(cvt->needed);
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@devolution.com
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id: SDL_mixer.c,v 1.2 2001/04/26 16:50:17 hercules Exp $";
|
||||
#endif
|
||||
|
||||
/* This provides the default mixing callback for the SDL audio routines */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_mutex.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_sysaudio.h"
|
||||
|
||||
SDL_AudioDevice *current_audio = NULL;
|
||||
|
||||
/* This table is used to add two sound values together and pin
|
||||
* the value to avoid overflow. (used with permission from ARDI)
|
||||
* Changed to use 0xFE instead of 0xFF for better sound quality.
|
||||
*/
|
||||
static const Uint8 mix8[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
||||
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
|
||||
0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
|
||||
0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
|
||||
0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
|
||||
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
|
||||
0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
|
||||
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
|
||||
0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
|
||||
0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
|
||||
0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
|
||||
0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
|
||||
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
|
||||
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
|
||||
0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
|
||||
0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE
|
||||
};
|
||||
|
||||
/* The volume ranges from 0 - 128 */
|
||||
#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
|
||||
#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
|
||||
|
||||
void SDL_MixAudio (Uint8 *dst, const Uint8 *src, Uint32 len, int volume)
|
||||
{
|
||||
Uint16 format;
|
||||
|
||||
if ( volume == 0 ) {
|
||||
return;
|
||||
}
|
||||
/* Mix the user-level audio format */
|
||||
if ( current_audio ) {
|
||||
if ( current_audio->convert.needed ) {
|
||||
format = current_audio->convert.src_format;
|
||||
} else {
|
||||
format = current_audio->spec.format;
|
||||
}
|
||||
} else {
|
||||
format = AUDIO_S16;
|
||||
}
|
||||
format = AUDIO_S16;
|
||||
switch (format) {
|
||||
|
||||
case AUDIO_U8: {
|
||||
Uint8 src_sample;
|
||||
|
||||
while ( len-- ) {
|
||||
src_sample = *src;
|
||||
ADJUST_VOLUME_U8(src_sample, volume);
|
||||
*dst = mix8[*dst+src_sample];
|
||||
++dst;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_S8: {
|
||||
Sint8 *dst8, *src8;
|
||||
Sint8 src_sample;
|
||||
int dst_sample;
|
||||
const int max_audioval = ((1<<(8-1))-1);
|
||||
const int min_audioval = -(1<<(8-1));
|
||||
|
||||
src8 = (Sint8 *)src;
|
||||
dst8 = (Sint8 *)dst;
|
||||
while ( len-- ) {
|
||||
src_sample = *src8;
|
||||
ADJUST_VOLUME(src_sample, volume);
|
||||
dst_sample = *dst8 + src_sample;
|
||||
if ( dst_sample > max_audioval ) {
|
||||
*dst8 = max_audioval;
|
||||
} else
|
||||
if ( dst_sample < min_audioval ) {
|
||||
*dst8 = min_audioval;
|
||||
} else {
|
||||
*dst8 = dst_sample;
|
||||
}
|
||||
++dst8;
|
||||
++src8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_S16LSB: {
|
||||
Sint16 src1, src2;
|
||||
int dst_sample;
|
||||
const int max_audioval = ((1<<(16-1))-1);
|
||||
const int min_audioval = -(1<<(16-1));
|
||||
|
||||
len /= 2;
|
||||
while ( len-- ) {
|
||||
src1 = ((src[1])<<8|src[0]);
|
||||
ADJUST_VOLUME(src1, volume);
|
||||
src2 = ((dst[1])<<8|dst[0]);
|
||||
src += 2;
|
||||
dst_sample = src1+src2;
|
||||
if ( dst_sample > max_audioval ) {
|
||||
dst_sample = max_audioval;
|
||||
} else
|
||||
if ( dst_sample < min_audioval ) {
|
||||
dst_sample = min_audioval;
|
||||
}
|
||||
dst[0] = dst_sample&0xFF;
|
||||
dst_sample >>= 8;
|
||||
dst[1] = dst_sample&0xFF;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_S16MSB: {
|
||||
Sint16 src1, src2;
|
||||
int dst_sample;
|
||||
const int max_audioval = ((1<<(16-1))-1);
|
||||
const int min_audioval = -(1<<(16-1));
|
||||
|
||||
len /= 2;
|
||||
while ( len-- ) {
|
||||
src1 = ((src[0])<<8|src[1]);
|
||||
ADJUST_VOLUME(src1, volume);
|
||||
src2 = ((dst[0])<<8|dst[1]);
|
||||
src += 2;
|
||||
dst_sample = src1+src2;
|
||||
if ( dst_sample > max_audioval ) {
|
||||
dst_sample = max_audioval;
|
||||
} else
|
||||
if ( dst_sample < min_audioval ) {
|
||||
dst_sample = min_audioval;
|
||||
}
|
||||
dst[1] = dst_sample&0xFF;
|
||||
dst_sample >>= 8;
|
||||
dst[0] = dst_sample&0xFF;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* If this happens... FIXME! */
|
||||
SDL_SetError("SDL_MixAudio(): unknown audio format");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@devolution.com
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id: SDL_sysaudio.h,v 1.8 2001/07/23 02:58:42 slouken Exp $";
|
||||
#endif
|
||||
|
||||
#ifndef _SDL_sysaudio_h
|
||||
#define _SDL_sysaudio_h
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
#include "SDL_thread.h"
|
||||
|
||||
/* The SDL audio driver */
|
||||
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||
|
||||
/* Define the SDL audio driver structure */
|
||||
#define _THIS SDL_AudioDevice *_this
|
||||
#ifndef _STATUS
|
||||
#define _STATUS SDL_status *status
|
||||
#endif
|
||||
struct SDL_AudioDevice {
|
||||
/* * * */
|
||||
/* The name of this audio driver */
|
||||
const char *name;
|
||||
|
||||
/* * * */
|
||||
/* The description of this audio driver */
|
||||
const char *desc;
|
||||
|
||||
/* * * */
|
||||
/* Public driver functions */
|
||||
int (*OpenAudio)(_THIS, SDL_AudioSpec *spec);
|
||||
void (*ThreadInit)(_THIS); /* Called by audio thread at start */
|
||||
void (*WaitAudio)(_THIS);
|
||||
void (*PlayAudio)(_THIS);
|
||||
Uint8 *(*GetAudioBuf)(_THIS);
|
||||
void (*WaitDone)(_THIS);
|
||||
void (*CloseAudio)(_THIS);
|
||||
|
||||
/* * * */
|
||||
/* Data common to all devices */
|
||||
|
||||
/* The current audio specification (shared with audio thread) */
|
||||
SDL_AudioSpec spec;
|
||||
|
||||
/* An audio conversion block for audio format emulation */
|
||||
SDL_AudioCVT convert;
|
||||
|
||||
/* Current state flags */
|
||||
int enabled;
|
||||
int paused;
|
||||
int opened;
|
||||
|
||||
/* Fake audio buffer for when the audio hardware is busy */
|
||||
Uint8 *fake_stream;
|
||||
|
||||
/* A semaphore for locking the mixing buffers */
|
||||
SDL_mutex *mixer_lock;
|
||||
|
||||
/* A thread to feed the audio device */
|
||||
SDL_Thread *thread;
|
||||
Uint32 threadid;
|
||||
|
||||
/* * * */
|
||||
/* Data private to this driver */
|
||||
struct SDL_PrivateAudioData *hidden;
|
||||
|
||||
/* * * */
|
||||
/* The function used to dispose of this structure */
|
||||
void (*free)(_THIS);
|
||||
};
|
||||
#undef _THIS
|
||||
|
||||
typedef struct AudioBootStrap {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
int (*available)(void);
|
||||
SDL_AudioDevice *(*create)(int devindex);
|
||||
} AudioBootStrap;
|
||||
|
||||
#ifdef OPENBSD_AUDIO_SUPPORT
|
||||
extern AudioBootStrap OPENBSD_AUDIO_bootstrap;
|
||||
#endif
|
||||
#ifdef OSS_SUPPORT
|
||||
extern AudioBootStrap DSP_bootstrap;
|
||||
extern AudioBootStrap DMA_bootstrap;
|
||||
#endif
|
||||
#ifdef ALSA_SUPPORT
|
||||
extern AudioBootStrap ALSA_bootstrap;
|
||||
#endif
|
||||
#if (defined(unix) && !defined(__CYGWIN32__)) && \
|
||||
!defined(OSS_SUPPORT) && !defined(ALSA_SUPPORT)
|
||||
extern AudioBootStrap AUDIO_bootstrap;
|
||||
#endif
|
||||
#ifdef ARTSC_SUPPORT
|
||||
extern AudioBootStrap ARTSC_bootstrap;
|
||||
#endif
|
||||
#ifdef ESD_SUPPORT
|
||||
extern AudioBootStrap ESD_bootstrap;
|
||||
#endif
|
||||
#ifdef NAS_SUPPORT
|
||||
extern AudioBootStrap NAS_bootstrap;
|
||||
#endif
|
||||
#ifdef ENABLE_DIRECTX
|
||||
extern AudioBootStrap DSOUND_bootstrap;
|
||||
#endif
|
||||
#ifdef ENABLE_WINDIB
|
||||
extern AudioBootStrap WAVEOUT_bootstrap;
|
||||
#endif
|
||||
#ifdef _AIX
|
||||
extern AudioBootStrap Paud_bootstrap;
|
||||
#endif
|
||||
#ifdef __BEOS__
|
||||
extern AudioBootStrap BAUDIO_bootstrap;
|
||||
#endif
|
||||
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
||||
extern AudioBootStrap SNDMGR_bootstrap;
|
||||
#endif
|
||||
#ifdef ENABLE_AHI
|
||||
extern AudioBootStrap AHI_bootstrap;
|
||||
#endif
|
||||
#ifdef DISKAUD_SUPPORT
|
||||
extern AudioBootStrap DISKAUD_bootstrap;
|
||||
#endif
|
||||
|
||||
/* This is the current audio device */
|
||||
extern SDL_AudioDevice *current_audio;
|
||||
|
||||
#endif /* _SDL_sysaudio_h */
|
||||
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@devolution.com
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id: SDL_wave.c,v 1.2 2001/04/26 16:50:17 hercules Exp $";
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FILE
|
||||
|
||||
/* Microsoft WAVE file loading routines */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_wave.h"
|
||||
#include "SDL_endian.h"
|
||||
|
||||
#ifndef NELEMS
|
||||
#define NELEMS(array) ((sizeof array)/(sizeof array[0]))
|
||||
#endif
|
||||
|
||||
static int ReadChunk(SDL_RWops *src, Chunk *chunk);
|
||||
|
||||
struct MS_ADPCM_decodestate {
|
||||
Uint8 hPredictor;
|
||||
Uint16 iDelta;
|
||||
Sint16 iSamp1;
|
||||
Sint16 iSamp2;
|
||||
};
|
||||
static struct MS_ADPCM_decoder {
|
||||
WaveFMT wavefmt;
|
||||
Uint16 wSamplesPerBlock;
|
||||
Uint16 wNumCoef;
|
||||
Sint16 aCoeff[7][2];
|
||||
/* * * */
|
||||
struct MS_ADPCM_decodestate state[2];
|
||||
} MS_ADPCM_state;
|
||||
|
||||
static int InitMS_ADPCM(WaveFMT *format)
|
||||
{
|
||||
Uint8 *rogue_feel;
|
||||
Uint16 extra_info;
|
||||
int i;
|
||||
|
||||
/* Set the rogue pointer to the MS_ADPCM specific data */
|
||||
MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
|
||||
MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
|
||||
MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
|
||||
MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
|
||||
MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
|
||||
MS_ADPCM_state.wavefmt.bitspersample =
|
||||
SDL_SwapLE16(format->bitspersample);
|
||||
rogue_feel = (Uint8 *)format+sizeof(*format);
|
||||
if ( sizeof(*format) == 16 ) {
|
||||
extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
}
|
||||
MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
if ( MS_ADPCM_state.wNumCoef != 7 ) {
|
||||
SDL_SetError("Unknown set of MS_ADPCM coefficients");
|
||||
return(-1);
|
||||
}
|
||||
for ( i=0; i<MS_ADPCM_state.wNumCoef; ++i ) {
|
||||
MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static Sint32 MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
|
||||
Uint8 nybble, Sint16 *coeff)
|
||||
{
|
||||
const Sint32 max_audioval = ((1<<(16-1))-1);
|
||||
const Sint32 min_audioval = -(1<<(16-1));
|
||||
const Sint32 adaptive[] = {
|
||||
230, 230, 230, 230, 307, 409, 512, 614,
|
||||
768, 614, 512, 409, 307, 230, 230, 230
|
||||
};
|
||||
Sint32 new_sample, delta;
|
||||
|
||||
new_sample = ((state->iSamp1 * coeff[0]) +
|
||||
(state->iSamp2 * coeff[1]))/256;
|
||||
if ( nybble & 0x08 ) {
|
||||
new_sample += state->iDelta * (nybble-0x10);
|
||||
} else {
|
||||
new_sample += state->iDelta * nybble;
|
||||
}
|
||||
if ( new_sample < min_audioval ) {
|
||||
new_sample = min_audioval;
|
||||
} else
|
||||
if ( new_sample > max_audioval ) {
|
||||
new_sample = max_audioval;
|
||||
}
|
||||
delta = ((Sint32)state->iDelta * adaptive[nybble])/256;
|
||||
if ( delta < 16 ) {
|
||||
delta = 16;
|
||||
}
|
||||
state->iDelta = delta;
|
||||
state->iSamp2 = state->iSamp1;
|
||||
state->iSamp1 = new_sample;
|
||||
return(new_sample);
|
||||
}
|
||||
|
||||
static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len)
|
||||
{
|
||||
struct MS_ADPCM_decodestate *state[2];
|
||||
Uint8 *freeable, *encoded, *decoded;
|
||||
Sint32 encoded_len, samplesleft;
|
||||
Sint8 nybble, stereo;
|
||||
Sint16 *coeff[2];
|
||||
Sint32 new_sample;
|
||||
|
||||
/* Allocate the proper sized output buffer */
|
||||
encoded_len = *audio_len;
|
||||
encoded = *audio_buf;
|
||||
freeable = *audio_buf;
|
||||
*audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) *
|
||||
MS_ADPCM_state.wSamplesPerBlock*
|
||||
MS_ADPCM_state.wavefmt.channels*sizeof(Sint16);
|
||||
*audio_buf = (Uint8 *)malloc(*audio_len);
|
||||
if ( *audio_buf == NULL ) {
|
||||
SDL_Error(SDL_ENOMEM);
|
||||
return(-1);
|
||||
}
|
||||
decoded = *audio_buf;
|
||||
|
||||
/* Get ready... Go! */
|
||||
stereo = (MS_ADPCM_state.wavefmt.channels == 2);
|
||||
state[0] = &MS_ADPCM_state.state[0];
|
||||
state[1] = &MS_ADPCM_state.state[stereo];
|
||||
while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) {
|
||||
/* Grab the initial information for this block */
|
||||
state[0]->hPredictor = *encoded++;
|
||||
if ( stereo ) {
|
||||
state[1]->hPredictor = *encoded++;
|
||||
}
|
||||
state[0]->iDelta = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
if ( stereo ) {
|
||||
state[1]->iDelta = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
}
|
||||
state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
if ( stereo ) {
|
||||
state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
}
|
||||
state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
if ( stereo ) {
|
||||
state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += sizeof(Sint16);
|
||||
}
|
||||
coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
|
||||
coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
|
||||
|
||||
/* Store the two initial samples we start with */
|
||||
decoded[0] = state[0]->iSamp2&0xFF;
|
||||
decoded[1] = state[0]->iSamp2>>8;
|
||||
decoded += 2;
|
||||
if ( stereo ) {
|
||||
decoded[0] = state[1]->iSamp2&0xFF;
|
||||
decoded[1] = state[1]->iSamp2>>8;
|
||||
decoded += 2;
|
||||
}
|
||||
decoded[0] = state[0]->iSamp1&0xFF;
|
||||
decoded[1] = state[0]->iSamp1>>8;
|
||||
decoded += 2;
|
||||
if ( stereo ) {
|
||||
decoded[0] = state[1]->iSamp1&0xFF;
|
||||
decoded[1] = state[1]->iSamp1>>8;
|
||||
decoded += 2;
|
||||
}
|
||||
|
||||
/* Decode and store the other samples in this block */
|
||||
samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)*
|
||||
MS_ADPCM_state.wavefmt.channels;
|
||||
while ( samplesleft > 0 ) {
|
||||
nybble = (*encoded)>>4;
|
||||
new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]);
|
||||
decoded[0] = new_sample&0xFF;
|
||||
new_sample >>= 8;
|
||||
decoded[1] = new_sample&0xFF;
|
||||
decoded += 2;
|
||||
|
||||
nybble = (*encoded)&0x0F;
|
||||
new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]);
|
||||
decoded[0] = new_sample&0xFF;
|
||||
new_sample >>= 8;
|
||||
decoded[1] = new_sample&0xFF;
|
||||
decoded += 2;
|
||||
|
||||
++encoded;
|
||||
samplesleft -= 2;
|
||||
}
|
||||
encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
|
||||
}
|
||||
free(freeable);
|
||||
return(0);
|
||||
}
|
||||
|
||||
struct IMA_ADPCM_decodestate {
|
||||
Sint32 sample;
|
||||
Sint8 index;
|
||||
};
|
||||
static struct IMA_ADPCM_decoder {
|
||||
WaveFMT wavefmt;
|
||||
Uint16 wSamplesPerBlock;
|
||||
/* * * */
|
||||
struct IMA_ADPCM_decodestate state[2];
|
||||
} IMA_ADPCM_state;
|
||||
|
||||
static int InitIMA_ADPCM(WaveFMT *format)
|
||||
{
|
||||
Uint8 *rogue_feel;
|
||||
Uint16 extra_info;
|
||||
|
||||
/* Set the rogue pointer to the IMA_ADPCM specific data */
|
||||
IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
|
||||
IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
|
||||
IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
|
||||
IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
|
||||
IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
|
||||
IMA_ADPCM_state.wavefmt.bitspersample =
|
||||
SDL_SwapLE16(format->bitspersample);
|
||||
rogue_feel = (Uint8 *)format+sizeof(*format);
|
||||
if ( sizeof(*format) == 16 ) {
|
||||
extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
rogue_feel += sizeof(Uint16);
|
||||
}
|
||||
IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble)
|
||||
{
|
||||
const Sint32 max_audioval = ((1<<(16-1))-1);
|
||||
const Sint32 min_audioval = -(1<<(16-1));
|
||||
const int index_table[16] = {
|
||||
-1, -1, -1, -1,
|
||||
2, 4, 6, 8,
|
||||
-1, -1, -1, -1,
|
||||
2, 4, 6, 8
|
||||
};
|
||||
const Sint32 step_table[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
|
||||
143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
|
||||
449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
|
||||
1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
|
||||
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
|
||||
9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
|
||||
22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
Sint32 delta, step;
|
||||
|
||||
/* Compute difference and new sample value */
|
||||
step = step_table[state->index];
|
||||
delta = step >> 3;
|
||||
if ( nybble & 0x04 ) delta += step;
|
||||
if ( nybble & 0x02 ) delta += (step >> 1);
|
||||
if ( nybble & 0x01 ) delta += (step >> 2);
|
||||
if ( nybble & 0x08 ) delta = -delta;
|
||||
state->sample += delta;
|
||||
|
||||
/* Update index value */
|
||||
state->index += index_table[nybble];
|
||||
if ( state->index > 88 ) {
|
||||
state->index = 88;
|
||||
} else
|
||||
if ( state->index < 0 ) {
|
||||
state->index = 0;
|
||||
}
|
||||
|
||||
/* Clamp output sample */
|
||||
if ( state->sample > max_audioval ) {
|
||||
state->sample = max_audioval;
|
||||
} else
|
||||
if ( state->sample < min_audioval ) {
|
||||
state->sample = min_audioval;
|
||||
}
|
||||
return(state->sample);
|
||||
}
|
||||
|
||||
/* Fill the decode buffer with a channel block of data (8 samples) */
|
||||
static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded,
|
||||
int channel, int numchannels, struct IMA_ADPCM_decodestate *state)
|
||||
{
|
||||
int i;
|
||||
Sint8 nybble;
|
||||
Sint32 new_sample;
|
||||
|
||||
decoded += (channel * 2);
|
||||
for ( i=0; i<4; ++i ) {
|
||||
nybble = (*encoded)&0x0F;
|
||||
new_sample = IMA_ADPCM_nibble(state, nybble);
|
||||
decoded[0] = new_sample&0xFF;
|
||||
new_sample >>= 8;
|
||||
decoded[1] = new_sample&0xFF;
|
||||
decoded += 2 * numchannels;
|
||||
|
||||
nybble = (*encoded)>>4;
|
||||
new_sample = IMA_ADPCM_nibble(state, nybble);
|
||||
decoded[0] = new_sample&0xFF;
|
||||
new_sample >>= 8;
|
||||
decoded[1] = new_sample&0xFF;
|
||||
decoded += 2 * numchannels;
|
||||
|
||||
++encoded;
|
||||
}
|
||||
}
|
||||
|
||||
static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len)
|
||||
{
|
||||
struct IMA_ADPCM_decodestate *state;
|
||||
Uint8 *freeable, *encoded, *decoded;
|
||||
Sint32 encoded_len, samplesleft;
|
||||
int c, channels;
|
||||
|
||||
/* Check to make sure we have enough variables in the state array */
|
||||
channels = IMA_ADPCM_state.wavefmt.channels;
|
||||
if ( channels > NELEMS(IMA_ADPCM_state.state) ) {
|
||||
SDL_SetError("IMA ADPCM decoder can only handle %d channels",
|
||||
NELEMS(IMA_ADPCM_state.state));
|
||||
return(-1);
|
||||
}
|
||||
state = IMA_ADPCM_state.state;
|
||||
|
||||
/* Allocate the proper sized output buffer */
|
||||
encoded_len = *audio_len;
|
||||
encoded = *audio_buf;
|
||||
freeable = *audio_buf;
|
||||
*audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) *
|
||||
IMA_ADPCM_state.wSamplesPerBlock*
|
||||
IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16);
|
||||
*audio_buf = (Uint8 *)malloc(*audio_len);
|
||||
if ( *audio_buf == NULL ) {
|
||||
SDL_Error(SDL_ENOMEM);
|
||||
return(-1);
|
||||
}
|
||||
decoded = *audio_buf;
|
||||
|
||||
/* Get ready... Go! */
|
||||
while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) {
|
||||
/* Grab the initial information for this block */
|
||||
for ( c=0; c<channels; ++c ) {
|
||||
/* Fill the state information for this block */
|
||||
state[c].sample = ((encoded[1]<<8)|encoded[0]);
|
||||
encoded += 2;
|
||||
if ( state[c].sample & 0x8000 ) {
|
||||
state[c].sample -= 0x10000;
|
||||
}
|
||||
state[c].index = *encoded++;
|
||||
/* Reserved byte in buffer header, should be 0 */
|
||||
if ( *encoded++ != 0 ) {
|
||||
/* Uh oh, corrupt data? Buggy code? */;
|
||||
}
|
||||
|
||||
/* Store the initial sample we start with */
|
||||
decoded[0] = state[c].sample&0xFF;
|
||||
decoded[1] = state[c].sample>>8;
|
||||
decoded += 2;
|
||||
}
|
||||
|
||||
/* Decode and store the other samples in this block */
|
||||
samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels;
|
||||
while ( samplesleft > 0 ) {
|
||||
for ( c=0; c<channels; ++c ) {
|
||||
Fill_IMA_ADPCM_block(decoded, encoded,
|
||||
c, channels, &state[c]);
|
||||
encoded += 4;
|
||||
samplesleft -= 8;
|
||||
}
|
||||
decoded += (channels * 8 * 2);
|
||||
}
|
||||
encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
|
||||
}
|
||||
free(freeable);
|
||||
return(0);
|
||||
}
|
||||
|
||||
SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc,
|
||||
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
|
||||
{
|
||||
int was_error;
|
||||
Chunk chunk;
|
||||
int lenread;
|
||||
int MS_ADPCM_encoded, IMA_ADPCM_encoded;
|
||||
int samplesize;
|
||||
|
||||
/* WAV magic header */
|
||||
Uint32 RIFFchunk;
|
||||
Uint32 wavelen;
|
||||
Uint32 WAVEmagic;
|
||||
|
||||
/* FMT chunk */
|
||||
WaveFMT *format = NULL;
|
||||
|
||||
/* Make sure we are passed a valid data source */
|
||||
was_error = 0;
|
||||
if ( src == NULL ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check the magic header */
|
||||
RIFFchunk = SDL_ReadLE32(src);
|
||||
wavelen = SDL_ReadLE32(src);
|
||||
WAVEmagic = SDL_ReadLE32(src);
|
||||
if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
|
||||
SDL_SetError("Unrecognized file type (not WAVE)");
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Read the audio data format chunk */
|
||||
chunk.data = NULL;
|
||||
do {
|
||||
if ( chunk.data != NULL ) {
|
||||
free(chunk.data);
|
||||
}
|
||||
lenread = ReadChunk(src, &chunk);
|
||||
if ( lenread < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
} while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
|
||||
|
||||
/* Decode the audio data format */
|
||||
format = (WaveFMT *)chunk.data;
|
||||
if ( chunk.magic != FMT ) {
|
||||
SDL_SetError("Complex WAVE files not supported");
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
|
||||
switch (SDL_SwapLE16(format->encoding)) {
|
||||
case PCM_CODE:
|
||||
/* We can understand this */
|
||||
break;
|
||||
case MS_ADPCM_CODE:
|
||||
/* Try to understand this */
|
||||
if ( InitMS_ADPCM(format) < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
MS_ADPCM_encoded = 1;
|
||||
break;
|
||||
case IMA_ADPCM_CODE:
|
||||
/* Try to understand this */
|
||||
if ( InitIMA_ADPCM(format) < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
IMA_ADPCM_encoded = 1;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown WAVE data format: 0x%.4x",
|
||||
SDL_SwapLE16(format->encoding));
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
memset(spec, 0, (sizeof *spec));
|
||||
spec->freq = SDL_SwapLE32(format->frequency);
|
||||
switch (SDL_SwapLE16(format->bitspersample)) {
|
||||
case 4:
|
||||
if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) {
|
||||
spec->format = AUDIO_S16;
|
||||
} else {
|
||||
was_error = 1;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
spec->format = AUDIO_U8;
|
||||
break;
|
||||
case 16:
|
||||
spec->format = AUDIO_S16;
|
||||
break;
|
||||
default:
|
||||
was_error = 1;
|
||||
break;
|
||||
}
|
||||
if ( was_error ) {
|
||||
SDL_SetError("Unknown %d-bit PCM data format",
|
||||
SDL_SwapLE16(format->bitspersample));
|
||||
goto done;
|
||||
}
|
||||
spec->channels = (Uint8)SDL_SwapLE16(format->channels);
|
||||
spec->samples = 4096; /* Good default buffer size */
|
||||
|
||||
/* Read the audio data chunk */
|
||||
*audio_buf = NULL;
|
||||
do {
|
||||
if ( *audio_buf != NULL ) {
|
||||
free(*audio_buf);
|
||||
}
|
||||
lenread = ReadChunk(src, &chunk);
|
||||
if ( lenread < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
*audio_len = lenread;
|
||||
*audio_buf = chunk.data;
|
||||
} while ( chunk.magic != DATA );
|
||||
|
||||
if ( MS_ADPCM_encoded ) {
|
||||
if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ( IMA_ADPCM_encoded ) {
|
||||
if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) {
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't return a buffer that isn't a multiple of samplesize */
|
||||
samplesize = ((spec->format & 0xFF)/8)*spec->channels;
|
||||
*audio_len &= ~(samplesize-1);
|
||||
|
||||
done:
|
||||
if ( format != NULL ) {
|
||||
free(format);
|
||||
}
|
||||
if ( freesrc && src ) {
|
||||
SDL_RWclose(src);
|
||||
}
|
||||
if ( was_error ) {
|
||||
spec = NULL;
|
||||
}
|
||||
return(spec);
|
||||
}
|
||||
|
||||
/* Since the WAV memory is allocated in the shared library, it must also
|
||||
be freed here. (Necessary under Win32, VC++)
|
||||
*/
|
||||
void SDL_FreeWAV(Uint8 *audio_buf)
|
||||
{
|
||||
if ( audio_buf != NULL ) {
|
||||
free(audio_buf);
|
||||
}
|
||||
}
|
||||
|
||||
static int ReadChunk(SDL_RWops *src, Chunk *chunk)
|
||||
{
|
||||
chunk->magic = SDL_ReadLE32(src);
|
||||
chunk->length = SDL_ReadLE32(src);
|
||||
chunk->data = (Uint8 *)malloc(chunk->length);
|
||||
if ( chunk->data == NULL ) {
|
||||
SDL_Error(SDL_ENOMEM);
|
||||
return(-1);
|
||||
}
|
||||
if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
|
||||
SDL_Error(SDL_EFREAD);
|
||||
free(chunk->data);
|
||||
return(-1);
|
||||
}
|
||||
return(chunk->length);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_FILE */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@devolution.com
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id: SDL_wave.h,v 1.2 2001/04/26 16:50:17 hercules Exp $";
|
||||
#endif
|
||||
|
||||
/* WAVE files are little-endian */
|
||||
|
||||
/*******************************************/
|
||||
/* Define values for Microsoft WAVE format */
|
||||
/*******************************************/
|
||||
#define RIFF 0x46464952 /* "RIFF" */
|
||||
#define WAVE 0x45564157 /* "WAVE" */
|
||||
#define FACT 0x74636166 /* "fact" */
|
||||
#define LIST 0x5453494c /* "LIST" */
|
||||
#define FMT 0x20746D66 /* "fmt " */
|
||||
#define DATA 0x61746164 /* "data" */
|
||||
#define PCM_CODE 0x0001
|
||||
#define MS_ADPCM_CODE 0x0002
|
||||
#define IMA_ADPCM_CODE 0x0011
|
||||
#define WAVE_MONO 1
|
||||
#define WAVE_STEREO 2
|
||||
|
||||
/* Normally, these three chunks come consecutively in a WAVE file */
|
||||
typedef struct WaveFMT {
|
||||
/* Not saved in the chunk we read:
|
||||
Uint32 FMTchunk;
|
||||
Uint32 fmtlen;
|
||||
*/
|
||||
Uint16 encoding;
|
||||
Uint16 channels; /* 1 = mono, 2 = stereo */
|
||||
Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
|
||||
Uint32 byterate; /* Average bytes per second */
|
||||
Uint16 blockalign; /* Bytes per sample block */
|
||||
Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
|
||||
} WaveFMT;
|
||||
|
||||
/* The general chunk found in the WAVE file */
|
||||
typedef struct Chunk {
|
||||
Uint32 magic;
|
||||
Uint32 length;
|
||||
Uint8 *data; /* Data includes magic and length */
|
||||
} Chunk;
|
||||
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
/// JOYSTICK STUB FOR Wolfenstein 3D port to KolibriOS
|
||||
/// Ported by maxcodehack and turbocat2001
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file SDL_joystick.h
|
||||
* @note In order to use these functions, SDL_Init() must have been called
|
||||
* with the SDL_INIT_JOYSTICK flag. This causes SDL to scan the system
|
||||
* for joysticks, and load appropriate drivers.
|
||||
*/
|
||||
|
||||
/** The joystick structure used to identify an SDL joystick */
|
||||
struct _SDL_Joystick;
|
||||
typedef struct _SDL_Joystick SDL_Joystick;
|
||||
|
||||
/* Function prototypes */
|
||||
/**
|
||||
* Count the number of joysticks attached to the system
|
||||
*/
|
||||
int SDL_NumJoysticks(void){};
|
||||
|
||||
/**
|
||||
* Get the implementation dependent name of a joystick.
|
||||
*
|
||||
* This can be called before any joysticks are opened.
|
||||
* If no name can be found, this function returns NULL.
|
||||
*/
|
||||
const char * SDL_JoystickName(int device_index){};
|
||||
|
||||
/**
|
||||
* Open a joystick for use.
|
||||
*
|
||||
* @param[in] device_index
|
||||
* The index passed as an argument refers to
|
||||
* the N'th joystick on the system. This index is the value which will
|
||||
* identify this joystick in future joystick events.
|
||||
*
|
||||
* @return This function returns a joystick identifier, or NULL if an error occurred.
|
||||
*/
|
||||
SDL_Joystick * SDL_JoystickOpen(int device_index){};
|
||||
|
||||
/**
|
||||
* Returns 1 if the joystick has been opened, or 0 if it has not.
|
||||
*/
|
||||
int SDL_JoystickOpened(int device_index){};
|
||||
|
||||
/**
|
||||
* Get the device index of an opened joystick.
|
||||
*/
|
||||
int SDL_JoystickIndex(SDL_Joystick *joystick){};
|
||||
|
||||
/**
|
||||
* Get the number of general axis controls on a joystick
|
||||
*/
|
||||
int SDL_JoystickNumAxes(SDL_Joystick *joystick){};
|
||||
|
||||
/**
|
||||
* Get the number of trackballs on a joystick
|
||||
*
|
||||
* Joystick trackballs have only relative motion events associated
|
||||
* with them and their state cannot be polled.
|
||||
*/
|
||||
int SDL_JoystickNumBalls(SDL_Joystick *joystick){};
|
||||
|
||||
/**
|
||||
* Get the number of POV hats on a joystick
|
||||
*/
|
||||
int SDL_JoystickNumHats(SDL_Joystick *joystick){};
|
||||
|
||||
/**
|
||||
* Get the number of buttons on a joystick
|
||||
*/
|
||||
int SDL_JoystickNumButtons(SDL_Joystick *joystick){};
|
||||
|
||||
/**
|
||||
* Update the current state of the open joysticks.
|
||||
*
|
||||
* This is called automatically by the event loop if any joystick
|
||||
* events are enabled.
|
||||
*/
|
||||
void SDL_JoystickUpdate(void){};
|
||||
|
||||
/**
|
||||
* Enable/disable joystick event polling.
|
||||
*
|
||||
* If joystick events are disabled, you must call SDL_JoystickUpdate()
|
||||
* yourself and check the state of the joystick when you want joystick
|
||||
* information.
|
||||
*
|
||||
* @param[in] state The state can be one of SDL_QUERY, SDL_ENABLE or SDL_IGNORE.
|
||||
*/
|
||||
int SDL_JoystickEventState(int state){};
|
||||
|
||||
/**
|
||||
* Get the current state of an axis control on a joystick
|
||||
*
|
||||
* @param[in] axis The axis indices start at index 0.
|
||||
*
|
||||
* @return The state is a value ranging from -32768 to 32767.
|
||||
*/
|
||||
int SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis){};
|
||||
|
||||
/**
|
||||
* @name Hat Positions
|
||||
* The return value of SDL_JoystickGetHat() is one of the following positions:
|
||||
*/
|
||||
/*@{*/
|
||||
#define SDL_HAT_CENTERED 0x00
|
||||
#define SDL_HAT_UP 0x01
|
||||
#define SDL_HAT_RIGHT 0x02
|
||||
#define SDL_HAT_DOWN 0x04
|
||||
#define SDL_HAT_LEFT 0x08
|
||||
#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT|SDL_HAT_UP)
|
||||
#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT|SDL_HAT_DOWN)
|
||||
#define SDL_HAT_LEFTUP (SDL_HAT_LEFT|SDL_HAT_UP)
|
||||
#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT|SDL_HAT_DOWN)
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* Get the current state of a POV hat on a joystick
|
||||
*
|
||||
* @param[in] hat The hat indices start at index 0.
|
||||
*/
|
||||
int SDL_JoystickGetHat(SDL_Joystick *joystick, int hat){};
|
||||
|
||||
/**
|
||||
* Get the ball axis change since the last poll
|
||||
*
|
||||
* @param[in] ball The ball indices start at index 0.
|
||||
*
|
||||
* @return This returns 0, or -1 if you passed it invalid parameters.
|
||||
*/
|
||||
int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy){};
|
||||
|
||||
/**
|
||||
* Get the current state of a button on a joystick
|
||||
*
|
||||
* @param[in] button The button indices start at index 0.
|
||||
*/
|
||||
int SDL_JoystickGetButton(SDL_Joystick *joystick, int button){};
|
||||
|
||||
/**
|
||||
* Close a joystick previously opened with SDL_JoystickOpen()
|
||||
*/
|
||||
void SDL_JoystickClose(SDL_Joystick *joystick){};
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <SDL.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define asm_inline __asm__ __volatile__
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef union{
|
||||
unsigned val;
|
||||
struct{
|
||||
short h;
|
||||
short w;
|
||||
};
|
||||
}ksys_screen_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static inline
|
||||
void _ksys_change_window(int new_x, int new_y, int new_w, int new_h)
|
||||
{
|
||||
asm_inline(
|
||||
"int $0x40"
|
||||
::"a"(67), "b"(new_x), "c"(new_y), "d"(new_w),"S"(new_h)
|
||||
);
|
||||
}
|
||||
|
||||
static inline
|
||||
ksys_screen_t _ksys_screen_size()
|
||||
{
|
||||
ksys_screen_t size;
|
||||
asm_inline(
|
||||
"int $0x40"
|
||||
:"=a"(size)
|
||||
:"a"(14)
|
||||
:"memory"
|
||||
);
|
||||
return size;
|
||||
}
|
||||
|
||||
void uSDL_SetWinCenter(unsigned w, unsigned h){
|
||||
ksys_screen_t screen_size= _ksys_screen_size();
|
||||
int new_x = screen_size.w/2-w/2;
|
||||
int new_y = screen_size.h/2-h/2;
|
||||
_ksys_change_window(new_x, new_y, -1, -1);
|
||||
}
|
||||
|
||||
|
||||
void uSDL_Delay(unsigned ms){
|
||||
unsigned start = SDL_GetTicks();
|
||||
do{
|
||||
asm_inline("int $0x40" :: "a"(5),"b"(1));
|
||||
}while (SDL_GetTicks()-start < ms);
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "animlib.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "keyboard.h"
|
||||
#include "network.h"
|
||||
#include "nortsong.h"
|
||||
#include "palette.h"
|
||||
#include "sizebuf.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*** Structs ***/
|
||||
/* The actual header has a lot of fields that are basically useless to us since
|
||||
* we both set our own framerate and the format itself only allows for
|
||||
* 320x200x8. Should a (nonexistent) ani be played that doesn't have the same
|
||||
* assumed values we are going to use, TOO BAD. It'll just be treated as
|
||||
* corrupt in playback.
|
||||
*/
|
||||
#define PALETTE_OFFSET 0x100 // 128 + sizeof(header)
|
||||
#define PAGEHEADER_OFFSET 0x500 // PALETTE_OFFSET + sizeof(palette)
|
||||
#define ANIM_OFFSET 0x0B00 // PAGEHEADER_OFFSET + sizeof(largepageheader) * 256
|
||||
#define ANI_PAGE_SIZE 0x10000 // 65536.
|
||||
typedef struct anim_FileHeader_s
|
||||
{
|
||||
unsigned int nlps; /* Number of 'pages', max 256. */
|
||||
unsigned int nRecords; /* Number of 'records', max 65535 */
|
||||
} anim_FileHeader_t;
|
||||
typedef struct anim_LargePageHeader_s
|
||||
{
|
||||
unsigned int baseRecord; /* The first record's number */
|
||||
unsigned int nRecords; /* Number of records. Supposedly there are bit flags but I saw no such code */
|
||||
unsigned int nBytes; /* Number of bytes used, excluding headers */
|
||||
} anim_LargePageHeader_t;
|
||||
|
||||
|
||||
/*** Globals ***/
|
||||
Uint8 CurrentPageBuffer[65536];
|
||||
anim_LargePageHeader_t PageHeader[256];
|
||||
unsigned int CurrentPageRecordSizes[256];
|
||||
|
||||
anim_LargePageHeader_t CurrentPageHeader;
|
||||
anim_FileHeader_t FileHeader;
|
||||
|
||||
unsigned int Curlpnum;
|
||||
|
||||
FILE * InFile;
|
||||
|
||||
|
||||
/*** Function decs ***/
|
||||
int JE_playRunSkipDump( Uint8 *, unsigned int );
|
||||
void JE_closeAnim( void );
|
||||
int JE_loadAnim( const char * );
|
||||
int JE_renderFrame( unsigned int );
|
||||
int JE_findPage ( unsigned int );
|
||||
int JE_drawFrame( unsigned int );
|
||||
int JE_loadPage( unsigned int );
|
||||
|
||||
/*** Implementation ***/
|
||||
|
||||
|
||||
/* Loads the given page into memory.
|
||||
*
|
||||
* Returns 0 on success or nonzero on failure (bad data)
|
||||
*/
|
||||
int JE_loadPage( unsigned int pagenumber )
|
||||
{
|
||||
unsigned int i, pageSize;
|
||||
|
||||
|
||||
if (Curlpnum == pagenumber) { return(0); } /* Already loaded */
|
||||
Curlpnum = pagenumber;
|
||||
|
||||
/* We need to seek to the page and load it into our buffer.
|
||||
* Pages have a fixed size of 0x10000; any left over space is padded
|
||||
* unless it's the end of the file.
|
||||
*
|
||||
* Pages repeat their headers for some reason. They then have two bytes of
|
||||
* padding folowed by a word for every record. THEN the data starts.
|
||||
*/
|
||||
fseek(InFile, ANIM_OFFSET + (pagenumber * ANI_PAGE_SIZE), SEEK_SET);
|
||||
efread(&CurrentPageHeader.baseRecord, 2, 1, InFile);
|
||||
efread(&CurrentPageHeader.nRecords, 2, 1, InFile);
|
||||
efread(&CurrentPageHeader.nBytes, 2, 1, InFile);
|
||||
|
||||
fseek(InFile, 2, SEEK_CUR);
|
||||
for (i = 0; i < CurrentPageHeader.nRecords; i++)
|
||||
{
|
||||
efread(&CurrentPageRecordSizes[i], 2, 1, InFile);
|
||||
}
|
||||
|
||||
/* What remains is the 'compressed' data */
|
||||
efread(CurrentPageBuffer, 1, CurrentPageHeader.nBytes, InFile);
|
||||
|
||||
/* Okay, we've succeeded in all our IO checks. Now, make sure the
|
||||
* headers aren't lying or damaged or something.
|
||||
*/
|
||||
pageSize = 0;
|
||||
for (i = 0; i < CurrentPageHeader.nRecords; i++)
|
||||
{
|
||||
pageSize += CurrentPageRecordSizes[i];
|
||||
}
|
||||
|
||||
if(pageSize != CurrentPageHeader.nBytes) { return(-1); }
|
||||
|
||||
/* So far, so good */
|
||||
return(0);
|
||||
}
|
||||
|
||||
int JE_drawFrame( unsigned int framenumber )
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
ret = JE_loadPage(framenumber);
|
||||
if (ret) { return(ret); }
|
||||
|
||||
ret = JE_renderFrame (framenumber);
|
||||
if (ret) { return(ret); }
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int JE_findPage( unsigned int framenumber )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
||||
for (i = 0; i < FileHeader.nlps; i++)
|
||||
{
|
||||
if (PageHeader[i].baseRecord <= framenumber
|
||||
&& PageHeader[i].baseRecord + PageHeader[i].nRecords > framenumber)
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
return(-1); /* Did not find */
|
||||
}
|
||||
|
||||
int JE_renderFrame( unsigned int framenumber )
|
||||
{
|
||||
unsigned int i, offset, destframe;
|
||||
|
||||
|
||||
destframe = framenumber - CurrentPageHeader.baseRecord;
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < destframe; i++)
|
||||
{
|
||||
offset += CurrentPageRecordSizes[i];
|
||||
}
|
||||
|
||||
return (JE_playRunSkipDump(CurrentPageBuffer + offset + 4, CurrentPageRecordSizes[destframe] - 4));
|
||||
}
|
||||
|
||||
void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed )
|
||||
{
|
||||
unsigned int i;
|
||||
int pageNum;
|
||||
|
||||
if (JE_loadAnim(animfile) != 0)
|
||||
{
|
||||
return; /* Failed to open or process file */
|
||||
}
|
||||
|
||||
/* Blank screen */
|
||||
JE_clr256(VGAScreen);
|
||||
JE_showVGA();
|
||||
|
||||
|
||||
/* re FileHeader.nRecords-1: It's -1 in the pascal too.
|
||||
* The final frame is a delta of the first, and we don't need that.
|
||||
* We could also, if we ever ended up needing to loop anis, check
|
||||
* the bools in the header to see if we should render the last
|
||||
* frame. But that's never going to be encessary :)
|
||||
*/
|
||||
for (i = startingframe; i < FileHeader.nRecords-1; i++)
|
||||
{
|
||||
/* Handle boring crap */
|
||||
setjasondelay(speed);
|
||||
|
||||
/* Load required frame. The loading function is smart enough to not re-load an already loaded frame */
|
||||
pageNum = JE_findPage(i);
|
||||
if(pageNum == -1) { break; }
|
||||
if (JE_loadPage(pageNum) != 0) { break; }
|
||||
|
||||
/* render frame. */
|
||||
if (JE_renderFrame(i) != 0) { break; }
|
||||
JE_showVGA();
|
||||
|
||||
|
||||
/* Return early if user presses a key */
|
||||
service_SDL_events(true);
|
||||
if (newkey)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait until we need the next frame */
|
||||
NETWORK_KEEP_ALIVE();
|
||||
wait_delay();
|
||||
}
|
||||
|
||||
JE_closeAnim();
|
||||
}
|
||||
|
||||
/* loadAnim opens the file and loads data from it into the header structs.
|
||||
* It should take care to clean up after itself should an error occur.
|
||||
*/
|
||||
int JE_loadAnim( const char *filename )
|
||||
{
|
||||
unsigned int i, fileSize;
|
||||
char temp[4];
|
||||
|
||||
|
||||
Curlpnum = -1;
|
||||
InFile = dir_fopen(data_dir(), filename, "rb");
|
||||
if(InFile == NULL)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fileSize = ftell_eof(InFile);
|
||||
if(fileSize < ANIM_OFFSET)
|
||||
{
|
||||
/* We don't know the exact size our file should be yet,
|
||||
* but we do know it should be way more than this */
|
||||
fclose(InFile);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Read in the header. The header is 256 bytes long or so,
|
||||
* but that includes a lot of padding as well as several
|
||||
* vars we really don't care about. We shall check the ID and extract
|
||||
* the handful of vars we care about. Every value in the header that
|
||||
* is constant will be ignored.
|
||||
*/
|
||||
|
||||
efread(&temp, 1, 4, InFile); /* The ID, should equal "LPF " */
|
||||
fseek(InFile, 2, SEEK_CUR); /* skip over this word */
|
||||
efread(&FileHeader.nlps, 2, 1, InFile); /* Number of pages */
|
||||
efread(&FileHeader.nRecords, 4, 1, InFile); /* Number of records */
|
||||
|
||||
if (memcmp(temp, "LPF ", 4) != 0
|
||||
|| FileHeader.nlps == 0 || FileHeader.nRecords == 0
|
||||
|| FileHeader.nlps > 256 || FileHeader.nRecords > 65535)
|
||||
{
|
||||
fclose(InFile);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Read in headers */
|
||||
fseek(InFile, PAGEHEADER_OFFSET, SEEK_SET);
|
||||
for (i = 0; i < FileHeader.nlps; i++)
|
||||
{
|
||||
efread(&PageHeader[i].baseRecord, 2, 1, InFile);
|
||||
efread(&PageHeader[i].nRecords, 2, 1, InFile);
|
||||
efread(&PageHeader[i].nBytes, 2, 1, InFile);
|
||||
}
|
||||
|
||||
|
||||
/* Now we have enough information to calculate the 'expected' file size.
|
||||
* Our calculation SHOULD be equal to fileSize, but we won't begrudge
|
||||
* padding */
|
||||
if (fileSize < (FileHeader.nlps-1) * ANI_PAGE_SIZE + ANIM_OFFSET
|
||||
+ PageHeader[FileHeader.nlps-1].nBytes
|
||||
+ PageHeader[FileHeader.nlps-1].nRecords * 2 + 8)
|
||||
{
|
||||
fclose(InFile);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Now read in the palette. */
|
||||
fseek(InFile, PALETTE_OFFSET, SEEK_SET);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
efread(&colors[i].b, 1, 1, InFile);
|
||||
efread(&colors[i].g, 1, 1, InFile);
|
||||
efread(&colors[i].r, 1, 1, InFile);
|
||||
efread(&colors[i].unused, 1, 1, InFile);
|
||||
}
|
||||
set_palette(colors, 0, 255);
|
||||
|
||||
/* Whew! That was hard. Let's go grab some beers! */
|
||||
return(0);
|
||||
}
|
||||
|
||||
void JE_closeAnim( void )
|
||||
{
|
||||
fclose(InFile);
|
||||
}
|
||||
|
||||
/* RunSkipDump decompresses the video. There are three operations, run, skip,
|
||||
* and dump. They can be used in either byte or word variations, making six
|
||||
* possible actions, and there's a seventh 'stop' action, which looks
|
||||
* like 0x80 0x00 0x00.
|
||||
*
|
||||
* Run is a memset.
|
||||
* Dump is a memcpy.
|
||||
* Skip leaves the old data intact and simply increments the pointers.
|
||||
*
|
||||
* returns 0 on success or 1 if decompressing failed. Failure to decompress
|
||||
* indicates a broken or malicious file; playback should terminate.
|
||||
*/
|
||||
int JE_playRunSkipDump( Uint8 *incomingBuffer, unsigned int IncomingBufferLength )
|
||||
{
|
||||
sizebuf_t Buffer_IN, Buffer_OUT;
|
||||
sizebuf_t * pBuffer_IN = &Buffer_IN, * pBuffer_OUT = &Buffer_OUT;
|
||||
|
||||
#define ANI_SHORT_RLE 0x00
|
||||
#define ANI_SHORT_SKIP 0x80
|
||||
#define ANI_LONG_OP 0x80
|
||||
#define ANI_LONG_COPY_OR_RLE 0x8000
|
||||
#define ANI_LONG_RLE 0x4000
|
||||
#define ANI_STOP 0x0000
|
||||
|
||||
SZ_Init(pBuffer_IN, incomingBuffer, IncomingBufferLength);
|
||||
SZ_Init(pBuffer_OUT, VGAScreen->pixels, VGAScreen->h * VGAScreen->pitch);
|
||||
|
||||
|
||||
/* 320x200 is the only supported format.
|
||||
* Assert is here as a hint should our screen size ever changes.
|
||||
* As for how to decompress to the wrong screen size... */
|
||||
assert(VGAScreen->h * VGAScreen->pitch == 320 * 200);
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Get one byte. This byte may have flags that tell us more */
|
||||
unsigned int opcode = MSG_ReadByte(pBuffer_IN);
|
||||
|
||||
/* Before we continue, check the error states/
|
||||
* We should *probably* check these after every read and write, but
|
||||
* I've rigged it so that the buffers will never go out of bounds.
|
||||
* So we can afford to be lazy; if the buffer overflows below it will
|
||||
* silently fail its writes and we'll catch the failure on our next
|
||||
* run through the loop. A failure means we should be
|
||||
* leaving ANYWAY. The contents of our buffers doesn't matter.
|
||||
*/
|
||||
if (SZ_Error(pBuffer_IN) || SZ_Error(pBuffer_OUT))
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Divide into 'short' and 'long' */
|
||||
if (opcode == ANI_LONG_OP) /* long ops */
|
||||
{
|
||||
opcode = MSG_ReadWord(pBuffer_IN);
|
||||
|
||||
if (opcode == ANI_STOP) /* We are done decompressing. Leave */
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (!(opcode & ANI_LONG_COPY_OR_RLE)) /* If it's not those two, it's a skip */
|
||||
{
|
||||
unsigned int count = opcode;
|
||||
SZ_Seek(pBuffer_OUT, count, SEEK_CUR);
|
||||
}
|
||||
else /* Now things get a bit more interesting... */
|
||||
{
|
||||
opcode &= ~ANI_LONG_COPY_OR_RLE; /* Clear that flag */
|
||||
|
||||
if (opcode & ANI_LONG_RLE) /* RLE */
|
||||
{
|
||||
unsigned int count = opcode & ~ANI_LONG_RLE; /* Clear flag */
|
||||
|
||||
/* Extract another byte */
|
||||
unsigned int value = MSG_ReadByte(pBuffer_IN);
|
||||
|
||||
/* The actual run */
|
||||
SZ_Memset(pBuffer_OUT, value, count);
|
||||
}
|
||||
else
|
||||
{ /* Long copy */
|
||||
unsigned int count = opcode;
|
||||
|
||||
/* Copy */
|
||||
SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count);
|
||||
}
|
||||
}
|
||||
} /* End of long ops */
|
||||
else /* short ops */
|
||||
{
|
||||
if (opcode & ANI_SHORT_SKIP) /* Short skip, move pointer only */
|
||||
{
|
||||
unsigned int count = opcode & ~ANI_SHORT_SKIP; /* clear flag to get count */
|
||||
SZ_Seek(pBuffer_OUT, count, SEEK_CUR);
|
||||
}
|
||||
else if (opcode == ANI_SHORT_RLE) /* Short RLE, memset the destination */
|
||||
{
|
||||
/* Extract a few more bytes */
|
||||
unsigned int count = MSG_ReadByte(pBuffer_IN);
|
||||
unsigned int value = MSG_ReadByte(pBuffer_IN);
|
||||
|
||||
/* Run */
|
||||
SZ_Memset(pBuffer_OUT, value, count);
|
||||
}
|
||||
else /* Short copy, memcpy from src to dest. */
|
||||
{
|
||||
unsigned int count = opcode;
|
||||
|
||||
/* Dump */
|
||||
SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count);
|
||||
}
|
||||
} /* End of short ops */
|
||||
}
|
||||
|
||||
/* And that's that */
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef ANIMLIB_H
|
||||
#define ANIMLIB_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed );
|
||||
|
||||
#endif /* ANIMLIB_H */
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "arg_parse.h"
|
||||
|
||||
#include "std_support.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt );
|
||||
|
||||
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option );
|
||||
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option );
|
||||
|
||||
Option parse_args( int argc, const char *argv[], const Options *options )
|
||||
{
|
||||
static int argn = 1;
|
||||
static bool no_more_options = false;
|
||||
|
||||
static int first_nonopt = 1;
|
||||
|
||||
Option option = { NOT_OPTION, NULL, 0 };
|
||||
option.argn = first_nonopt;
|
||||
|
||||
while (argn < argc)
|
||||
{
|
||||
size_t arg_len = strlen(argv[argn]);
|
||||
|
||||
if (!no_more_options &&
|
||||
argv[argn][0] == '-' && // first char is '-'
|
||||
arg_len > 1) // option is not "-"
|
||||
{
|
||||
option.argn = argn;
|
||||
|
||||
if (argv[argn][1] == '-') // string begins with "--"
|
||||
{
|
||||
if (arg_len == 2) // "--" alone indicates end of options
|
||||
{
|
||||
++argn;
|
||||
no_more_options = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
argn = parse_long_opt(argc, argv, options, &option);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
argn = parse_short_opt(argc, argv, options, &option);
|
||||
}
|
||||
|
||||
// shift option in front of non-options
|
||||
permute(argv, &first_nonopt, &option.argn, argn);
|
||||
|
||||
// don't include "--" in non-options
|
||||
if (no_more_options)
|
||||
++option.argn;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip non-options, permute later when option encountered
|
||||
++argn;
|
||||
}
|
||||
}
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt )
|
||||
{
|
||||
const int nonopts = *first_opt - *first_nonopt;
|
||||
|
||||
// slide each of the options in front of the non-options
|
||||
for (int i = *first_opt; i < after_opt; ++i)
|
||||
{
|
||||
for (int j = i; j > *first_nonopt; --j)
|
||||
{
|
||||
// swap argv[j] and argv[j - 1]
|
||||
const char *temp = argv[j];
|
||||
argv[j] = argv[j - 1];
|
||||
argv[j - 1] = temp;
|
||||
}
|
||||
|
||||
// position of first non-option shifts right once for each option
|
||||
++(*first_nonopt);
|
||||
}
|
||||
|
||||
// position of first option is initial position of first non-option
|
||||
*first_opt -= nonopts;
|
||||
}
|
||||
|
||||
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option )
|
||||
{
|
||||
static size_t offset = 1; // ignore the "-"
|
||||
|
||||
int argn = option->argn;
|
||||
|
||||
const char *arg = argv[argn];
|
||||
|
||||
const size_t arg_len = strlen(arg);
|
||||
|
||||
const bool arg_attached = (offset + 1 < arg_len), // possible argument attached?
|
||||
last_in_argv = (argn == argc - 1);
|
||||
|
||||
option->value = INVALID_OPTION;
|
||||
|
||||
for (; !(options->short_opt == 0 &&
|
||||
options->long_opt == NULL); ++options)
|
||||
{
|
||||
if (options->short_opt != 0 &&
|
||||
options->short_opt == arg[offset])
|
||||
{
|
||||
option->value = options->value;
|
||||
|
||||
if (options->has_arg)
|
||||
{
|
||||
if (arg_attached) // arg direclty follows option
|
||||
{
|
||||
option->arg = arg + offset + 1;
|
||||
|
||||
offset = arg_len;
|
||||
}
|
||||
else if (!last_in_argv) // arg is next in argv
|
||||
{
|
||||
option->arg = argv[++argn];
|
||||
|
||||
offset = arg_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
option->value = OPTION_MISSING_ARG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (option->value)
|
||||
{
|
||||
case INVALID_OPTION:
|
||||
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], argv[option->argn][offset]);
|
||||
break;
|
||||
case OPTION_MISSING_ARG:
|
||||
fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], argv[option->argn][offset]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (++offset >= arg_len)
|
||||
{
|
||||
++argn;
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
return argn; // which arg in argv that parse_args() should examine when called again
|
||||
}
|
||||
|
||||
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option )
|
||||
{
|
||||
int argn = option->argn;
|
||||
|
||||
const char *arg = argv[argn] + 2; // ignore the "--"
|
||||
|
||||
const size_t arg_len = strlen(arg),
|
||||
arg_opt_len = ot_strchrnul(arg, '=') - arg; // length before "="
|
||||
|
||||
const bool arg_attached = (arg_opt_len < arg_len), // argument attached using "="?
|
||||
last_in_argv = (argn == argc - 1);
|
||||
|
||||
option->value = INVALID_OPTION;
|
||||
|
||||
for (; !(options->short_opt == 0 &&
|
||||
options->long_opt == NULL); ++options)
|
||||
{
|
||||
if (options->long_opt != NULL &&
|
||||
strncmp(options->long_opt, arg, arg_opt_len) == 0) // matches (partially, at least)
|
||||
{
|
||||
if (option->value != INVALID_OPTION) // other match already found
|
||||
{
|
||||
option->value = AMBIGUOUS_OPTION;
|
||||
break;
|
||||
}
|
||||
|
||||
option->value = options->value;
|
||||
|
||||
if (options->has_arg)
|
||||
{
|
||||
if (arg_attached) // arg is after "="
|
||||
{
|
||||
option->arg = arg + arg_opt_len + 1;
|
||||
}
|
||||
else if (!last_in_argv) // arg is next in argv
|
||||
{
|
||||
option->arg = argv[++argn];
|
||||
}
|
||||
else // arg is missing
|
||||
{
|
||||
option->value = OPTION_MISSING_ARG;
|
||||
// can't break, gotta check for ambiguity
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_opt_len == strlen(options->long_opt)) // exact match
|
||||
break;
|
||||
// can't break for partial match, gotta check for ambiguity
|
||||
}
|
||||
}
|
||||
|
||||
switch (option->value)
|
||||
{
|
||||
case INVALID_OPTION:
|
||||
fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[option->argn]);
|
||||
break;
|
||||
case AMBIGUOUS_OPTION:
|
||||
fprintf(stderr, "%s: option '%s' is ambiguous\n", argv[0], argv[option->argn]);
|
||||
break;
|
||||
case OPTION_MISSING_ARG:
|
||||
fprintf(stderr, "%s: option '%s' requires an argument\n", argv[0], argv[option->argn]);
|
||||
break;
|
||||
}
|
||||
|
||||
++argn;
|
||||
|
||||
return argn; // which arg in argv that parse_args() should examine when called again
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef ARG_PARSE_H
|
||||
#define ARG_PARSE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// this is essentially a reimplementation of getopt_long()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
char short_opt;
|
||||
const char *long_opt;
|
||||
bool has_arg;
|
||||
}
|
||||
Options;
|
||||
|
||||
enum
|
||||
{
|
||||
// indicates that argv[argn..argc) are not options
|
||||
NOT_OPTION = 0,
|
||||
|
||||
/* behavior of parse_args() is undefined after
|
||||
it has returned any of the following values */
|
||||
INVALID_OPTION = -1,
|
||||
AMBIGUOUS_OPTION = -2,
|
||||
OPTION_MISSING_ARG = -3
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
const char *arg;
|
||||
|
||||
int argn;
|
||||
}
|
||||
Option;
|
||||
|
||||
Option parse_args( int argc, const char *argv[], const Options *options );
|
||||
|
||||
#endif /* ARG_PARSE_H */
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "backgrnd.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "mtrand.h"
|
||||
#include "opentyr.h"
|
||||
#include "varz.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*Special Background 2 and Background 3*/
|
||||
|
||||
/*Back Pos 3*/
|
||||
JE_word backPos, backPos2, backPos3;
|
||||
JE_word backMove, backMove2, backMove3;
|
||||
|
||||
/*Main Maps*/
|
||||
JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
|
||||
JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
|
||||
JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
|
||||
intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
|
||||
JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
|
||||
|
||||
|
||||
JE_boolean anySmoothies;
|
||||
JE_byte smoothie_data[9]; /* [1..9] */
|
||||
|
||||
void JE_darkenBackground( JE_word neat ) /* wild detail level */
|
||||
{
|
||||
Uint8 *s = VGAScreen->pixels; /* screen pointer, 8-bit specific */
|
||||
int x, y;
|
||||
|
||||
s += 24;
|
||||
|
||||
for (y = 184; y; y--)
|
||||
{
|
||||
for (x = 264; x; x--)
|
||||
{
|
||||
*s = ((((*s & 0x0f) << 4) - (*s & 0x0f) + ((((x - neat - y) >> 2) + *(s-2) + (y == 184 ? 0 : *(s-(VGAScreen->pitch-1)))) & 0x0f)) >> 4) | (*s & 0xf0);
|
||||
s++;
|
||||
}
|
||||
s += VGAScreen->pitch - 264;
|
||||
}
|
||||
}
|
||||
|
||||
void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map )
|
||||
{
|
||||
assert(surface->format->BitsPerPixel == 8);
|
||||
|
||||
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
|
||||
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
|
||||
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
|
||||
|
||||
for (int y = 0; y < 28; y++)
|
||||
{
|
||||
// not drawing on screen yet; skip y
|
||||
if ((pixels + (12 * 24)) < pixels_ll)
|
||||
{
|
||||
pixels += surface->pitch;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int tile = 0; tile < 12; tile++)
|
||||
{
|
||||
Uint8 *data = *(map + tile);
|
||||
|
||||
// no tile; skip tile
|
||||
if (data == NULL)
|
||||
{
|
||||
pixels += 24;
|
||||
continue;
|
||||
}
|
||||
|
||||
data += y * 24;
|
||||
|
||||
for (int x = 24; x; x--)
|
||||
{
|
||||
if (pixels >= pixels_ul)
|
||||
return;
|
||||
if (pixels >= pixels_ll && *data != 0)
|
||||
*pixels = *data;
|
||||
|
||||
pixels++;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
pixels += surface->pitch - 12 * 24;
|
||||
}
|
||||
}
|
||||
|
||||
void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map )
|
||||
{
|
||||
assert(surface->format->BitsPerPixel == 8);
|
||||
|
||||
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
|
||||
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
|
||||
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
|
||||
|
||||
for (int y = 0; y < 28; y++)
|
||||
{
|
||||
// not drawing on screen yet; skip y
|
||||
if ((pixels + (12 * 24)) < pixels_ll)
|
||||
{
|
||||
pixels += surface->pitch;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int tile = 0; tile < 12; tile++)
|
||||
{
|
||||
Uint8 *data = *(map + tile);
|
||||
|
||||
// no tile; skip tile
|
||||
if (data == NULL)
|
||||
{
|
||||
pixels += 24;
|
||||
continue;
|
||||
}
|
||||
|
||||
data += y * 24;
|
||||
|
||||
for (int x = 24; x; x--)
|
||||
{
|
||||
if (pixels >= pixels_ul)
|
||||
return;
|
||||
if (pixels >= pixels_ll && *data != 0)
|
||||
*pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2);
|
||||
|
||||
pixels++;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
pixels += surface->pitch - 12 * 24;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_background_1( SDL_Surface *surface )
|
||||
{
|
||||
SDL_FillRect(surface, NULL, 0);
|
||||
|
||||
Uint8 **map = (Uint8 **)mapYPos + mapXbpPos - 12;
|
||||
|
||||
for (int i = -1; i < 7; i++)
|
||||
{
|
||||
blit_background_row(surface, mapXPos, (i * 28) + backPos, map);
|
||||
|
||||
map += 14;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_background_2( SDL_Surface *surface )
|
||||
{
|
||||
if (map2YDelayMax > 1 && backMove2 < 2)
|
||||
backMove2 = (map2YDelay == 1) ? 1 : 0;
|
||||
|
||||
if (background2 != 0)
|
||||
{
|
||||
// water effect combines background 1 and 2 by syncronizing the x coordinate
|
||||
int x = smoothies[1] ? mapXPos : mapX2Pos;
|
||||
|
||||
Uint8 **map = (Uint8 **)mapY2Pos + (smoothies[1] ? mapXbpPos : mapX2bpPos) - 12;
|
||||
|
||||
for (int i = -1; i < 7; i++)
|
||||
{
|
||||
blit_background_row(surface, x, (i * 28) + backPos2, map);
|
||||
|
||||
map += 14;
|
||||
}
|
||||
}
|
||||
|
||||
/*Set Movement of background*/
|
||||
if (--map2YDelay == 0)
|
||||
{
|
||||
map2YDelay = map2YDelayMax;
|
||||
|
||||
backPos2 += backMove2;
|
||||
|
||||
if (backPos2 > 27)
|
||||
{
|
||||
backPos2 -= 28;
|
||||
mapY2--;
|
||||
mapY2Pos -= 14; /*Map Width*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_background_2_blend( SDL_Surface *surface )
|
||||
{
|
||||
if (map2YDelayMax > 1 && backMove2 < 2)
|
||||
backMove2 = (map2YDelay == 1) ? 1 : 0;
|
||||
|
||||
Uint8 **map = (Uint8 **)mapY2Pos + mapX2bpPos - 12;
|
||||
|
||||
for (int i = -1; i < 7; i++)
|
||||
{
|
||||
blit_background_row_blend(surface, mapX2Pos, (i * 28) + backPos2, map);
|
||||
|
||||
map += 14;
|
||||
}
|
||||
|
||||
/*Set Movement of background*/
|
||||
if (--map2YDelay == 0)
|
||||
{
|
||||
map2YDelay = map2YDelayMax;
|
||||
|
||||
backPos2 += backMove2;
|
||||
|
||||
if (backPos2 > 27)
|
||||
{
|
||||
backPos2 -= 28;
|
||||
mapY2--;
|
||||
mapY2Pos -= 14; /*Map Width*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_background_3( SDL_Surface *surface )
|
||||
{
|
||||
/* Movement of background */
|
||||
backPos3 += backMove3;
|
||||
|
||||
if (backPos3 > 27)
|
||||
{
|
||||
backPos3 -= 28;
|
||||
mapY3--;
|
||||
mapY3Pos -= 15; /*Map Width*/
|
||||
}
|
||||
|
||||
Uint8 **map = (Uint8 **)mapY3Pos + mapX3bpPos - 12;
|
||||
|
||||
for (int i = -1; i < 7; i++)
|
||||
{
|
||||
blit_background_row(surface, mapX3Pos, (i * 28) + backPos3, map);
|
||||
|
||||
map += 15;
|
||||
}
|
||||
}
|
||||
|
||||
void JE_filterScreen( JE_shortint col, JE_shortint int_)
|
||||
{
|
||||
Uint8 *s = NULL; /* screen pointer, 8-bit specific */
|
||||
int x, y;
|
||||
unsigned int temp;
|
||||
|
||||
if (filterFade)
|
||||
{
|
||||
levelBrightness += levelBrightnessChg;
|
||||
if ((filterFadeStart && levelBrightness < -14) || levelBrightness > 14)
|
||||
{
|
||||
levelBrightnessChg = -levelBrightnessChg;
|
||||
filterFadeStart = false;
|
||||
levelFilter = levelFilterNew;
|
||||
}
|
||||
if (!filterFadeStart && levelBrightness == 0)
|
||||
{
|
||||
filterFade = false;
|
||||
levelBrightness = -99;
|
||||
}
|
||||
}
|
||||
|
||||
if (col != -99 && filtrationAvail)
|
||||
{
|
||||
s = VGAScreen->pixels;
|
||||
s += 24;
|
||||
|
||||
col <<= 4;
|
||||
|
||||
for (y = 184; y; y--)
|
||||
{
|
||||
for (x = 264; x; x--)
|
||||
{
|
||||
*s = col | (*s & 0x0f);
|
||||
s++;
|
||||
}
|
||||
s += VGAScreen->pitch - 264;
|
||||
}
|
||||
}
|
||||
|
||||
if (int_ != -99 && explosionTransparent)
|
||||
{
|
||||
s = VGAScreen->pixels;
|
||||
s += 24;
|
||||
|
||||
for (y = 184; y; y--)
|
||||
{
|
||||
for (x = 264; x; x--)
|
||||
{
|
||||
temp = (*s & 0x0f) + int_;
|
||||
*s = (*s & 0xf0) | (temp >= 0x1f ? 0 : (temp >= 0x0f ? 0x0f : temp));
|
||||
s++;
|
||||
}
|
||||
s += VGAScreen->pitch - 264;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_checkSmoothies( void )
|
||||
{
|
||||
anySmoothies = (processorType > 2 && (smoothies[1-1] || smoothies[2-1])) || (processorType > 1 && (smoothies[3-1] || smoothies[4-1] || smoothies[5-1]));
|
||||
}
|
||||
|
||||
void lava_filter( SDL_Surface *dst, SDL_Surface *src )
|
||||
{
|
||||
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
||||
|
||||
/* we don't need to check for over-reading the pixel surfaces since we only
|
||||
* read from the top 185+1 scanlines, and there should be 320 */
|
||||
|
||||
const int dst_pitch = dst->pitch;
|
||||
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
|
||||
const Uint8 * const dst_pixel_ll = (Uint8 *)dst->pixels; // lower limit
|
||||
|
||||
const int src_pitch = src->pitch;
|
||||
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
|
||||
const Uint8 * const src_pixel_ll = (Uint8 *)src->pixels; // lower limit
|
||||
|
||||
int w = 320 * 185 - 1;
|
||||
|
||||
for (int y = 185 - 1; y >= 0; --y)
|
||||
{
|
||||
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
|
||||
src_pixel -= (src_pitch - 320); // in case pitch is not 320
|
||||
|
||||
for (int x = 320 - 1; x >= 0; x -= 8)
|
||||
{
|
||||
int waver = abs(((w >> 9) & 0x0f) - 8) - 1;
|
||||
w -= 8;
|
||||
|
||||
for (int xi = 8 - 1; xi >= 0; --xi)
|
||||
{
|
||||
--dst_pixel;
|
||||
--src_pixel;
|
||||
|
||||
// value is average value of source pixel (2x), destination pixel above, and destination pixel below (all with waver)
|
||||
// hue is red
|
||||
Uint8 value = 0;
|
||||
|
||||
if (src_pixel + waver >= src_pixel_ll)
|
||||
value += (*(src_pixel + waver) & 0x0f) * 2;
|
||||
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
|
||||
if (dst_pixel + waver - dst_pitch >= dst_pixel_ll)
|
||||
value += *(dst_pixel + waver - dst_pitch) & 0x0f;
|
||||
|
||||
*dst_pixel = (value / 4) | 0x70;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void water_filter( SDL_Surface *dst, SDL_Surface *src )
|
||||
{
|
||||
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
||||
|
||||
Uint8 hue = smoothie_data[1] << 4;
|
||||
|
||||
/* we don't need to check for over-reading the pixel surfaces since we only
|
||||
* read from the top 185+1 scanlines, and there should be 320 */
|
||||
|
||||
const int dst_pitch = dst->pitch;
|
||||
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
|
||||
|
||||
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
|
||||
|
||||
int w = 320 * 185 - 1;
|
||||
|
||||
for (int y = 185 - 1; y >= 0; --y)
|
||||
{
|
||||
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
|
||||
src_pixel -= (src->pitch - 320); // in case pitch is not 320
|
||||
|
||||
for (int x = 320 - 1; x >= 0; x -= 8)
|
||||
{
|
||||
int waver = abs(((w >> 10) & 0x07) - 4) - 1;
|
||||
w -= 8;
|
||||
|
||||
for (int xi = 8 - 1; xi >= 0; --xi)
|
||||
{
|
||||
--dst_pixel;
|
||||
--src_pixel;
|
||||
|
||||
// pixel is copied from source if not blue
|
||||
// otherwise, value is average of value of source pixel and destination pixel below (with waver)
|
||||
if ((*src_pixel & 0x30) == 0)
|
||||
{
|
||||
*dst_pixel = *src_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
Uint8 value = *src_pixel & 0x0f;
|
||||
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
|
||||
*dst_pixel = (value / 2) | hue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src )
|
||||
{
|
||||
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
||||
|
||||
Uint8 *dst_pixel = dst->pixels;
|
||||
const Uint8 *src_pixel = src->pixels;
|
||||
|
||||
for (int y = 0; y < 184; ++y)
|
||||
{
|
||||
for (int x = 0; x < 320; ++x)
|
||||
{
|
||||
// value is average value of source pixel and destination pixel
|
||||
// hue is icy blue
|
||||
|
||||
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
|
||||
*dst_pixel = (value / 2) | 0x80;
|
||||
|
||||
++dst_pixel;
|
||||
++src_pixel;
|
||||
}
|
||||
|
||||
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
|
||||
src_pixel += (src->pitch - 320); // in case pitch is not 320
|
||||
}
|
||||
}
|
||||
|
||||
void blur_filter( SDL_Surface *dst, SDL_Surface *src )
|
||||
{
|
||||
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
||||
|
||||
Uint8 *dst_pixel = dst->pixels;
|
||||
const Uint8 *src_pixel = src->pixels;
|
||||
|
||||
for (int y = 0; y < 184; ++y)
|
||||
{
|
||||
for (int x = 0; x < 320; ++x)
|
||||
{
|
||||
// value is average value of source pixel and destination pixel
|
||||
// hue is source pixel hue
|
||||
|
||||
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
|
||||
*dst_pixel = (value / 2) | (*src_pixel & 0xf0);
|
||||
|
||||
++dst_pixel;
|
||||
++src_pixel;
|
||||
}
|
||||
|
||||
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
|
||||
src_pixel += (src->pitch - 320); // in case pitch is not 320
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Background Starfield */
|
||||
typedef struct
|
||||
{
|
||||
Uint8 color;
|
||||
JE_word position; // relies on overflow wrap-around
|
||||
int speed;
|
||||
} StarfieldStar;
|
||||
|
||||
#define MAX_STARS 100
|
||||
#define STARFIELD_HUE 0x90
|
||||
static StarfieldStar starfield_stars[MAX_STARS];
|
||||
int starfield_speed;
|
||||
|
||||
void initialize_starfield( void )
|
||||
{
|
||||
for (int i = MAX_STARS-1; i >= 0; --i)
|
||||
{
|
||||
starfield_stars[i].position = mt_rand() % 320 + mt_rand() % 200 * VGAScreen->pitch;
|
||||
starfield_stars[i].speed = mt_rand() % 3 + 2;
|
||||
starfield_stars[i].color = mt_rand() % 16 + STARFIELD_HUE;
|
||||
}
|
||||
}
|
||||
|
||||
void update_and_draw_starfield( SDL_Surface* surface, int move_speed )
|
||||
{
|
||||
Uint8* p = (Uint8*)surface->pixels;
|
||||
|
||||
for (int i = MAX_STARS-1; i >= 0; --i)
|
||||
{
|
||||
StarfieldStar* star = &starfield_stars[i];
|
||||
|
||||
star->position += (star->speed + move_speed) * surface->pitch;
|
||||
|
||||
if (star->position < 177 * surface->pitch)
|
||||
{
|
||||
if (p[star->position] == 0)
|
||||
{
|
||||
p[star->position] = star->color;
|
||||
}
|
||||
|
||||
// If star is bright enough, draw surrounding pixels
|
||||
if (star->color - 4 >= STARFIELD_HUE)
|
||||
{
|
||||
if (p[star->position + 1] == 0)
|
||||
p[star->position + 1] = star->color - 4;
|
||||
|
||||
if (star->position > 0 && p[star->position - 1] == 0)
|
||||
p[star->position - 1] = star->color - 4;
|
||||
|
||||
if (p[star->position + surface->pitch] == 0)
|
||||
p[star->position + surface->pitch] = star->color - 4;
|
||||
|
||||
if (star->position >= surface->pitch && p[star->position - surface->pitch] == 0)
|
||||
p[star->position - surface->pitch] = star->color - 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef BACKGRND_H
|
||||
#define BACKGRND_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern JE_word backPos, backPos2, backPos3;
|
||||
extern JE_word backMove, backMove2, backMove3;
|
||||
extern JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
|
||||
extern JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
|
||||
extern JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
|
||||
extern intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
|
||||
extern JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
|
||||
extern JE_boolean anySmoothies; // if yes, I want one :D
|
||||
extern JE_byte smoothie_data[9];
|
||||
|
||||
extern int starfield_speed;
|
||||
|
||||
void JE_darkenBackground( JE_word neat );
|
||||
|
||||
void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map );
|
||||
void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map );
|
||||
|
||||
void draw_background_1( SDL_Surface *surface );
|
||||
void draw_background_2( SDL_Surface *surface );
|
||||
void draw_background_2_blend( SDL_Surface *surface );
|
||||
void draw_background_3( SDL_Surface *surface );
|
||||
|
||||
void JE_filterScreen( JE_shortint col, JE_shortint generic_int );
|
||||
|
||||
void JE_checkSmoothies( void );
|
||||
void lava_filter( SDL_Surface *dst, SDL_Surface *src );
|
||||
void water_filter( SDL_Surface *dst, SDL_Surface *src );
|
||||
void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src );
|
||||
void blur_filter( SDL_Surface *dst, SDL_Surface *src );
|
||||
/*smoothies #5 is used for 3*/
|
||||
/*smoothies #9 is a vertical flip*/
|
||||
|
||||
void initialize_starfield( void );
|
||||
void update_and_draw_starfield( SDL_Surface* surface, int move_speed );
|
||||
|
||||
#endif /* BACKGRND_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include "opentyr.h"
|
||||
#include "config_file.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define SAVE_FILES_NUM (11 * 2)
|
||||
|
||||
/* These are necessary because the size of the structure has changed from the original, but we
|
||||
need to know the original sizes in order to find things in TYRIAN.SAV */
|
||||
#define SAVE_FILES_SIZE 2398
|
||||
#define SIZEOF_SAVEGAMETEMP SAVE_FILES_SIZE + 4 + 100
|
||||
#define SAVE_FILE_SIZE (SIZEOF_SAVEGAMETEMP - 4)
|
||||
|
||||
/*#define SAVE_FILES_SIZE (2502 - 4)
|
||||
#define SAVE_FILE_SIZE (SAVE_FILES_SIZE)*/
|
||||
|
||||
typedef SDLKey JE_KeySettingType[8]; /* [1..8] */
|
||||
typedef JE_byte JE_PItemsType[12]; /* [1..12] */
|
||||
|
||||
typedef JE_byte JE_EditorItemAvailType[100]; /* [1..100] */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
JE_word encode;
|
||||
JE_word level;
|
||||
JE_PItemsType items;
|
||||
JE_longint score;
|
||||
JE_longint score2;
|
||||
char levelName[11]; /* string [9]; */ /* SYN: Added one more byte to match lastLevelName below */
|
||||
JE_char name[15]; /* [1..14] */ /* SYN: Added extra byte for null */
|
||||
JE_byte cubes;
|
||||
JE_byte power[2]; /* [1..2] */
|
||||
JE_byte episode;
|
||||
JE_PItemsType lastItems;
|
||||
JE_byte difficulty;
|
||||
JE_byte secretHint;
|
||||
JE_byte input1;
|
||||
JE_byte input2;
|
||||
JE_boolean gameHasRepeated; /*See if you went from one episode to another*/
|
||||
JE_byte initialDifficulty;
|
||||
|
||||
/* High Scores - Each episode has both sets of 1&2 player selections - with 3 in each */
|
||||
JE_longint highScore1,
|
||||
highScore2;
|
||||
char highScoreName[30]; /* string [29] */
|
||||
JE_byte highScoreDiff;
|
||||
} JE_SaveFileType;
|
||||
|
||||
typedef JE_SaveFileType JE_SaveFilesType[SAVE_FILES_NUM]; /* [1..savefilesnum] */
|
||||
typedef JE_byte JE_SaveGameTemp[SAVE_FILES_SIZE + 4 + 100]; /* [1..sizeof(savefilestype) + 4 + 100] */
|
||||
|
||||
extern const JE_byte cryptKey[10];
|
||||
extern const JE_KeySettingType defaultKeySettings;
|
||||
extern const char defaultHighScoreNames[34][23];
|
||||
extern const char defaultTeamNames[22][25];
|
||||
extern const JE_EditorItemAvailType initialItemAvail;
|
||||
extern JE_boolean smoothies[9];
|
||||
extern JE_byte starShowVGASpecialCode;
|
||||
extern JE_word lastCubeMax, cubeMax;
|
||||
extern JE_word cubeList[4];
|
||||
extern JE_boolean gameHasRepeated;
|
||||
extern JE_shortint difficultyLevel, oldDifficultyLevel, initialDifficulty;
|
||||
extern uint power, lastPower, powerAdd;
|
||||
extern JE_byte shieldWait, shieldT;
|
||||
|
||||
enum
|
||||
{
|
||||
SHOT_FRONT,
|
||||
SHOT_REAR,
|
||||
SHOT_LEFT_SIDEKICK,
|
||||
SHOT_RIGHT_SIDEKICK,
|
||||
SHOT_MISC,
|
||||
SHOT_P2_CHARGE,
|
||||
SHOT_P1_SUPERBOMB,
|
||||
SHOT_P2_SUPERBOMB,
|
||||
SHOT_SPECIAL,
|
||||
SHOT_NORTSPARKS,
|
||||
SHOT_SPECIAL2
|
||||
};
|
||||
|
||||
extern JE_byte shotRepeat[11], shotMultiPos[11];
|
||||
extern JE_boolean portConfigChange, portConfigDone;
|
||||
extern char lastLevelName[11], levelName[11];
|
||||
extern JE_byte mainLevel, nextLevel, saveLevel;
|
||||
extern JE_KeySettingType keySettings;
|
||||
extern JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg;
|
||||
extern JE_boolean filtrationAvail, filterActive, filterFade, filterFadeStart;
|
||||
extern JE_boolean gameJustLoaded;
|
||||
extern JE_boolean galagaMode;
|
||||
extern JE_boolean extraGame;
|
||||
extern JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian, trentWin;
|
||||
extern JE_byte superArcadeMode;
|
||||
extern JE_byte superArcadePowerUp;
|
||||
extern JE_real linkGunDirec;
|
||||
extern JE_byte inputDevice[2];
|
||||
extern JE_byte secretHint;
|
||||
extern JE_byte background3over;
|
||||
extern JE_byte background2over;
|
||||
extern JE_byte gammaCorrection;
|
||||
extern JE_boolean superPause, explosionTransparent, youAreCheating, displayScore, background2, smoothScroll, wild, superWild, starActive, topEnemyOver, skyEnemyOverAll, background2notTransparent;
|
||||
extern JE_byte versionNum;
|
||||
extern JE_byte fastPlay;
|
||||
extern JE_boolean pentiumMode;
|
||||
extern JE_byte gameSpeed;
|
||||
extern JE_byte processorType;
|
||||
extern JE_SaveFilesType saveFiles;
|
||||
extern JE_SaveGameTemp saveTemp;
|
||||
extern JE_word editorLevel;
|
||||
|
||||
extern Config opentyrian_config;
|
||||
|
||||
void JE_initProcessorType( void );
|
||||
void JE_setNewGameSpeed( void );
|
||||
const char *get_user_directory( void );
|
||||
void JE_loadConfiguration( void );
|
||||
void JE_saveConfiguration( void );
|
||||
|
||||
void JE_saveGame( JE_byte slot, const char *name );
|
||||
void JE_loadGame( JE_byte slot );
|
||||
|
||||
void JE_encryptSaveTemp( void );
|
||||
void JE_decryptSaveTemp( void );
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2015 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/*!
|
||||
* \file config_file.h
|
||||
* \author Carl Reinke
|
||||
* \date 2015
|
||||
* \copyright GNU General Public License v2+ or Mozilla Public License 2.0
|
||||
*/
|
||||
#ifndef CONFIG_FILE_H
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef COMPILE_TIME_ASSERT
|
||||
/*!
|
||||
* \brief Cause compile error if compile-time computable condition fails.
|
||||
*
|
||||
* \param[in] name the unique identifier of the assertion
|
||||
* \param[in] cond the condition
|
||||
*/
|
||||
#define COMPILE_TIME_ASSERT(name, cond) typedef int assert_ ## name[(cond) * 2 - 1]
|
||||
#endif
|
||||
|
||||
#ifndef COUNTOF
|
||||
/*!
|
||||
* \brief Calculate the number of elements in a fixed-length array.
|
||||
*
|
||||
* \param[in] a the fixed-length array
|
||||
* \return the number of elements in the array
|
||||
*/
|
||||
#define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
|
||||
#endif
|
||||
|
||||
/* string type */
|
||||
|
||||
/*!
|
||||
* \brief A short-string-optimizing string type.
|
||||
*
|
||||
* This struct allows for storing up to 15 characters (plus a terminating \c '\0') inline. For
|
||||
* longer strings memory will be allocated.
|
||||
*
|
||||
* The tag for this union is the last character of \p short_buf:
|
||||
* \li if \c '\0' then \p short_buf is valid,
|
||||
* \li otherwise \p long_buf is valid.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/*!
|
||||
* \brief The inline buffer for short strings.
|
||||
*/
|
||||
char short_buf[16];
|
||||
|
||||
/*!
|
||||
* \brief The buffer for long strings.
|
||||
*
|
||||
* May be \c NULL.
|
||||
*/
|
||||
char *long_buf;
|
||||
} ConfigString;
|
||||
|
||||
/*! \cond suppress_doxygen */
|
||||
COMPILE_TIME_ASSERT(string_short_buf_sufficient, sizeof(char *) + 1 <= COUNTOF(((ConfigString *)NULL)->short_buf));
|
||||
/*! \endcond */
|
||||
|
||||
/*! \cond suppress_doxygen */
|
||||
#define CONFIG_STRING_LONG_TAG(s) ((s).short_buf[COUNTOF((s).short_buf) - 1])
|
||||
/*! \endcond */
|
||||
|
||||
/*!
|
||||
* \brief Return a C-string backed by a string.
|
||||
*
|
||||
* \param[in] string the string
|
||||
* \return the C-string
|
||||
*/
|
||||
static inline const char *config_string_to_cstr( const ConfigString *string )
|
||||
{
|
||||
assert(string != NULL);
|
||||
char is_long = CONFIG_STRING_LONG_TAG(*string);
|
||||
return is_long ?
|
||||
string->long_buf :
|
||||
string->short_buf;
|
||||
}
|
||||
|
||||
/* config types */
|
||||
|
||||
/*!
|
||||
* \brief An option consisting of one (an item) or many (a list) values.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*!
|
||||
* \brief The key of the option.
|
||||
*/
|
||||
ConfigString key;
|
||||
|
||||
/*!
|
||||
* \brief The number of values in the option if it is a 'list' option.
|
||||
*
|
||||
* If \c 0 then the option \e may be an 'item' option.
|
||||
*
|
||||
* \see ::ConfigOption::value
|
||||
*/
|
||||
unsigned int values_count;
|
||||
|
||||
/*!
|
||||
* \brief The value or values.
|
||||
*
|
||||
* The tag for this union is \p value_count:
|
||||
* \li if \c 0 then \p value is valid,
|
||||
* \li otherwise \p values is valid.
|
||||
*/
|
||||
union
|
||||
{
|
||||
/*!
|
||||
* \brief The value of an 'item' option or an empty 'list' option.
|
||||
*
|
||||
* If this field is \c NULL then the option is an empty 'list' option.
|
||||
*/
|
||||
ConfigString value;
|
||||
|
||||
/*!
|
||||
* \brief The values of a non-empty 'list' option.
|
||||
*/
|
||||
ConfigString *values;
|
||||
} v;
|
||||
} ConfigOption;
|
||||
|
||||
/*!
|
||||
* \brief A section consisting of options.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*!
|
||||
* \brief The type of the section.
|
||||
*/
|
||||
ConfigString type;
|
||||
|
||||
/*!
|
||||
* \brief The optional name of the section.
|
||||
*
|
||||
* May be \c NULL.
|
||||
*/
|
||||
ConfigString name;
|
||||
|
||||
/*!
|
||||
* \brief The number of options in the section.
|
||||
*/
|
||||
unsigned int options_count;
|
||||
|
||||
/*!
|
||||
* \brief The options in the section.
|
||||
*
|
||||
* \c NULL if \p options_count is \c 0.
|
||||
*/
|
||||
ConfigOption *options;
|
||||
} ConfigSection;
|
||||
|
||||
/*!
|
||||
* \brief A configuration consisting of sections.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*!
|
||||
* \brief The number of sections in the configuration.
|
||||
*/
|
||||
unsigned int sections_count;
|
||||
|
||||
/*!
|
||||
* \brief The sections in the configuration.
|
||||
*
|
||||
* \c NULL if \p sections_count is \c 0.
|
||||
*/
|
||||
ConfigSection *sections;
|
||||
} Config;
|
||||
|
||||
/* config manipulators */
|
||||
|
||||
/*!
|
||||
* \brief Initialize a configuration.
|
||||
*
|
||||
* \param[in] config the configuration
|
||||
* \return void
|
||||
*/
|
||||
extern void config_init( Config *config );
|
||||
|
||||
/*!
|
||||
* \brief Release any memory allocated inside a configuration.
|
||||
*
|
||||
* \param[in] config the configuration
|
||||
* \return void
|
||||
*/
|
||||
extern void config_deinit( Config *config );
|
||||
|
||||
/*!
|
||||
* \brief Parse a configuration from a file.
|
||||
*
|
||||
* \param[in] config the uninitalized configuration
|
||||
* \param[in] file the file handle
|
||||
* \return whether parsing succeeded
|
||||
*/
|
||||
extern bool config_parse( Config *config, FILE *file );
|
||||
|
||||
/*!
|
||||
* \brief Write a configuration to a file.
|
||||
*
|
||||
* \param[in] config the configuration
|
||||
* \param[in] file the file handle
|
||||
* \return void
|
||||
*/
|
||||
extern void config_write( const Config *config, FILE *file );
|
||||
|
||||
/* config section accessors/manipulators -- by type, name */
|
||||
|
||||
/*! \see ::config_add_section() */
|
||||
extern ConfigSection *config_add_section_len( Config *config, const char *type, size_t type_len, const char *name, size_t name_len );
|
||||
|
||||
/*!
|
||||
* \brief Add a section to a configuration.
|
||||
*
|
||||
* \param[in] config the configuration to contain the section
|
||||
* \param[in] type the type of the section
|
||||
* \param[in] name the name of the section; may be \c NULL
|
||||
* \return the added section; \c NULL if out of memory
|
||||
*/
|
||||
static inline ConfigSection *config_add_section( Config *config, const char *type, const char *name)
|
||||
{
|
||||
assert(type != NULL);
|
||||
return config_add_section_len(config, type, strlen(type), name, name == NULL ? 0 : strlen(name));
|
||||
}
|
||||
|
||||
// TODO: extern Config *config_remove_section( Config *config, unsigned int i );
|
||||
|
||||
/*!
|
||||
* \brief Iterate sections by type.
|
||||
*
|
||||
* \param[in] config the configuration containing the sections
|
||||
* \param[in] type the type of the section
|
||||
* \param[in,out] save the saved state of the iterator; initialize \c *save to \c NULL before
|
||||
* iteration
|
||||
* \return the section; \c NULL if iteration finished
|
||||
*/
|
||||
extern ConfigSection *config_find_sections( Config *config, const char *type, ConfigSection **save );
|
||||
|
||||
/*!
|
||||
* \brief Find a section by type and name.
|
||||
*
|
||||
* \param[in] config the configuration containing the section
|
||||
* \param[in] type the type of the section
|
||||
* \param[in] name the name of the section
|
||||
* \return the section; \c NULL if it does not exist
|
||||
*/
|
||||
extern ConfigSection *config_find_section( Config *config, const char *type, const char *name );
|
||||
|
||||
/*!
|
||||
* \brief Find a section by type and name, creating the section if it did not exist.
|
||||
*
|
||||
* \param[in] config the configuration containing the section
|
||||
* \param[in] type the type of the section
|
||||
* \param[in] name the name of the section; may be \c NULL
|
||||
* \return the section; \c NULL if out of memory
|
||||
*/
|
||||
extern ConfigSection *config_find_or_add_section( Config *config, const char *type, const char *name );
|
||||
|
||||
/* config option accessors/manipulators -- by key */
|
||||
|
||||
/*! \see ::config_set_option() */
|
||||
extern ConfigOption *config_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
|
||||
|
||||
/*!
|
||||
* \brief Set a value of an 'item' option by key, creating the option if necessary.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the item value; \c NULL to set an emtpy 'list' option instead of an 'item'
|
||||
* option (can be used to delete an 'item' option)
|
||||
* \return the option; \c NULL if out of memory
|
||||
*/
|
||||
static inline ConfigOption *config_set_option( ConfigSection *section, const char *key, const char *value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
return config_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get an option by key.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \return the option; \c NULL if it does not exist
|
||||
*/
|
||||
extern ConfigOption *config_get_option( const ConfigSection *section, const char *key );
|
||||
|
||||
/*! \see ::config_get_or_set_option() */
|
||||
extern ConfigOption *config_get_or_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
|
||||
|
||||
/*!
|
||||
* \brief Get an option by key, creating an 'item' option if the option did not exist.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the default item value; \c NULL to set an empty 'list' option instead of an
|
||||
* 'item' option
|
||||
* \return the option; \c NULL if out of memory
|
||||
*/
|
||||
static inline ConfigOption *config_get_or_set_option( ConfigSection *section, const char *key, const char *value )
|
||||
{
|
||||
assert(key != NULL);
|
||||
return config_get_or_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
|
||||
}
|
||||
|
||||
/*! \see ::config_set_string_option() */
|
||||
extern void config_set_string_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
|
||||
|
||||
/*!
|
||||
* \brief Set a string value of an 'item' option by key, creating the option if necessary.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the item value
|
||||
* \return void
|
||||
*/
|
||||
static inline void config_set_string_option( ConfigSection *section, const char *key, const char *value )
|
||||
{
|
||||
assert(key != NULL);
|
||||
config_set_string_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get a string value of an 'item' option by key.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[out] out_value the item value if a valid option exists; otherwise unset
|
||||
* \return whether \p out_value was set
|
||||
*/
|
||||
extern bool config_get_string_option( const ConfigSection *section, const char *key, const char **out_value );
|
||||
|
||||
/*!
|
||||
* \brief Get a string value of an 'item' option by key, setting the option if it was invalid or
|
||||
* creating the option if it did not exist.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the default item value
|
||||
* \return the value
|
||||
*/
|
||||
extern const char *config_get_or_set_string_option( ConfigSection *section, const char *key, const char *value );
|
||||
|
||||
/*!
|
||||
* \brief The styles of boolean values.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ZERO_ONE = 0,
|
||||
NO_YES = 1,
|
||||
OFF_ON = 2,
|
||||
FALSE_TRUE = 3,
|
||||
} ConfigBoolStyle;
|
||||
|
||||
/*!
|
||||
* \brief Set a boolean value of an 'item' option by key, creating the option if necessary.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the item value
|
||||
* \param[in] style the style of boolean value
|
||||
* \return void
|
||||
*/
|
||||
extern void config_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style );
|
||||
|
||||
/*!
|
||||
* \brief Get a boolean value of an 'item' option by key.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[out] out_value the item value if a valid option exists; otherwise unset
|
||||
* \return whether \p out_value was set
|
||||
*/
|
||||
extern bool config_get_bool_option( const ConfigSection *section, const char *key, bool *out_value );
|
||||
|
||||
/*!
|
||||
* \brief Get a boolean value of an 'item' option by key, setting the option if it was invalid or
|
||||
* creating the option if it did not exist.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the default item value
|
||||
* \param[in] style the style of boolean value
|
||||
* \return the value
|
||||
*/
|
||||
extern bool config_get_or_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style );
|
||||
|
||||
/*!
|
||||
* \brief Set an integer value of an 'item' option by key, creating the option if necessary.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the item value
|
||||
* \return void
|
||||
*/
|
||||
extern void config_set_int_option( ConfigSection *section, const char *key, int value );
|
||||
|
||||
/*!
|
||||
* \brief Get an integer value of an 'item' option by key.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[out] out_value the item value if a valid option exists; otherwise unset
|
||||
* \return whether \p out_value was set
|
||||
*/
|
||||
extern bool config_get_int_option( const ConfigSection *section, const char *key, int *out_value );
|
||||
|
||||
/*!
|
||||
* \brief Get an integer value of an 'item' option by key, setting the option if it was invalid or
|
||||
* creating the option if it did not exist.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the default item value
|
||||
* \return the value
|
||||
*/
|
||||
extern int config_get_or_set_int_option( ConfigSection *section, const char *key, int value );
|
||||
|
||||
/*!
|
||||
* \brief Set an unsigned integer value of an 'item' option by key, creating the option if
|
||||
* necessary.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the item value
|
||||
* \return void
|
||||
*/
|
||||
extern void config_set_uint_option( ConfigSection *section, const char *key, unsigned int value );
|
||||
|
||||
/*!
|
||||
* \brief Get an unsigned integer value of an 'item' option by key.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[out] out_value the item value if a valid option exists; otherwise unset
|
||||
* \return whether \p out_value was set
|
||||
*/
|
||||
extern bool config_get_uint_option( const ConfigSection *section, const char *key, unsigned int *out_value );
|
||||
|
||||
/*!
|
||||
* \brief Get an unsigned integer value of an 'item' option by key, setting the option if it was
|
||||
* invalid or creating the option if it did not exist.
|
||||
*
|
||||
* \param[in] section the section containing the option
|
||||
* \param[in] key the option key
|
||||
* \param[in] value the default item value
|
||||
* \return the value
|
||||
*/
|
||||
extern unsigned int config_get_or_set_uint_option( ConfigSection *section, const char *key, unsigned int value );
|
||||
|
||||
/* config option accessors/manipulators -- by reference */
|
||||
|
||||
/*! \see ::config_set_value() */
|
||||
extern ConfigOption *config_set_value_len( ConfigOption *option, const char *value, size_t value_len );
|
||||
|
||||
/*!
|
||||
* \brief Set the value of an 'item' option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \param[in] value the value
|
||||
* \return the option; \c NULL if out of memory
|
||||
*/
|
||||
static inline ConfigOption *config_set_value( ConfigOption *option, const char *value )
|
||||
{
|
||||
return config_set_value_len(option, value, value == NULL ? 0 : strlen(value));
|
||||
}
|
||||
|
||||
/*! \see ::config_add_value() */
|
||||
extern ConfigOption *config_add_value_len( ConfigOption *option, const char *value, size_t value_len );
|
||||
|
||||
/*!
|
||||
* \brief Add a value to a 'list' option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \param[in] value the value
|
||||
* \return the option; \c NULL if out of memory
|
||||
*/
|
||||
static inline ConfigOption *config_add_value( ConfigOption *option, const char *value )
|
||||
{
|
||||
assert(value != NULL);
|
||||
return config_add_value_len(option, value, strlen(value));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Remove a value from a 'list' option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \param[in] i the index of the value
|
||||
* \return the option; \c NULL if out of memory or invalid \p index
|
||||
*/
|
||||
extern ConfigOption *config_remove_value( ConfigOption *option, unsigned int i );
|
||||
|
||||
/*!
|
||||
* \brief Get the value of an 'item' option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \return the value; \c NULL if \p option was \c NULL or was a 'list' option
|
||||
*/
|
||||
extern const char *config_get_value( const ConfigOption *option );
|
||||
|
||||
/*!
|
||||
* \brief Get the value that indicates whether the option is a 'list' option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \return whether the option is a 'list' option
|
||||
*/
|
||||
static inline bool config_is_value_list( const ConfigOption *option )
|
||||
{
|
||||
assert(option != NULL);
|
||||
return option->values_count > 0 ||
|
||||
config_string_to_cstr(&option->v.value) == NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get the number of values assigned to the option.
|
||||
*
|
||||
* \param[in] option the option
|
||||
* \return \c 1 if the option is an 'item' option; the number of elements if the option is a 'list'
|
||||
* option
|
||||
*/
|
||||
static inline unsigned int config_get_value_count( const ConfigOption *option )
|
||||
{
|
||||
assert(option != NULL);
|
||||
return option->values_count == 0 ?
|
||||
(config_string_to_cstr(&option->v.value) == NULL ? 0 : 1) :
|
||||
option->values_count;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Iterate over the values assigned to the option.
|
||||
*
|
||||
* \param[out] string_value the value variable to declare
|
||||
* \param[in] option the option
|
||||
*/
|
||||
#define foreach_option_value( string_value, option ) \
|
||||
for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \
|
||||
for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \
|
||||
*_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \
|
||||
*_value = _values_begin; _value < _values_end; ++_value) \
|
||||
for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL)
|
||||
|
||||
/*!
|
||||
* \brief Iterate over the values assigned to the option.
|
||||
*
|
||||
* \param[out] i the index variable to declare
|
||||
* \param[out] string_value the value variable to declare
|
||||
* \param[in] option the option
|
||||
*/
|
||||
#define foreach_option_i_value( i, string_value, option ) \
|
||||
for (unsigned int (i) = 0; (i) == 0; (i) = ~0) \
|
||||
for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \
|
||||
for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \
|
||||
*_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \
|
||||
*_value = _values_begin; _value < _values_end; ++_value, (i) = _value - _values_begin) \
|
||||
for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL)
|
||||
|
||||
/*!
|
||||
* \brief Remove a value from an option during iteration. Should be followed by \c continue.
|
||||
*/
|
||||
#define foreach_remove_option_value() \
|
||||
{ \
|
||||
extern void config_oom( void ); \
|
||||
unsigned int _value_i = _value - _values_begin; \
|
||||
if (config_remove_value(_option, _value_i) == NULL) \
|
||||
config_oom(); \
|
||||
_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0]; \
|
||||
_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count]; \
|
||||
_value = _values_begin + _value_i - 1; \
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef DESTRUCT_H
|
||||
#define DESTRUCT_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
void JE_destructGame( void );
|
||||
|
||||
#endif /* DESTRUCT_H */
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "editship.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "file.h"
|
||||
#include "opentyr.h"
|
||||
|
||||
#define SAS (sizeof(JE_ShipsType) - 4)
|
||||
|
||||
const JE_byte extraCryptKey[10] = { 58, 23, 16, 192, 254, 82, 113, 147, 62, 99 };
|
||||
|
||||
JE_boolean extraAvail;
|
||||
JE_ShipsType extraShips;
|
||||
void *extraShapes;
|
||||
JE_word extraShapeSize;
|
||||
|
||||
void JE_decryptShips( void )
|
||||
{
|
||||
JE_boolean correct = true;
|
||||
JE_ShipsType s2;
|
||||
JE_byte y;
|
||||
|
||||
for (int x = SAS - 1; x >= 0; x--)
|
||||
{
|
||||
s2[x] = extraShips[x] ^ extraCryptKey[(x + 1) % 10];
|
||||
if (x > 0)
|
||||
s2[x] ^= extraShips[x - 1];
|
||||
} /* <= Key Decryption Test (Reversed key) */
|
||||
|
||||
y = 0;
|
||||
for (uint x = 0; x < SAS; x++)
|
||||
y += s2[x];
|
||||
if (extraShips[SAS + 0] != y)
|
||||
correct = false;
|
||||
|
||||
y = 0;
|
||||
for (uint x = 0; x < SAS; x++)
|
||||
y -= s2[x];
|
||||
if (extraShips[SAS + 1] != y)
|
||||
correct = false;
|
||||
|
||||
y = 1;
|
||||
for (uint x = 0; x < SAS; x++)
|
||||
y = y * s2[x] + 1;
|
||||
if (extraShips[SAS + 2] != y)
|
||||
correct = false;
|
||||
|
||||
y = 0;
|
||||
for (uint x = 0; x < SAS; x++)
|
||||
y ^= s2[x];
|
||||
if (extraShips[SAS + 3] != y)
|
||||
correct = false;
|
||||
|
||||
if (!correct)
|
||||
exit(255);
|
||||
|
||||
memcpy(extraShips, s2, sizeof(extraShips));
|
||||
}
|
||||
|
||||
void JE_loadExtraShapes( void )
|
||||
{
|
||||
FILE *f = dir_fopen(get_user_directory(), "newsh$.shp", "rb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
extraAvail = true;
|
||||
extraShapeSize = ftell_eof(f) - sizeof(extraShips);
|
||||
extraShapes = malloc(extraShapeSize);
|
||||
efread(extraShapes, extraShapeSize, 1, f);
|
||||
efread(extraShips, sizeof(extraShips), 1, f);
|
||||
JE_decryptShips();
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef EDITSHIP_H
|
||||
#define EDITSHIP_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
|
||||
typedef JE_byte JE_ShipsType[154]; /* [1..154] */
|
||||
|
||||
extern JE_boolean extraAvail;
|
||||
extern JE_ShipsType extraShips;
|
||||
extern void *extraShapes;
|
||||
extern JE_word extraShapeSize;
|
||||
|
||||
void JE_decryptShips( void );
|
||||
void JE_loadExtraShapes( void );
|
||||
|
||||
#endif /* EDITSHIP_H */
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "episodes.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "file.h"
|
||||
#include "lvllib.h"
|
||||
#include "lvlmast.h"
|
||||
#include "opentyr.h"
|
||||
|
||||
|
||||
/* MAIN Weapons Data */
|
||||
JE_WeaponPortType weaponPort;
|
||||
JE_WeaponType weapons[WEAP_NUM + 1]; /* [0..weapnum] */
|
||||
|
||||
/* Items */
|
||||
JE_PowerType powerSys;
|
||||
JE_ShipType ships;
|
||||
JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */
|
||||
JE_ShieldType shields;
|
||||
JE_SpecialType special;
|
||||
|
||||
/* Enemy data */
|
||||
JE_EnemyDatType enemyDat;
|
||||
|
||||
/* EPISODE variables */
|
||||
JE_byte initial_episode_num, episodeNum = 0;
|
||||
JE_boolean episodeAvail[EPISODE_MAX]; /* [1..episodemax] */
|
||||
char episode_file[13], cube_file[13];
|
||||
|
||||
JE_longint episode1DataLoc;
|
||||
|
||||
/* Tells the game whether the level currently loaded is a bonus level. */
|
||||
JE_boolean bonusLevel;
|
||||
|
||||
/* Tells if the game jumped back to Episode 1 */
|
||||
JE_boolean jumpBackToEpisode1;
|
||||
|
||||
void JE_loadItemDat( void )
|
||||
{
|
||||
FILE *f = NULL;
|
||||
|
||||
if (episodeNum <= 3)
|
||||
{
|
||||
f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb");
|
||||
efread(&episode1DataLoc, sizeof(JE_longint), 1, f);
|
||||
fseek(f, episode1DataLoc, SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
// episode 4 stores item data in the level file
|
||||
f = dir_fopen_die(data_dir(), levelFile, "rb");
|
||||
fseek(f, lvlPos[lvlNum-1], SEEK_SET);
|
||||
}
|
||||
|
||||
JE_word itemNum[7]; /* [1..7] */
|
||||
efread(&itemNum, sizeof(JE_word), 7, f);
|
||||
|
||||
for (int i = 0; i < WEAP_NUM + 1; ++i)
|
||||
{
|
||||
efread(&weapons[i].drain, sizeof(JE_word), 1, f);
|
||||
efread(&weapons[i].shotrepeat, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].multi, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].weapani, sizeof(JE_word), 1, f);
|
||||
efread(&weapons[i].max, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].tx, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].ty, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].aim, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].attack, sizeof(JE_byte), 8, f);
|
||||
efread(&weapons[i].del, sizeof(JE_byte), 8, f);
|
||||
efread(&weapons[i].sx, sizeof(JE_shortint), 8, f);
|
||||
efread(&weapons[i].sy, sizeof(JE_shortint), 8, f);
|
||||
efread(&weapons[i].bx, sizeof(JE_shortint), 8, f);
|
||||
efread(&weapons[i].by, sizeof(JE_shortint), 8, f);
|
||||
efread(&weapons[i].sg, sizeof(JE_word), 8, f);
|
||||
efread(&weapons[i].acceleration, sizeof(JE_shortint), 1, f);
|
||||
efread(&weapons[i].accelerationx, sizeof(JE_shortint), 1, f);
|
||||
efread(&weapons[i].circlesize, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].sound, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].trail, sizeof(JE_byte), 1, f);
|
||||
efread(&weapons[i].shipblastfilter, sizeof(JE_byte), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PORT_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&weaponPort[i].name, 1, 30, f);
|
||||
weaponPort[i].name[30] = '\0';
|
||||
efread(&weaponPort[i].opnum, sizeof(JE_byte), 1, f);
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
efread(&weaponPort[i].op[j], sizeof(JE_word), 11, f);
|
||||
}
|
||||
efread(&weaponPort[i].cost, sizeof(JE_word), 1, f);
|
||||
efread(&weaponPort[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&weaponPort[i].poweruse, sizeof(JE_word), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SPECIAL_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&special[i].name, 1, 30, f);
|
||||
special[i].name[30] = '\0';
|
||||
efread(&special[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&special[i].pwr, sizeof(JE_byte), 1, f);
|
||||
efread(&special[i].stype, sizeof(JE_byte), 1, f);
|
||||
efread(&special[i].wpn, sizeof(JE_word), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < POWER_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&powerSys[i].name, 1, 30, f);
|
||||
powerSys[i].name[30] = '\0';
|
||||
efread(&powerSys[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&powerSys[i].power, sizeof(JE_shortint), 1, f);
|
||||
efread(&powerSys[i].speed, sizeof(JE_byte), 1, f);
|
||||
efread(&powerSys[i].cost, sizeof(JE_word), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SHIP_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&ships[i].name, 1, 30, f);
|
||||
ships[i].name[30] = '\0';
|
||||
efread(&ships[i].shipgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&ships[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&ships[i].ani, sizeof(JE_byte), 1, f);
|
||||
efread(&ships[i].spd, sizeof(JE_shortint), 1, f);
|
||||
efread(&ships[i].dmg, sizeof(JE_byte), 1, f);
|
||||
efread(&ships[i].cost, sizeof(JE_word), 1, f);
|
||||
efread(&ships[i].bigshipgraphic, sizeof(JE_byte), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < OPTION_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&options[i].name, 1, 30, f);
|
||||
options[i].name[30] = '\0';
|
||||
efread(&options[i].pwr, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&options[i].cost, sizeof(JE_word), 1, f);
|
||||
efread(&options[i].tr, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].option, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].opspd, sizeof(JE_shortint), 1, f);
|
||||
efread(&options[i].ani, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].gr, sizeof(JE_word), 20, f);
|
||||
efread(&options[i].wport, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].wpnum, sizeof(JE_word), 1, f);
|
||||
efread(&options[i].ammo, sizeof(JE_byte), 1, f);
|
||||
efread(&options[i].stop, 1, 1, f); /* override sizeof(JE_boolean) */
|
||||
efread(&options[i].icongr, sizeof(JE_byte), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SHIELD_NUM + 1; ++i)
|
||||
{
|
||||
fseek(f, 1, SEEK_CUR); /* skip string length */
|
||||
efread(&shields[i].name, 1, 30, f);
|
||||
shields[i].name[30] = '\0';
|
||||
efread(&shields[i].tpwr, sizeof(JE_byte), 1, f);
|
||||
efread(&shields[i].mpwr, sizeof(JE_byte), 1, f);
|
||||
efread(&shields[i].itemgraphic, sizeof(JE_word), 1, f);
|
||||
efread(&shields[i].cost, sizeof(JE_word), 1, f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ENEMY_NUM + 1; ++i)
|
||||
{
|
||||
efread(&enemyDat[i].ani, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].tur, sizeof(JE_byte), 3, f);
|
||||
efread(&enemyDat[i].freq, sizeof(JE_byte), 3, f);
|
||||
efread(&enemyDat[i].xmove, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].ymove, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].xaccel, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].yaccel, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].xcaccel, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].ycaccel, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].startx, sizeof(JE_integer), 1, f);
|
||||
efread(&enemyDat[i].starty, sizeof(JE_integer), 1, f);
|
||||
efread(&enemyDat[i].startxc, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].startyc, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].armor, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].esize, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].egraphic, sizeof(JE_word), 20, f);
|
||||
efread(&enemyDat[i].explosiontype, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].animate, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].shapebank, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].xrev, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].yrev, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].dgr, sizeof(JE_word), 1, f);
|
||||
efread(&enemyDat[i].dlevel, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].dani, sizeof(JE_shortint), 1, f);
|
||||
efread(&enemyDat[i].elaunchfreq, sizeof(JE_byte), 1, f);
|
||||
efread(&enemyDat[i].elaunchtype, sizeof(JE_word), 1, f);
|
||||
efread(&enemyDat[i].value, sizeof(JE_integer), 1, f);
|
||||
efread(&enemyDat[i].eenemydie, sizeof(JE_word), 1, f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void JE_initEpisode( JE_byte newEpisode )
|
||||
{
|
||||
if (newEpisode == episodeNum)
|
||||
return;
|
||||
|
||||
episodeNum = newEpisode;
|
||||
|
||||
sprintf(levelFile, "tyrian%d.lvl", episodeNum);
|
||||
sprintf(cube_file, "cubetxt%d.dat", episodeNum);
|
||||
sprintf(episode_file, "levels%d.dat", episodeNum);
|
||||
|
||||
JE_analyzeLevel();
|
||||
JE_loadItemDat();
|
||||
}
|
||||
|
||||
void JE_scanForEpisodes( void )
|
||||
{
|
||||
for (int i = 0; i < EPISODE_MAX; ++i)
|
||||
{
|
||||
char ep_file[20];
|
||||
snprintf(ep_file, sizeof(ep_file), "tyrian%d.lvl", i + 1);
|
||||
episodeAvail[i] = dir_file_exists(data_dir(), ep_file);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int JE_findNextEpisode( void )
|
||||
{
|
||||
unsigned int newEpisode = episodeNum;
|
||||
|
||||
jumpBackToEpisode1 = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
newEpisode++;
|
||||
|
||||
if (newEpisode > EPISODE_MAX)
|
||||
{
|
||||
newEpisode = 1;
|
||||
jumpBackToEpisode1 = true;
|
||||
gameHasRepeated = true;
|
||||
}
|
||||
|
||||
if (episodeAvail[newEpisode-1] || newEpisode == episodeNum)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newEpisode;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef EPISODES_H
|
||||
#define EPISODES_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
#include "lvlmast.h"
|
||||
|
||||
|
||||
/* Episodes and general data */
|
||||
|
||||
#define FIRST_LEVEL 1
|
||||
#define EPISODE_MAX 5
|
||||
#define EPISODE_AVAILABLE 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
JE_word drain;
|
||||
JE_byte shotrepeat;
|
||||
JE_byte multi;
|
||||
JE_word weapani;
|
||||
JE_byte max;
|
||||
JE_byte tx, ty, aim;
|
||||
JE_byte attack[8], del[8]; /* [1..8] */
|
||||
JE_shortint sx[8], sy[8]; /* [1..8] */
|
||||
JE_shortint bx[8], by[8]; /* [1..8] */
|
||||
JE_word sg[8]; /* [1..8] */
|
||||
JE_shortint acceleration, accelerationx;
|
||||
JE_byte circlesize;
|
||||
JE_byte sound;
|
||||
JE_byte trail;
|
||||
JE_byte shipblastfilter;
|
||||
} JE_WeaponType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_byte opnum;
|
||||
JE_word op[2][11]; /* [1..2, 1..11] */
|
||||
JE_word cost;
|
||||
JE_word itemgraphic;
|
||||
JE_word poweruse;
|
||||
} JE_WeaponPortType[PORT_NUM + 1]; /* [0..portnum] */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_word itemgraphic;
|
||||
JE_byte power;
|
||||
JE_shortint speed;
|
||||
JE_word cost;
|
||||
} JE_PowerType[POWER_NUM + 1]; /* [0..powernum] */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_word itemgraphic;
|
||||
JE_byte pwr;
|
||||
JE_byte stype;
|
||||
JE_word wpn;
|
||||
} JE_SpecialType[SPECIAL_NUM + 1]; /* [0..specialnum] */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_byte pwr;
|
||||
JE_word itemgraphic;
|
||||
JE_word cost;
|
||||
JE_byte tr, option;
|
||||
JE_shortint opspd;
|
||||
JE_byte ani;
|
||||
JE_word gr[20]; /* [1..20] */
|
||||
JE_byte wport;
|
||||
JE_word wpnum;
|
||||
JE_byte ammo;
|
||||
JE_boolean stop;
|
||||
JE_byte icongr;
|
||||
} JE_OptionType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_byte tpwr;
|
||||
JE_byte mpwr;
|
||||
JE_word itemgraphic;
|
||||
JE_word cost;
|
||||
} JE_ShieldType[SHIELD_NUM + 1]; /* [0..shieldnum] */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[31]; /* string [30] */
|
||||
JE_word shipgraphic;
|
||||
JE_word itemgraphic;
|
||||
JE_byte ani;
|
||||
JE_shortint spd;
|
||||
JE_byte dmg;
|
||||
JE_word cost;
|
||||
JE_byte bigshipgraphic;
|
||||
} JE_ShipType[SHIP_NUM + 1]; /* [0..shipnum] */
|
||||
|
||||
/* EnemyData */
|
||||
typedef struct
|
||||
{
|
||||
JE_byte ani;
|
||||
JE_byte tur[3]; /* [1..3] */
|
||||
JE_byte freq[3]; /* [1..3] */
|
||||
JE_shortint xmove;
|
||||
JE_shortint ymove;
|
||||
JE_shortint xaccel;
|
||||
JE_shortint yaccel;
|
||||
JE_shortint xcaccel;
|
||||
JE_shortint ycaccel;
|
||||
JE_integer startx;
|
||||
JE_integer starty;
|
||||
JE_shortint startxc;
|
||||
JE_shortint startyc;
|
||||
JE_byte armor;
|
||||
JE_byte esize;
|
||||
JE_word egraphic[20]; /* [1..20] */
|
||||
JE_byte explosiontype;
|
||||
JE_byte animate; /* 0:Not Yet 1:Always 2:When Firing Only */
|
||||
JE_byte shapebank; /* See LEVELMAK.DOC */
|
||||
JE_shortint xrev, yrev;
|
||||
JE_word dgr;
|
||||
JE_shortint dlevel;
|
||||
JE_shortint dani;
|
||||
JE_byte elaunchfreq;
|
||||
JE_word elaunchtype;
|
||||
JE_integer value;
|
||||
JE_word eenemydie;
|
||||
} JE_EnemyDatType[ENEMY_NUM + 1]; /* [0..enemynum] */
|
||||
|
||||
extern JE_WeaponPortType weaponPort;
|
||||
extern JE_WeaponType weapons[WEAP_NUM + 1]; /* [0..weapnum] */
|
||||
extern JE_PowerType powerSys;
|
||||
extern JE_ShipType ships;
|
||||
extern JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */
|
||||
extern JE_ShieldType shields;
|
||||
extern JE_SpecialType special;
|
||||
extern JE_EnemyDatType enemyDat;
|
||||
extern JE_byte initial_episode_num, episodeNum;
|
||||
extern JE_boolean episodeAvail[EPISODE_MAX];
|
||||
|
||||
extern char episode_file[13], cube_file[13];
|
||||
|
||||
extern JE_longint episode1DataLoc;
|
||||
extern JE_boolean bonusLevel;
|
||||
extern JE_boolean jumpBackToEpisode1;
|
||||
|
||||
void JE_loadItemDat( void );
|
||||
void JE_initEpisode( JE_byte newEpisode );
|
||||
unsigned int JE_findNextEpisode( void );
|
||||
void JE_scanForEpisodes( void );
|
||||
|
||||
#endif /* EPISODES_H */
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "file.h"
|
||||
|
||||
#include "opentyr.h"
|
||||
#include "varz.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *custom_data_dir = NULL;
|
||||
|
||||
// finds the Tyrian data directory
|
||||
const char *data_dir( void )
|
||||
{
|
||||
const char *dirs[] =
|
||||
{
|
||||
custom_data_dir,
|
||||
TYRIAN_DIR,
|
||||
"data",
|
||||
".",
|
||||
};
|
||||
|
||||
static const char *dir = NULL;
|
||||
|
||||
if (dir != NULL)
|
||||
return dir;
|
||||
|
||||
for (uint i = 0; i < COUNTOF(dirs); ++i)
|
||||
{
|
||||
if (dirs[i] == NULL)
|
||||
continue;
|
||||
|
||||
FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb");
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
|
||||
dir = dirs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == NULL) // data not found
|
||||
dir = "";
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
// prepend directory and fopen
|
||||
FILE *dir_fopen( const char *dir, const char *file, const char *mode )
|
||||
{
|
||||
char *path = malloc(strlen(dir) + 1 + strlen(file) + 1);
|
||||
sprintf(path, "%s/%s", dir, file);
|
||||
|
||||
FILE *f = fopen(path, mode);
|
||||
fprintf(stderr, "%s\n", path);
|
||||
free(path);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// warn when dir_fopen fails
|
||||
FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode )
|
||||
{
|
||||
FILE *f = dir_fopen(dir, file, mode);
|
||||
|
||||
if (f == NULL)
|
||||
fprintf(stderr, "warning: failed to open '%s': %s\n", file, strerror(errno));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// die when dir_fopen fails
|
||||
FILE *dir_fopen_die( const char *dir, const char *file, const char *mode )
|
||||
{
|
||||
FILE *f = dir_fopen(dir, file, mode);
|
||||
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "error: failed to open '%s': %s\n", file, strerror(errno));
|
||||
fprintf(stderr, "error: One or more of the required Tyrian " TYRIAN_VERSION " data files could not be found.\n"
|
||||
" Please read the README file.\n");
|
||||
JE_tyrianHalt(1);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// check if file can be opened for reading
|
||||
bool dir_file_exists( const char *dir, const char *file )
|
||||
{
|
||||
FILE *f = dir_fopen(dir, file, "rb");
|
||||
if (f != NULL)
|
||||
fclose(f);
|
||||
return (f != NULL);
|
||||
}
|
||||
|
||||
// returns end-of-file position
|
||||
long ftell_eof( FILE *f )
|
||||
{
|
||||
long pos = ftell(f);
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
|
||||
fseek(f, pos, SEEK_SET);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// endian-swapping fread that dies if the expected amount cannot be read
|
||||
size_t efread( void *buffer, size_t size, size_t num, FILE *stream )
|
||||
{
|
||||
size_t num_read = fread(buffer, size, num, stream);
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
switch (size)
|
||||
{
|
||||
case 2:
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint16 *)buffer)[i] = SDL_Swap16(((Uint16 *)buffer)[i]);
|
||||
break;
|
||||
case 4:
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint32 *)buffer)[i] = SDL_Swap32(((Uint32 *)buffer)[i]);
|
||||
break;
|
||||
case 8:
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint64 *)buffer)[i] = SDL_Swap64(((Uint64 *)buffer)[i]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (num_read != num)
|
||||
{
|
||||
fprintf(stderr, "error: An unexpected problem occurred while reading from a file.\n");
|
||||
JE_tyrianHalt(1);
|
||||
}
|
||||
|
||||
return num_read;
|
||||
}
|
||||
|
||||
// endian-swapping fwrite that dies if the expected amount cannot be written
|
||||
size_t efwrite( const void *buffer, size_t size, size_t num, FILE *stream )
|
||||
{
|
||||
void *swap_buffer = NULL;
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
switch (size)
|
||||
{
|
||||
case 2:
|
||||
swap_buffer = malloc(size * num);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint16 *)swap_buffer)[i] = SDL_SwapLE16(((Uint16 *)buffer)[i]);
|
||||
buffer = swap_buffer;
|
||||
break;
|
||||
case 4:
|
||||
swap_buffer = malloc(size * num);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint32 *)swap_buffer)[i] = SDL_SwapLE32(((Uint32 *)buffer)[i]);
|
||||
buffer = swap_buffer;
|
||||
break;
|
||||
case 8:
|
||||
swap_buffer = malloc(size * num);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
((Uint64 *)swap_buffer)[i] = SDL_SwapLE64(((Uint64 *)buffer)[i]);
|
||||
buffer = swap_buffer;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t num_written = fwrite(buffer, size, num, stream);
|
||||
|
||||
if (swap_buffer != NULL)
|
||||
free(swap_buffer);
|
||||
|
||||
if (num_written != num)
|
||||
{
|
||||
fprintf(stderr, "error: An unexpected problem occurred while writing to a file.\n");
|
||||
JE_tyrianHalt(1);
|
||||
}
|
||||
|
||||
return num_written;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include "SDL_endian.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern const char *custom_data_dir;
|
||||
|
||||
const char *data_dir( void );
|
||||
|
||||
FILE *dir_fopen( const char *dir, const char *file, const char *mode );
|
||||
FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode );
|
||||
FILE *dir_fopen_die( const char *dir, const char *file, const char *mode );
|
||||
|
||||
bool dir_file_exists( const char *dir, const char *file );
|
||||
|
||||
long ftell_eof( FILE *f );
|
||||
|
||||
// endian-swapping fread/fwrite that die if the expected amount cannot be read/written
|
||||
size_t efread( void *buffer, size_t size, size_t num, FILE *stream );
|
||||
size_t efwrite( const void *buffer, size_t size, size_t num, FILE *stream );
|
||||
|
||||
#endif // FILE_H
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "font.h"
|
||||
|
||||
#include "fonthand.h"
|
||||
#include "sprite.h"
|
||||
|
||||
/**
|
||||
* \file font.c
|
||||
* \brief Text drawing routines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Draws text in a color specified by hue and value and with a drop
|
||||
* shadow.
|
||||
*
|
||||
* A '~' in the text is not drawn but instead toggles highlighting which
|
||||
* increases \c value by 4.
|
||||
*
|
||||
* \li like JE_dString() if (black == false && shadow_dist == 2 && hue == 15)
|
||||
* \li like JE_textShade() with PART_SHADE if (black == true && shadow_dist == 1)
|
||||
* \li like JE_outTextAndDarken() if (black == false && shadow_dist == 1)
|
||||
* \li like JE_outTextAdjust() with shadow if (black == false && shadow_dist == 2)
|
||||
*
|
||||
* @param surface destination surface
|
||||
* @param x initial x-position in pixels; which direction(s) the text is drawn
|
||||
* from this position depends on the alignment
|
||||
* @param y initial upper y-position in pixels
|
||||
* @param text text to be drawn
|
||||
* @param font style/size of text
|
||||
* @param alignment left_aligned, centered, or right_aligned
|
||||
* @param hue hue component of text color
|
||||
* @param value value component of text color
|
||||
* @param black if true the shadow is drawn as solid black, if false the shadow
|
||||
* is drawn by darkening the pixels of the destination surface
|
||||
* @param shadow_dist distance in pixels that the shadow will be drawn away from
|
||||
* the text. (This is added to both the x and y positions, so a value of
|
||||
* 1 causes the shadow to be drawn 1 pixel right and 1 pixel lower than
|
||||
* the text.)
|
||||
*/
|
||||
void draw_font_hv_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist )
|
||||
{
|
||||
draw_font_dark(surface, x + shadow_dist, y + shadow_dist, text, font, alignment, black);
|
||||
|
||||
draw_font_hv(surface, x, y, text, font, alignment, hue, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draws text in a color specified by hue and value and with a
|
||||
* surrounding shadow.
|
||||
*
|
||||
* A '~' in the text is not drawn but instead toggles highlighting which
|
||||
* increases \c value by 4.
|
||||
*
|
||||
* \li like JE_textShade() with FULL_SHADE if (black == true && shadow_dist == 1)
|
||||
*
|
||||
* @param surface destination surface
|
||||
* @param x initial x-position in pixels; which direction(s) the text is drawn
|
||||
* from this position depends on the alignment
|
||||
* @param y initial upper y-position in pixels
|
||||
* @param text text to be drawn
|
||||
* @param font style/size of text
|
||||
* @param alignment left_aligned, centered, or right_aligned
|
||||
* @param hue hue component of text color
|
||||
* @param value value component of text color
|
||||
* @param black if true the shadow is drawn as solid black, if false the shadow
|
||||
* is drawn by darkening the pixels of the destination surface
|
||||
* @param shadow_dist distance in pixels that the shadows will be drawn away
|
||||
* from the text. (This distance is separately added to and subtracted
|
||||
* from the x position and y position, resulting in four shadows -- one
|
||||
* in each cardinal direction. If this shadow distance is small enough,
|
||||
* this produces a shadow that outlines the text.)
|
||||
*/
|
||||
void draw_font_hv_full_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist )
|
||||
{
|
||||
draw_font_dark(surface, x, y - shadow_dist, text, font, alignment, black);
|
||||
draw_font_dark(surface, x + shadow_dist, y, text, font, alignment, black);
|
||||
draw_font_dark(surface, x, y + shadow_dist, text, font, alignment, black);
|
||||
draw_font_dark(surface, x - shadow_dist, y, text, font, alignment, black);
|
||||
|
||||
draw_font_hv(surface, x, y, text, font, alignment, hue, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draws text in a color specified by hue and value.
|
||||
*
|
||||
* A '~' in the text is not drawn but instead toggles highlighting which
|
||||
* increases \c value by 4.
|
||||
*
|
||||
* \li like JE_outText() with (brightness >= 0)
|
||||
* \li like JE_outTextAdjust() without shadow
|
||||
*
|
||||
* @param surface destination surface
|
||||
* @param x initial x-position in pixels; which direction(s) the text is drawn
|
||||
* from this position depends on the alignment
|
||||
* @param y initial upper y-position in pixels
|
||||
* @param text text to be drawn
|
||||
* @param font style/size of text
|
||||
* @param alignment left_aligned, centered, or right_aligned
|
||||
* @param hue hue component of text color
|
||||
* @param value value component of text color
|
||||
*/
|
||||
void draw_font_hv( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value )
|
||||
{
|
||||
switch (alignment)
|
||||
{
|
||||
case left_aligned:
|
||||
break;
|
||||
case centered:
|
||||
x -= JE_textWidth(text, font) / 2;
|
||||
break;
|
||||
case right_aligned:
|
||||
x -= JE_textWidth(text, font);
|
||||
break;
|
||||
}
|
||||
|
||||
bool highlight = false;
|
||||
|
||||
for (; *text != '\0'; ++text)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)*text];
|
||||
|
||||
switch (*text)
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
highlight = !highlight;
|
||||
if (highlight)
|
||||
value += 4;
|
||||
else
|
||||
value -= 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(font, sprite_id))
|
||||
{
|
||||
blit_sprite_hv(surface, x, y, font, sprite_id, hue, value);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draws blended text in a color specified by hue and value.
|
||||
*
|
||||
* Corresponds to blit_sprite_hv_blend()
|
||||
*
|
||||
* \li like JE_outTextModify()
|
||||
*
|
||||
* @param surface destination surface
|
||||
* @param x initial x-position in pixels; which direction(s) the text is drawn
|
||||
* from this position depends on the alignment
|
||||
* @param y initial upper y-position in pixels
|
||||
* @param text text to be drawn
|
||||
* @param font style/size of text
|
||||
* @param alignment left_aligned, centered, or right_aligned
|
||||
* @param hue hue component of text color
|
||||
* @param value value component of text color
|
||||
*/
|
||||
void draw_font_hv_blend( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value )
|
||||
{
|
||||
switch (alignment)
|
||||
{
|
||||
case left_aligned:
|
||||
break;
|
||||
case centered:
|
||||
x -= JE_textWidth(text, font) / 2;
|
||||
break;
|
||||
case right_aligned:
|
||||
x -= JE_textWidth(text, font);
|
||||
break;
|
||||
}
|
||||
|
||||
for (; *text != '\0'; ++text)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)*text];
|
||||
|
||||
switch (*text)
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(font, sprite_id))
|
||||
{
|
||||
blit_sprite_hv_blend(surface, x, y, font, sprite_id, hue, value);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draws darkened text.
|
||||
*
|
||||
* Corresponds to blit_sprite_dark()
|
||||
*
|
||||
* \li like JE_outText() with (brightness < 0) if (black == true)
|
||||
*
|
||||
* @param surface destination surface
|
||||
* @param x initial x-position in pixels; which direction(s) the text is drawn
|
||||
* from this position depends on the alignment
|
||||
* @param y initial upper y-position in pixels
|
||||
* @param text text to be drawn
|
||||
* @param font style/size of text
|
||||
* @param alignment left_aligned, centered, or right_aligned
|
||||
* @param black if true text is drawn as solid black, if false text is drawn by
|
||||
* darkening the pixels of the destination surface
|
||||
*/
|
||||
void draw_font_dark( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, bool black )
|
||||
{
|
||||
switch (alignment)
|
||||
{
|
||||
case left_aligned:
|
||||
break;
|
||||
case centered:
|
||||
x -= JE_textWidth(text, font) / 2;
|
||||
break;
|
||||
case right_aligned:
|
||||
x -= JE_textWidth(text, font);
|
||||
break;
|
||||
}
|
||||
|
||||
for (; *text != '\0'; ++text)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)*text];
|
||||
|
||||
switch (*text)
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(font, sprite_id))
|
||||
{
|
||||
blit_sprite_dark(surface, x, y, font, sprite_id, black);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
large_font = 0,
|
||||
normal_font = 1,
|
||||
small_font = 2
|
||||
}
|
||||
Font;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
left_aligned,
|
||||
centered,
|
||||
right_aligned
|
||||
}
|
||||
FontAlignment;
|
||||
|
||||
void draw_font_hv_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist );
|
||||
void draw_font_hv_full_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist );
|
||||
|
||||
void draw_font_hv( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value );
|
||||
void draw_font_hv_blend( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value );
|
||||
void draw_font_dark( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, bool black );
|
||||
|
||||
#endif // FONT_H
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "fonthand.h"
|
||||
|
||||
#include "network.h"
|
||||
#include "nortsong.h"
|
||||
#include "nortvars.h"
|
||||
#include "opentyr.h"
|
||||
#include "params.h"
|
||||
#include "sprite.h"
|
||||
#include "vga256d.h"
|
||||
#include "video.h"
|
||||
|
||||
const int font_ascii[256] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 26, 33, 60, 61, 62, -1, 32, 64, 65, 63, 84, 29, 83, 28, 80, // !"#$%&'()*+,-./
|
||||
79, 70, 71, 72, 73, 74, 75, 76, 77, 78, 31, 30, -1, 85, -1, 27, // 0123456789:;<=>?
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // @ABCDEFGHIJKLMNO
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 68, 82, 69, -1, -1, // PQRSTUVWXYZ[\]^_
|
||||
-1, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // `abcdefghijklmno
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 66, 81, 67, -1, -1, // pqrstuvwxyz{|}~⌂
|
||||
|
||||
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, // ÇüéâäàåçêëèïîìÄÅ
|
||||
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, // ÉæÆôöòûùÿÖÜ¢£¥₧ƒ
|
||||
118, 119, 120, 121, 122, 123, 124, 125, 126, -1, -1, -1, -1, -1, -1, -1, // áíóúñѪº¿
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/* shape constants included in newshape.h */
|
||||
|
||||
JE_byte textGlowFont, textGlowBrightness = 6;
|
||||
|
||||
JE_boolean levelWarningDisplay;
|
||||
JE_byte levelWarningLines;
|
||||
char levelWarningText[10][61]; /* [1..10] of string [60] */
|
||||
JE_boolean warningRed;
|
||||
|
||||
JE_byte warningSoundDelay;
|
||||
JE_word armorShipDelay;
|
||||
JE_byte warningCol;
|
||||
JE_shortint warningColChange;
|
||||
|
||||
void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font )
|
||||
{
|
||||
const int defaultBrightness = -3;
|
||||
|
||||
int bright = 0;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
switch (s[i])
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
bright = (bright == 0) ? 2 : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1)
|
||||
{
|
||||
blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false);
|
||||
blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, 0xf, defaultBrightness + bright);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int JE_fontCenter( const char *s, unsigned int font )
|
||||
{
|
||||
return 160 - (JE_textWidth(s, font) / 2);
|
||||
}
|
||||
|
||||
int JE_textWidth( const char *s, unsigned int font )
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
if (s[i] == ' ')
|
||||
x += 6;
|
||||
else if (sprite_id != -1)
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype )
|
||||
{
|
||||
switch (shadetype)
|
||||
{
|
||||
case PART_SHADE:
|
||||
JE_outText(screen, x+1, y+1, s, 0, -1);
|
||||
JE_outText(screen, x, y, s, colorbank, brightness);
|
||||
break;
|
||||
case FULL_SHADE:
|
||||
JE_outText(screen, x-1, y, s, 0, -1);
|
||||
JE_outText(screen, x+1, y, s, 0, -1);
|
||||
JE_outText(screen, x, y-1, s, 0, -1);
|
||||
JE_outText(screen, x, y+1, s, 0, -1);
|
||||
JE_outText(screen, x, y, s, colorbank, brightness);
|
||||
break;
|
||||
case DARKEN:
|
||||
JE_outTextAndDarken(screen, x+1, y+1, s, colorbank, brightness, TINY_FONT);
|
||||
break;
|
||||
case TRICK:
|
||||
JE_outTextModify(screen, x, y, s, colorbank, brightness, TINY_FONT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness )
|
||||
{
|
||||
int bright = 0;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
switch (s[i])
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
bright = (bright == 0) ? 4 : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
|
||||
{
|
||||
if (brightness >= 0)
|
||||
blit_sprite_hv_unsafe(screen, x, y, TINY_FONT, sprite_id, colorbank, brightness + bright);
|
||||
else
|
||||
blit_sprite_dark(screen, x, y, TINY_FONT, sprite_id, true);
|
||||
|
||||
x += sprite(TINY_FONT, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font )
|
||||
{
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
if (s[i] == ' ')
|
||||
{
|
||||
x += 6;
|
||||
}
|
||||
else if (sprite_id != -1)
|
||||
{
|
||||
blit_sprite_hv_blend(screen, x, y, font, sprite_id, filter, brightness);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, JE_boolean shadow )
|
||||
{
|
||||
int bright = 0;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
switch (s[i])
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
bright = (bright == 0) ? 4 : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
|
||||
{
|
||||
if (shadow)
|
||||
blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false);
|
||||
blit_sprite_hv(screen, x, y, font, sprite_id, filter, brightness + bright);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font )
|
||||
{
|
||||
int bright = 0;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; ++i)
|
||||
{
|
||||
int sprite_id = font_ascii[(unsigned char)s[i]];
|
||||
|
||||
switch (s[i])
|
||||
{
|
||||
case ' ':
|
||||
x += 6;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
bright = (bright == 0) ? 4 : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
|
||||
{
|
||||
blit_sprite_dark(screen, x + 1, y + 1, font, sprite_id, false);
|
||||
blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, colorbank, brightness + bright);
|
||||
|
||||
x += sprite(font, sprite_id)->width + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_updateWarning( SDL_Surface * screen )
|
||||
{
|
||||
if (delaycount2() == 0)
|
||||
{ /*Update Color Bars*/
|
||||
|
||||
warningCol += warningColChange;
|
||||
if (warningCol > 14 * 16 + 10 || warningCol < 14 * 16 + 4)
|
||||
{
|
||||
warningColChange = -warningColChange;
|
||||
}
|
||||
fill_rectangle_xy(screen, 0, 0, 319, 5, warningCol);
|
||||
fill_rectangle_xy(screen, 0, 194, 319, 199, warningCol);
|
||||
JE_showVGA();
|
||||
|
||||
setjasondelay2(6);
|
||||
|
||||
if (warningSoundDelay > 0)
|
||||
{
|
||||
warningSoundDelay--;
|
||||
}
|
||||
else
|
||||
{
|
||||
warningSoundDelay = 14;
|
||||
JE_playSampleNum(S_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s )
|
||||
{
|
||||
JE_integer z;
|
||||
JE_byte c = 15;
|
||||
|
||||
if (warningRed)
|
||||
{
|
||||
c = 7;
|
||||
}
|
||||
|
||||
JE_outTextAdjust(screen, x - 1, y, s, 0, -12, textGlowFont, false);
|
||||
JE_outTextAdjust(screen, x, y - 1, s, 0, -12, textGlowFont, false);
|
||||
JE_outTextAdjust(screen, x + 1, y, s, 0, -12, textGlowFont, false);
|
||||
JE_outTextAdjust(screen, x, y + 1, s, 0, -12, textGlowFont, false);
|
||||
if (frameCountMax > 0)
|
||||
for (z = 1; z <= 12; z++)
|
||||
{
|
||||
setjasondelay(frameCountMax);
|
||||
JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false);
|
||||
if (JE_anyButton())
|
||||
{
|
||||
frameCountMax = 0;
|
||||
}
|
||||
|
||||
NETWORK_KEEP_ALIVE();
|
||||
|
||||
JE_showVGA();
|
||||
|
||||
wait_delay();
|
||||
}
|
||||
for (z = (frameCountMax == 0) ? 6 : 12; z >= textGlowBrightness; z--)
|
||||
{
|
||||
setjasondelay(frameCountMax);
|
||||
JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false);
|
||||
if (JE_anyButton())
|
||||
{
|
||||
frameCountMax = 0;
|
||||
}
|
||||
|
||||
NETWORK_KEEP_ALIVE();
|
||||
|
||||
JE_showVGA();
|
||||
|
||||
wait_delay();
|
||||
}
|
||||
textGlowBrightness = 6;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef FONTHAND_H
|
||||
#define FONTHAND_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#define PART_SHADE 0
|
||||
#define FULL_SHADE 1
|
||||
#define DARKEN 2
|
||||
#define TRICK 3
|
||||
#define NO_SHADE 255
|
||||
|
||||
extern const int font_ascii[256];
|
||||
|
||||
extern JE_byte textGlowFont, textGlowBrightness;
|
||||
extern JE_boolean levelWarningDisplay;
|
||||
extern JE_byte levelWarningLines;
|
||||
extern char levelWarningText[10][61];
|
||||
extern JE_boolean warningRed;
|
||||
extern JE_byte warningSoundDelay;
|
||||
extern JE_word armorShipDelay;
|
||||
extern JE_byte warningCol;
|
||||
extern JE_shortint warningColChange;
|
||||
|
||||
void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font );
|
||||
|
||||
int JE_fontCenter( const char *s, unsigned int font );
|
||||
int JE_textWidth( const char *s, unsigned int font );
|
||||
void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype );
|
||||
void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness );
|
||||
void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font );
|
||||
void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, bool shadow );
|
||||
void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font );
|
||||
|
||||
void JE_updateWarning( SDL_Surface * screen );
|
||||
void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s );
|
||||
|
||||
#endif /* FONTHAND_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef GAME_MENU_H
|
||||
#define GAME_MENU_H
|
||||
|
||||
#include "helptext.h"
|
||||
#include "opentyr.h"
|
||||
|
||||
typedef JE_byte JE_MenuChoiceType[MENU_MAX];
|
||||
|
||||
JE_longint JE_cashLeft( void );
|
||||
void JE_itemScreen( void );
|
||||
|
||||
void load_cubes( void );
|
||||
bool load_cube( int cube_slot, int cube_index );
|
||||
|
||||
void JE_drawItem( JE_byte itemType, JE_word itemNum, JE_word x, JE_word y );
|
||||
void JE_drawMenuHeader( void );
|
||||
void JE_drawMenuChoices( void );
|
||||
void JE_updateNavScreen( void );
|
||||
void JE_drawNavLines( JE_boolean dark );
|
||||
void JE_drawLines( SDL_Surface *surface, JE_boolean dark );
|
||||
void JE_drawDots( void );
|
||||
void JE_drawPlanet( JE_byte planetNum );
|
||||
void draw_ship_illustration( void );
|
||||
void JE_scaleBitmap( SDL_Surface *dst, const SDL_Surface *src, int x1, int y1, int x2, int y2 );
|
||||
void JE_initWeaponView( void );
|
||||
void JE_computeDots( void );
|
||||
JE_integer JE_partWay( JE_integer start, JE_integer finish, JE_byte dots, JE_byte dist );
|
||||
void JE_doShipSpecs( void );
|
||||
void JE_drawMainMenuHelpText( void );
|
||||
JE_boolean JE_quitRequest( void );
|
||||
void JE_genItemMenu( JE_byte itemnum );
|
||||
void JE_scaleInPicture( SDL_Surface *dst, const SDL_Surface *src );
|
||||
void JE_drawScore( void );
|
||||
void JE_menuFunction( JE_byte select );
|
||||
void JE_drawShipSpecs( SDL_Surface *, SDL_Surface * );
|
||||
void JE_weaponSimUpdate( void );
|
||||
void JE_weaponViewFrame( void );
|
||||
|
||||
#endif // GAME_MENU_H
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "helptext.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "episodes.h"
|
||||
#include "file.h"
|
||||
#include "fonthand.h"
|
||||
#include "menus.h"
|
||||
#include "opentyr.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
const JE_byte menuHelp[MENU_MAX][11] = /* [1..maxmenu, 1..11] */
|
||||
{
|
||||
{ 1, 34, 2, 3, 4, 5, 0, 0, 0, 0, 0 },
|
||||
{ 6, 7, 8, 9, 10, 11, 11, 12, 0, 0, 0 },
|
||||
{ 13, 14, 15, 15, 16, 17, 12, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 4, 30, 30, 3, 5, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 16, 17, 15, 15, 12, 0, 0, 0, 0, 0, 0 },
|
||||
{ 31, 31, 31, 31, 32, 12, 0, 0, 0, 0, 0 },
|
||||
{ 4, 34, 3, 5, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
JE_byte verticalHeight = 7;
|
||||
JE_byte helpBoxColor = 12;
|
||||
JE_byte helpBoxBrightness = 1;
|
||||
JE_byte helpBoxShadeType = FULL_SHADE;
|
||||
|
||||
char helpTxt[39][231]; /* [1..39] of string [230] */
|
||||
char pName[21][16]; /* [1..21] of string [15] */
|
||||
char miscText[HELPTEXT_MISCTEXT_COUNT][42]; /* [1..68] of string [41] */
|
||||
char miscTextB[HELPTEXT_MISCTEXTB_COUNT][HELPTEXT_MISCTEXTB_SIZE]; /* [1..5] of string [10] */
|
||||
char keyName[8][18]; /* [1..8] of string [17] */
|
||||
char menuText[7][HELPTEXT_MENUTEXT_SIZE]; /* [1..7] of string [20] */
|
||||
char outputs[9][31]; /* [1..9] of string [30] */
|
||||
char topicName[6][21]; /* [1..6] of string [20] */
|
||||
char mainMenuHelp[HELPTEXT_MAINMENUHELP_COUNT][66]; /* [1..34] of string [65] */
|
||||
char inGameText[6][21]; /* [1..6] of string [20] */
|
||||
char detailLevel[6][13]; /* [1..6] of string [12] */
|
||||
char gameSpeedText[5][13]; /* [1..5] of string [12] */
|
||||
char inputDevices[3][13]; /* [1..3] of string [12] */
|
||||
char networkText[HELPTEXT_NETWORKTEXT_COUNT][HELPTEXT_NETWORKTEXT_SIZE]; /* [1..4] of string [20] */
|
||||
char difficultyNameB[11][21]; /* [0..9] of string [20] */
|
||||
char joyButtonNames[5][21]; /* [1..5] of string [20] */
|
||||
char superShips[HELPTEXT_SUPERSHIPS_COUNT][26]; /* [0..10] of string [25] */
|
||||
char specialName[HELPTEXT_SPECIALNAME_COUNT][10]; /* [1..9] of string [9] */
|
||||
char destructHelp[25][22]; /* [1..25] of string [21] */
|
||||
char weaponNames[17][17]; /* [1..17] of string [16] */
|
||||
char destructModeName[DESTRUCT_MODES][13]; /* [1..destructmodes] of string [12] */
|
||||
char shipInfo[HELPTEXT_SHIPINFO_COUNT][2][256]; /* [1..13, 1..2] of string */
|
||||
char menuInt[MENU_MAX+1][11][18]; /* [0..14, 1..11] of string [17] */
|
||||
|
||||
|
||||
void decrypt_pascal_string( char *s, int len )
|
||||
{
|
||||
static const unsigned char crypt_key[] = { 204, 129, 63, 255, 71, 19, 25, 62, 1, 99 };
|
||||
|
||||
for (int i = len - 1; i >= 0; --i)
|
||||
{
|
||||
s[i] ^= crypt_key[i % sizeof(crypt_key)];
|
||||
if (i > 0)
|
||||
s[i] ^= s[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
void read_encrypted_pascal_string( char *s, int size, FILE *f )
|
||||
{
|
||||
int len = getc(f);
|
||||
if (len != EOF)
|
||||
{
|
||||
int skip = MAX((len + 1) - size, 0);
|
||||
assert(skip == 0);
|
||||
|
||||
len -= skip;
|
||||
efread(s, 1, len, f);
|
||||
if (size > 0)
|
||||
s[len] = '\0';
|
||||
fseek(f, skip, SEEK_CUR);
|
||||
|
||||
decrypt_pascal_string(s, len);
|
||||
}
|
||||
}
|
||||
|
||||
void skip_pascal_string( FILE *f )
|
||||
{
|
||||
int len = getc(f);
|
||||
fseek(f, len, SEEK_CUR);
|
||||
}
|
||||
|
||||
void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth )
|
||||
{
|
||||
JE_byte startpos, endpos, pos;
|
||||
JE_boolean endstring;
|
||||
|
||||
char substring[256];
|
||||
|
||||
if (strlen(message) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pos = 1;
|
||||
endpos = 0;
|
||||
endstring = false;
|
||||
|
||||
do
|
||||
{
|
||||
startpos = endpos + 1;
|
||||
|
||||
do
|
||||
{
|
||||
endpos = pos;
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
if (pos == strlen(message))
|
||||
{
|
||||
endstring = true;
|
||||
if ((unsigned)(pos - startpos) < boxwidth)
|
||||
{
|
||||
endpos = pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!(message[pos-1] == ' ' || endstring));
|
||||
|
||||
} while (!((unsigned)(pos - startpos) > boxwidth || endstring));
|
||||
|
||||
SDL_strlcpy(substring, message + startpos - 1, MIN((size_t)(endpos - startpos + 1), sizeof(substring)));
|
||||
JE_textShade(screen, x, y, substring, helpBoxColor, helpBoxBrightness, helpBoxShadeType);
|
||||
|
||||
y += verticalHeight;
|
||||
|
||||
} while (!endstring);
|
||||
|
||||
if (endpos != pos + 1)
|
||||
{
|
||||
JE_textShade(screen, x, y, message + endpos, helpBoxColor, helpBoxBrightness, helpBoxShadeType);
|
||||
}
|
||||
|
||||
helpBoxColor = 12;
|
||||
helpBoxShadeType = FULL_SHADE;
|
||||
}
|
||||
|
||||
void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth )
|
||||
{
|
||||
JE_helpBox(screen, x, y, helpTxt[messagenum-1], boxwidth);
|
||||
}
|
||||
|
||||
void JE_loadHelpText( void )
|
||||
{
|
||||
const unsigned int menuInt_entries[MENU_MAX + 1] = { -1, 7, 9, 8, -1, -1, 11, -1, -1, -1, 6, 4, 6, 7, 5 };
|
||||
|
||||
FILE *f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb");
|
||||
efread(&episode1DataLoc, sizeof(JE_longint), 1, f);
|
||||
|
||||
/*Online Help*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(helpTxt); ++i)
|
||||
read_encrypted_pascal_string(helpTxt[i], sizeof(helpTxt[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Planet names*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(pName); ++i)
|
||||
read_encrypted_pascal_string(pName[i], sizeof(pName[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Miscellaneous text*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(miscText); ++i)
|
||||
read_encrypted_pascal_string(miscText[i], sizeof(miscText[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Little Miscellaneous text*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(miscTextB); ++i)
|
||||
read_encrypted_pascal_string(miscTextB[i], sizeof(miscTextB[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Key names*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[6]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[6][i], sizeof(menuInt[6][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Main Menu*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(menuText); ++i)
|
||||
read_encrypted_pascal_string(menuText[i], sizeof(menuText[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Event text*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(outputs); ++i)
|
||||
read_encrypted_pascal_string(outputs[i], sizeof(outputs[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Help topics*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(topicName); ++i)
|
||||
read_encrypted_pascal_string(topicName[i], sizeof(topicName[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Main Menu Help*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(mainMenuHelp); ++i)
|
||||
read_encrypted_pascal_string(mainMenuHelp[i], sizeof(mainMenuHelp[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 1 - Main*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[1]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[1][i], sizeof(menuInt[1][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 2 - Items*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[2]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[2][i], sizeof(menuInt[2][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 3 - Options*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[3]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[3][i], sizeof(menuInt[3][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*InGame Menu*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(inGameText); ++i)
|
||||
read_encrypted_pascal_string(inGameText[i], sizeof(inGameText[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Detail Level*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(detailLevel); ++i)
|
||||
read_encrypted_pascal_string(detailLevel[i], sizeof(detailLevel[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Game speed text*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(gameSpeedText); ++i)
|
||||
read_encrypted_pascal_string(gameSpeedText[i], sizeof(gameSpeedText[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
// episode names
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(episode_name); ++i)
|
||||
read_encrypted_pascal_string(episode_name[i], sizeof(episode_name[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
// difficulty names
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(difficulty_name); ++i)
|
||||
read_encrypted_pascal_string(difficulty_name[i], sizeof(difficulty_name[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
// gameplay mode names
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(gameplay_name); ++i)
|
||||
read_encrypted_pascal_string(gameplay_name[i], sizeof(gameplay_name[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 10 - 2Player Main*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[10]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[10][i], sizeof(menuInt[10][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Input Devices*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(inputDevices); ++i)
|
||||
read_encrypted_pascal_string(inputDevices[i], sizeof(inputDevices[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Network text*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(networkText); ++i)
|
||||
read_encrypted_pascal_string(networkText[i], sizeof(networkText[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 11 - 2Player Network*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[11]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[11][i], sizeof(menuInt[11][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*HighScore Difficulty Names*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(difficultyNameB); ++i)
|
||||
read_encrypted_pascal_string(difficultyNameB[i], sizeof(difficultyNameB[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 12 - Network Options*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[12]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[12][i], sizeof(menuInt[12][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Menu 13 - Joystick*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < menuInt_entries[13]; ++i)
|
||||
read_encrypted_pascal_string(menuInt[13][i], sizeof(menuInt[13][i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Joystick Button Assignments*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(joyButtonNames); ++i)
|
||||
read_encrypted_pascal_string(joyButtonNames[i], sizeof(joyButtonNames[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*SuperShips - For Super Arcade Mode*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(superShips); ++i)
|
||||
read_encrypted_pascal_string(superShips[i], sizeof(superShips[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*SuperShips - For Super Arcade Mode*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(specialName); ++i)
|
||||
read_encrypted_pascal_string(specialName[i], sizeof(specialName[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Secret DESTRUCT game*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(destructHelp); ++i)
|
||||
read_encrypted_pascal_string(destructHelp[i], sizeof(destructHelp[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Secret DESTRUCT weapons*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(weaponNames); ++i)
|
||||
read_encrypted_pascal_string(weaponNames[i], sizeof(weaponNames[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*Secret DESTRUCT modes*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(destructModeName); ++i)
|
||||
read_encrypted_pascal_string(destructModeName[i], sizeof(destructModeName[i]), f);
|
||||
skip_pascal_string(f);
|
||||
|
||||
/*NEW: Ship Info*/
|
||||
skip_pascal_string(f);
|
||||
for (unsigned int i = 0; i < COUNTOF(shipInfo); ++i)
|
||||
{
|
||||
read_encrypted_pascal_string(shipInfo[i][0], sizeof(shipInfo[i][0]), f);
|
||||
read_encrypted_pascal_string(shipInfo[i][1], sizeof(shipInfo[i][1]), f);
|
||||
}
|
||||
skip_pascal_string(f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef HELPTEXT_H
|
||||
#define HELPTEXT_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define MENU_MAX 14
|
||||
|
||||
#define DESTRUCT_MODES 5
|
||||
|
||||
extern const JE_byte menuHelp[MENU_MAX][11]; /* [1..14, 1..11] */
|
||||
|
||||
extern JE_byte verticalHeight;
|
||||
extern JE_byte helpBoxColor, helpBoxBrightness, helpBoxShadeType;
|
||||
|
||||
#define HELPTEXT_MISCTEXT_COUNT 68
|
||||
#define HELPTEXT_MISCTEXTB_COUNT 5
|
||||
#define HELPTEXT_MISCTEXTB_SIZE 11
|
||||
#define HELPTEXT_MENUTEXT_SIZE 21
|
||||
#define HELPTEXT_MAINMENUHELP_COUNT 34
|
||||
#define HELPTEXT_NETWORKTEXT_COUNT 4
|
||||
#define HELPTEXT_NETWORKTEXT_SIZE 22
|
||||
#define HELPTEXT_SUPERSHIPS_COUNT 11
|
||||
#define HELPTEXT_SPECIALNAME_COUNT 9
|
||||
#define HELPTEXT_SHIPINFO_COUNT 13
|
||||
|
||||
extern char helpTxt[39][231];
|
||||
extern char pName[21][16];
|
||||
extern char miscText[HELPTEXT_MISCTEXT_COUNT][42];
|
||||
extern char miscTextB[HELPTEXT_MISCTEXTB_COUNT][HELPTEXT_MISCTEXTB_SIZE];
|
||||
extern char keyName[8][18];
|
||||
extern char menuText[7][HELPTEXT_MENUTEXT_SIZE];
|
||||
extern char outputs[9][31];
|
||||
extern char topicName[6][21];
|
||||
extern char mainMenuHelp[HELPTEXT_MAINMENUHELP_COUNT][66];
|
||||
extern char inGameText[6][21];
|
||||
extern char detailLevel[6][13];
|
||||
extern char gameSpeedText[5][13];
|
||||
extern char inputDevices[3][13];
|
||||
extern char networkText[HELPTEXT_NETWORKTEXT_COUNT][HELPTEXT_NETWORKTEXT_SIZE];
|
||||
extern char difficultyNameB[11][21];
|
||||
extern char joyButtonNames[5][21];
|
||||
extern char superShips[HELPTEXT_SUPERSHIPS_COUNT][26];
|
||||
extern char specialName[HELPTEXT_SPECIALNAME_COUNT][10];
|
||||
extern char destructHelp[25][22];
|
||||
extern char weaponNames[17][17];
|
||||
extern char destructModeName[DESTRUCT_MODES][13];
|
||||
extern char shipInfo[HELPTEXT_SHIPINFO_COUNT][2][256];
|
||||
extern char menuInt[MENU_MAX+1][11][18];
|
||||
|
||||
void read_encrypted_pascal_string( char *s, int size, FILE *f );
|
||||
void skip_pascal_string( FILE *f );
|
||||
|
||||
void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth );
|
||||
void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth );
|
||||
void JE_loadHelpText( void );
|
||||
|
||||
#endif /* HELPTEXT_H */
|
||||
|
||||
@@ -0,0 +1,653 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "joystick.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "config_file.h"
|
||||
#include "file.h"
|
||||
#include "keyboard.h"
|
||||
#include "nortsong.h"
|
||||
#include "opentyr.h"
|
||||
#include "params.h"
|
||||
#include "varz.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
int joystick_axis_threshold( int j, int value );
|
||||
int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] );
|
||||
|
||||
const char *assignment_to_code( const Joystick_assignment *assignment );
|
||||
void code_to_assignment( Joystick_assignment *assignment, const char *buffer );
|
||||
|
||||
int joystick_repeat_delay = 300; // milliseconds, repeat delay for buttons
|
||||
bool joydown = false; // any joystick buttons down, updated by poll_joysticks()
|
||||
bool ignore_joystick = false;
|
||||
|
||||
int joysticks = 0;
|
||||
Joystick *joystick = NULL;
|
||||
|
||||
static const int joystick_analog_max = 32767;
|
||||
|
||||
// eliminates axis movement below the threshold
|
||||
int joystick_axis_threshold( int j, int value )
|
||||
{
|
||||
assert(j < joysticks);
|
||||
|
||||
bool negative = value < 0;
|
||||
if (negative)
|
||||
value = -value;
|
||||
|
||||
if (value <= joystick[j].threshold * 1000)
|
||||
return 0;
|
||||
|
||||
value -= joystick[j].threshold * 1000;
|
||||
|
||||
return negative ? -value : value;
|
||||
}
|
||||
|
||||
// converts joystick axis to sane Tyrian-usable value (based on sensitivity)
|
||||
int joystick_axis_reduce( int j, int value )
|
||||
{
|
||||
assert(j < joysticks);
|
||||
|
||||
value = joystick_axis_threshold(j, value);
|
||||
|
||||
if (value == 0)
|
||||
return 0;
|
||||
|
||||
return value / (3000 - 200 * joystick[j].sensitivity);
|
||||
}
|
||||
|
||||
// converts analog joystick axes to an angle
|
||||
// returns false if axes are centered (there is no angle)
|
||||
bool joystick_analog_angle( int j, float *angle )
|
||||
{
|
||||
assert(j < joysticks);
|
||||
|
||||
float x = joystick_axis_threshold(j, joystick[j].x), y = joystick_axis_threshold(j, joystick[j].y);
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
*angle += atanf(-y / x);
|
||||
*angle += (x < 0) ? -M_PI_2 : M_PI_2;
|
||||
return true;
|
||||
}
|
||||
else if (y != 0)
|
||||
{
|
||||
*angle += y < 0 ? M_PI : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* gives back value 0..joystick_analog_max indicating that one of the assigned
|
||||
* buttons has been pressed or that one of the assigned axes/hats has been moved
|
||||
* in the assigned direction
|
||||
*/
|
||||
int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] )
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int temp = 0;
|
||||
|
||||
switch (assignment[i].type)
|
||||
{
|
||||
case NONE:
|
||||
continue;
|
||||
|
||||
case AXIS:
|
||||
temp = SDL_JoystickGetAxis(joystick_handle, assignment[i].num);
|
||||
|
||||
if (assignment[i].negative_axis)
|
||||
temp = -temp;
|
||||
break;
|
||||
|
||||
case BUTTON:
|
||||
temp = SDL_JoystickGetButton(joystick_handle, assignment[i].num) == 1 ? joystick_analog_max : 0;
|
||||
break;
|
||||
|
||||
case HAT:
|
||||
temp = SDL_JoystickGetHat(joystick_handle, assignment[i].num);
|
||||
|
||||
if (assignment[i].x_axis)
|
||||
temp &= SDL_HAT_LEFT | SDL_HAT_RIGHT;
|
||||
else
|
||||
temp &= SDL_HAT_UP | SDL_HAT_DOWN;
|
||||
|
||||
if (assignment[i].negative_axis)
|
||||
temp &= SDL_HAT_LEFT | SDL_HAT_UP;
|
||||
else
|
||||
temp &= SDL_HAT_RIGHT | SDL_HAT_DOWN;
|
||||
|
||||
temp = temp ? joystick_analog_max : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (temp > result)
|
||||
result = temp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// updates joystick state
|
||||
void poll_joystick( int j )
|
||||
{
|
||||
assert(j < joysticks);
|
||||
|
||||
if (joystick[j].handle == NULL)
|
||||
return;
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
|
||||
// indicates that a direction/action was pressed since last poll
|
||||
joystick[j].input_pressed = false;
|
||||
|
||||
// indicates that an direction/action has been held long enough to fake a repeat press
|
||||
bool repeat = joystick[j].joystick_delay < SDL_GetTicks();
|
||||
|
||||
// update direction state
|
||||
for (uint d = 0; d < COUNTOF(joystick[j].direction); d++)
|
||||
{
|
||||
bool old = joystick[j].direction[d];
|
||||
|
||||
joystick[j].analog_direction[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d]);
|
||||
joystick[j].direction[d] = joystick[j].analog_direction[d] > (joystick_analog_max / 2);
|
||||
joydown |= joystick[j].direction[d];
|
||||
|
||||
joystick[j].direction_pressed[d] = joystick[j].direction[d] && (!old || repeat);
|
||||
joystick[j].input_pressed |= joystick[j].direction_pressed[d];
|
||||
}
|
||||
|
||||
joystick[j].x = -joystick[j].analog_direction[3] + joystick[j].analog_direction[1];
|
||||
joystick[j].y = -joystick[j].analog_direction[0] + joystick[j].analog_direction[2];
|
||||
|
||||
// update action state
|
||||
for (uint d = 0; d < COUNTOF(joystick[j].action); d++)
|
||||
{
|
||||
bool old = joystick[j].action[d];
|
||||
|
||||
joystick[j].action[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d + COUNTOF(joystick[j].direction)]) > (joystick_analog_max / 2);
|
||||
joydown |= joystick[j].action[d];
|
||||
|
||||
joystick[j].action_pressed[d] = joystick[j].action[d] && (!old || repeat);
|
||||
joystick[j].input_pressed |= joystick[j].action_pressed[d];
|
||||
}
|
||||
|
||||
joystick[j].confirm = joystick[j].action[0] || joystick[j].action[4];
|
||||
joystick[j].cancel = joystick[j].action[1] || joystick[j].action[5];
|
||||
|
||||
// if new input, reset press-repeat delay
|
||||
if (joystick[j].input_pressed)
|
||||
joystick[j].joystick_delay = SDL_GetTicks() + joystick_repeat_delay;
|
||||
}
|
||||
|
||||
// updates all joystick states
|
||||
void poll_joysticks( void )
|
||||
{
|
||||
joydown = false;
|
||||
|
||||
for (int j = 0; j < joysticks; j++)
|
||||
poll_joystick(j);
|
||||
}
|
||||
|
||||
// sends SDL KEYDOWN and KEYUP events for a key
|
||||
void push_key( SDLKey key )
|
||||
{
|
||||
SDL_Event e;
|
||||
|
||||
memset(&e.key.keysym, 0, sizeof(e.key.keysym));
|
||||
|
||||
e.key.keysym.sym = key;
|
||||
e.key.keysym.unicode = key;
|
||||
|
||||
e.key.state = SDL_RELEASED;
|
||||
|
||||
e.type = SDL_KEYDOWN;
|
||||
SDL_PushEvent(&e);
|
||||
|
||||
e.type = SDL_KEYUP;
|
||||
SDL_PushEvent(&e);
|
||||
}
|
||||
|
||||
// helps us be lazy by pretending joysticks are a keyboard (useful for menus)
|
||||
void push_joysticks_as_keyboard( void )
|
||||
{
|
||||
const SDLKey confirm = SDLK_RETURN, cancel = SDLK_ESCAPE;
|
||||
const SDLKey direction[4] = { SDLK_UP, SDLK_RIGHT, SDLK_DOWN, SDLK_LEFT };
|
||||
|
||||
poll_joysticks();
|
||||
|
||||
for (int j = 0; j < joysticks; j++)
|
||||
{
|
||||
if (!joystick[j].input_pressed)
|
||||
continue;
|
||||
|
||||
if (joystick[j].confirm)
|
||||
push_key(confirm);
|
||||
if (joystick[j].cancel)
|
||||
push_key(cancel);
|
||||
|
||||
for (uint d = 0; d < COUNTOF(joystick[j].direction_pressed); d++)
|
||||
{
|
||||
if (joystick[j].direction_pressed[d])
|
||||
push_key(direction[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initializes SDL joystick system and loads assignments for joysticks found
|
||||
void init_joysticks( void )
|
||||
{
|
||||
if (ignore_joystick)
|
||||
return;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
|
||||
{
|
||||
fprintf(stderr, "warning: failed to initialize joystick system: %s\n", SDL_GetError());
|
||||
ignore_joystick = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_JoystickEventState(SDL_IGNORE);
|
||||
|
||||
joysticks = SDL_NumJoysticks();
|
||||
joystick = malloc(joysticks * sizeof(*joystick));
|
||||
|
||||
for (int j = 0; j < joysticks; j++)
|
||||
{
|
||||
memset(&joystick[j], 0, sizeof(*joystick));
|
||||
|
||||
joystick[j].handle = SDL_JoystickOpen(j);
|
||||
if (joystick[j].handle != NULL)
|
||||
{
|
||||
printf("joystick detected: %s ", SDL_JoystickName(j));
|
||||
printf("(%d axes, %d buttons, %d hats)\n",
|
||||
SDL_JoystickNumAxes(joystick[j].handle),
|
||||
SDL_JoystickNumButtons(joystick[j].handle),
|
||||
SDL_JoystickNumHats(joystick[j].handle));
|
||||
|
||||
if (!load_joystick_assignments(&opentyrian_config, j))
|
||||
reset_joystick_assignments(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (joysticks == 0)
|
||||
printf("no joysticks detected\n");
|
||||
}
|
||||
|
||||
// deinitializes SDL joystick system and saves joystick assignments
|
||||
void deinit_joysticks( void )
|
||||
{
|
||||
if (ignore_joystick)
|
||||
return;
|
||||
|
||||
for (int j = 0; j < joysticks; j++)
|
||||
{
|
||||
if (joystick[j].handle != NULL)
|
||||
{
|
||||
save_joystick_assignments(&opentyrian_config, j);
|
||||
SDL_JoystickClose(joystick[j].handle);
|
||||
}
|
||||
}
|
||||
|
||||
free(joystick);
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
||||
void reset_joystick_assignments( int j )
|
||||
{
|
||||
assert(j < joysticks);
|
||||
|
||||
// defaults: first 2 axes, first hat, first 6 buttons
|
||||
for (uint a = 0; a < COUNTOF(joystick[j].assignment); a++)
|
||||
{
|
||||
// clear assignments
|
||||
for (uint i = 0; i < COUNTOF(joystick[j].assignment[a]); i++)
|
||||
joystick[j].assignment[a][i].type = NONE;
|
||||
|
||||
if (a < 4)
|
||||
{
|
||||
if (SDL_JoystickNumAxes(joystick[j].handle) >= 2)
|
||||
{
|
||||
joystick[j].assignment[a][0].type = AXIS;
|
||||
joystick[j].assignment[a][0].num = (a + 1) % 2;
|
||||
joystick[j].assignment[a][0].negative_axis = (a == 0 || a == 3);
|
||||
}
|
||||
|
||||
if (SDL_JoystickNumHats(joystick[j].handle) >= 1)
|
||||
{
|
||||
joystick[j].assignment[a][1].type = HAT;
|
||||
joystick[j].assignment[a][1].num = 0;
|
||||
joystick[j].assignment[a][1].x_axis = (a == 1 || a == 3);
|
||||
joystick[j].assignment[a][1].negative_axis = (a == 0 || a == 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a - 4 < (unsigned)SDL_JoystickNumButtons(joystick[j].handle))
|
||||
{
|
||||
joystick[j].assignment[a][0].type = BUTTON;
|
||||
joystick[j].assignment[a][0].num = a - 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
joystick[j].analog = false;
|
||||
joystick[j].sensitivity = 5;
|
||||
joystick[j].threshold = 5;
|
||||
}
|
||||
|
||||
static const char* const assignment_names[] =
|
||||
{
|
||||
"up",
|
||||
"right",
|
||||
"down",
|
||||
"left",
|
||||
"fire",
|
||||
"change fire",
|
||||
"left sidekick",
|
||||
"right sidekick",
|
||||
"menu",
|
||||
"pause",
|
||||
};
|
||||
|
||||
bool load_joystick_assignments( Config *config, int j )
|
||||
{
|
||||
ConfigSection *section = config_find_section(config, "joystick", SDL_JoystickName(j));
|
||||
if (section == NULL)
|
||||
return false;
|
||||
|
||||
if (!config_get_bool_option(section, "analog", &joystick[j].analog))
|
||||
joystick[j].analog = false;
|
||||
|
||||
joystick[j].sensitivity = config_get_or_set_int_option(section, "sensitivity", 5);
|
||||
|
||||
joystick[j].threshold = config_get_or_set_int_option(section, "threshold", 5);
|
||||
|
||||
for (size_t a = 0; a < COUNTOF(assignment_names); ++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < COUNTOF(joystick[j].assignment[a]); ++i)
|
||||
joystick[j].assignment[a][i].type = NONE;
|
||||
|
||||
ConfigOption *option = config_get_option(section, assignment_names[a]);
|
||||
if (option == NULL)
|
||||
continue;
|
||||
|
||||
foreach_option_i_value(i, value, option)
|
||||
{
|
||||
if (i >= COUNTOF(joystick[j].assignment[a]))
|
||||
break;
|
||||
|
||||
code_to_assignment(&joystick[j].assignment[a][i], value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save_joystick_assignments( Config *config, int j )
|
||||
{
|
||||
ConfigSection *section = config_find_or_add_section(config, "joystick", SDL_JoystickName(j));
|
||||
if (section == NULL)
|
||||
exit(EXIT_FAILURE); // out of memory
|
||||
|
||||
config_set_bool_option(section, "analog", joystick[j].analog, NO_YES);
|
||||
|
||||
config_set_int_option(section, "sensitivity", joystick[j].sensitivity);
|
||||
|
||||
config_set_int_option(section, "threshold", joystick[j].threshold);
|
||||
|
||||
for (size_t a = 0; a < COUNTOF(assignment_names); ++a)
|
||||
{
|
||||
ConfigOption *option = config_set_option(section, assignment_names[a], NULL);
|
||||
if (option == NULL)
|
||||
exit(EXIT_FAILURE); // out of memory
|
||||
|
||||
option = config_set_value(option, NULL);
|
||||
if (option == NULL)
|
||||
exit(EXIT_FAILURE); // out of memory
|
||||
|
||||
for (size_t i = 0; i < COUNTOF(joystick[j].assignment[a]); ++i)
|
||||
{
|
||||
if (joystick[j].assignment[a][i].type == NONE)
|
||||
continue;
|
||||
|
||||
option = config_add_value(option, assignment_to_code(&joystick[j].assignment[a][i]));
|
||||
if (option == NULL)
|
||||
exit(EXIT_FAILURE); // out of memory
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// fills buffer with comma separated list of assigned joystick functions
|
||||
void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments )
|
||||
{
|
||||
strncpy(buffer, "", buffer_len);
|
||||
|
||||
bool comma = false;
|
||||
for (uint i = 0; i < COUNTOF(*joystick->assignment); ++i)
|
||||
{
|
||||
if (assignments[i].type == NONE)
|
||||
continue;
|
||||
|
||||
size_t len = snprintf(buffer, buffer_len, "%s%s",
|
||||
comma ? ", " : "",
|
||||
assignment_to_code(&assignments[i]));
|
||||
buffer += len;
|
||||
buffer_len -= len;
|
||||
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
|
||||
// reverse of assignment_to_code()
|
||||
void code_to_assignment( Joystick_assignment *assignment, const char *buffer )
|
||||
{
|
||||
memset(assignment, 0, sizeof(*assignment));
|
||||
|
||||
char axis = 0, direction = 0;
|
||||
|
||||
if (sscanf(buffer, " AX %d%c", &assignment->num, &direction) == 2)
|
||||
assignment->type = AXIS;
|
||||
else if (sscanf(buffer, " BTN %d", &assignment->num) == 1)
|
||||
assignment->type = BUTTON;
|
||||
else if (sscanf(buffer, " H %d%c%c", &assignment->num, &axis, &direction) == 3)
|
||||
assignment->type = HAT;
|
||||
|
||||
if (assignment->num == 0)
|
||||
assignment->type = NONE;
|
||||
else
|
||||
--assignment->num;
|
||||
|
||||
assignment->x_axis = (toupper(axis) == 'X');
|
||||
assignment->negative_axis = (toupper(direction) == '-');
|
||||
}
|
||||
|
||||
/* gives the short (6 or less characters) identifier for a joystick assignment
|
||||
*
|
||||
* two of these per direction/action is all that can fit on the joystick config screen,
|
||||
* assuming two digits for the axis/button/hat number
|
||||
*/
|
||||
const char *assignment_to_code( const Joystick_assignment *assignment )
|
||||
{
|
||||
static char name[7];
|
||||
|
||||
switch (assignment->type)
|
||||
{
|
||||
case NONE:
|
||||
strcpy(name, "");
|
||||
break;
|
||||
|
||||
case AXIS:
|
||||
snprintf(name, sizeof(name), "AX %d%c",
|
||||
assignment->num + 1,
|
||||
assignment->negative_axis ? '-' : '+');
|
||||
break;
|
||||
|
||||
case BUTTON:
|
||||
snprintf(name, sizeof(name), "BTN %d",
|
||||
assignment->num + 1);
|
||||
break;
|
||||
|
||||
case HAT:
|
||||
snprintf(name, sizeof(name), "H %d%c%c",
|
||||
assignment->num + 1,
|
||||
assignment->x_axis ? 'X' : 'Y',
|
||||
assignment->negative_axis ? '-' : '+');
|
||||
break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// captures joystick input for configuring assignments
|
||||
// returns false if non-joystick input was detected
|
||||
// TODO: input from joystick other than the one being configured probably should not be ignored
|
||||
bool detect_joystick_assignment( int j, Joystick_assignment *assignment )
|
||||
{
|
||||
// get initial joystick state to compare against to see if anything was pressed
|
||||
|
||||
const int axes = SDL_JoystickNumAxes(joystick[j].handle);
|
||||
Sint16 *axis = malloc(axes * sizeof(*axis));
|
||||
for (int i = 0; i < axes; i++)
|
||||
axis[i] = SDL_JoystickGetAxis(joystick[j].handle, i);
|
||||
|
||||
const int buttons = SDL_JoystickNumButtons(joystick[j].handle);
|
||||
Uint8 *button = malloc(buttons * sizeof(*button));
|
||||
for (int i = 0; i < buttons; i++)
|
||||
button[i] = SDL_JoystickGetButton(joystick[j].handle, i);
|
||||
|
||||
const int hats = SDL_JoystickNumHats(joystick[j].handle);
|
||||
Uint8 *hat = malloc(hats * sizeof(*hat));
|
||||
for (int i = 0; i < hats; i++)
|
||||
hat[i] = SDL_JoystickGetHat(joystick[j].handle, i);
|
||||
|
||||
bool detected = false;
|
||||
|
||||
do
|
||||
{
|
||||
setjasondelay(1);
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
|
||||
for (int i = 0; i < axes; ++i)
|
||||
{
|
||||
Sint16 temp = SDL_JoystickGetAxis(joystick[j].handle, i);
|
||||
|
||||
if (abs(temp - axis[i]) > joystick_analog_max * 2 / 3)
|
||||
{
|
||||
assignment->type = AXIS;
|
||||
assignment->num = i;
|
||||
assignment->negative_axis = temp < axis[i];
|
||||
detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < buttons; ++i)
|
||||
{
|
||||
Uint8 new_button = SDL_JoystickGetButton(joystick[j].handle, i),
|
||||
changed = button[i] ^ new_button;
|
||||
|
||||
if (!changed)
|
||||
continue;
|
||||
|
||||
if (new_button == 0) // button was released
|
||||
{
|
||||
button[i] = new_button;
|
||||
}
|
||||
else // button was pressed
|
||||
{
|
||||
assignment->type = BUTTON;
|
||||
assignment->num = i;
|
||||
detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < hats; ++i)
|
||||
{
|
||||
Uint8 new_hat = SDL_JoystickGetHat(joystick[j].handle, i),
|
||||
changed = hat[i] ^ new_hat;
|
||||
|
||||
if (!changed)
|
||||
continue;
|
||||
|
||||
if ((new_hat & changed) == SDL_HAT_CENTERED) // hat was centered
|
||||
{
|
||||
hat[i] = new_hat;
|
||||
}
|
||||
else
|
||||
{
|
||||
assignment->type = HAT;
|
||||
assignment->num = i;
|
||||
assignment->x_axis = changed & (SDL_HAT_LEFT | SDL_HAT_RIGHT);
|
||||
assignment->negative_axis = changed & (SDL_HAT_LEFT | SDL_HAT_UP);
|
||||
detected = true;
|
||||
}
|
||||
}
|
||||
|
||||
service_SDL_events(true);
|
||||
JE_showVGA();
|
||||
|
||||
wait_delay();
|
||||
}
|
||||
while (!detected && !newkey && !newmouse);
|
||||
|
||||
free(axis);
|
||||
free(button);
|
||||
free(hat);
|
||||
|
||||
return detected;
|
||||
}
|
||||
|
||||
// compares relevant parts of joystick assignments for equality
|
||||
bool joystick_assignment_cmp( const Joystick_assignment *a, const Joystick_assignment *b )
|
||||
{
|
||||
if (a->type == b->type)
|
||||
{
|
||||
switch (a->type)
|
||||
{
|
||||
case NONE:
|
||||
return true;
|
||||
case AXIS:
|
||||
return (a->num == b->num) &&
|
||||
(a->negative_axis == b->negative_axis);
|
||||
case BUTTON:
|
||||
return (a->num == b->num);
|
||||
case HAT:
|
||||
return (a->num == b->num) &&
|
||||
(a->x_axis == b->x_axis) &&
|
||||
(a->negative_axis == b->negative_axis);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef JOYSTICK_H
|
||||
#define JOYSTICK_H
|
||||
|
||||
#include "opentyr.h"
|
||||
#include "config_file.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NONE,
|
||||
AXIS,
|
||||
BUTTON,
|
||||
HAT
|
||||
}
|
||||
Joystick_assignment_types;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Joystick_assignment_types type;
|
||||
int num;
|
||||
|
||||
// if hat
|
||||
bool x_axis; // else y_axis
|
||||
|
||||
// if hat or axis
|
||||
bool negative_axis; // else positive
|
||||
}
|
||||
Joystick_assignment;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_Joystick *handle;
|
||||
|
||||
Joystick_assignment assignment[10][2]; // 0-3: directions, 4-9: actions
|
||||
|
||||
bool analog;
|
||||
int sensitivity, threshold;
|
||||
|
||||
signed int x, y;
|
||||
int analog_direction[4];
|
||||
bool direction[4], direction_pressed[4]; // up, right, down, left (_pressed, for emulating key presses)
|
||||
|
||||
bool confirm, cancel;
|
||||
bool action[6], action_pressed[6]; // fire, mode swap, left fire, right fire, menu, pause
|
||||
|
||||
Uint32 joystick_delay;
|
||||
bool input_pressed;
|
||||
}
|
||||
Joystick;
|
||||
|
||||
extern int joystick_repeat_delay;
|
||||
extern bool joydown;
|
||||
extern bool ignore_joystick;
|
||||
extern int joysticks;
|
||||
extern Joystick *joystick;
|
||||
|
||||
int joystick_axis_reduce( int j, int value );
|
||||
bool joystick_analog_angle( int j, float *angle );
|
||||
|
||||
void poll_joystick( int j );
|
||||
void poll_joysticks( void );
|
||||
|
||||
void push_key( SDLKey key );
|
||||
void push_joysticks_as_keyboard( void );
|
||||
|
||||
void init_joysticks( void );
|
||||
void deinit_joysticks( void );
|
||||
|
||||
void reset_joystick_assignments( int j );
|
||||
bool load_joystick_assignments( Config* config, int j );
|
||||
bool save_joystick_assignments( Config* config, int j );
|
||||
|
||||
void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments );
|
||||
|
||||
bool detect_joystick_assignment( int j, Joystick_assignment *assignment );
|
||||
bool joystick_assignment_cmp( const Joystick_assignment *, const Joystick_assignment * );
|
||||
|
||||
#endif /* JOYSTICK_H */
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "jukebox.h"
|
||||
|
||||
#include "font.h"
|
||||
#include "joystick.h"
|
||||
#include "keyboard.h"
|
||||
#include "lds_play.h"
|
||||
#include "loudness.h"
|
||||
#include "mtrand.h"
|
||||
#include "nortsong.h"
|
||||
#include "opentyr.h"
|
||||
#include "palette.h"
|
||||
#include "sprite.h"
|
||||
#include "starlib.h"
|
||||
#include "vga_palette.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void jukebox( void )
|
||||
{
|
||||
bool trigger_quit = false, // true when user wants to quit
|
||||
quitting = false;
|
||||
|
||||
bool hide_text = false;
|
||||
|
||||
bool fade_looped_songs = true, fading_song = false;
|
||||
bool stopped = false;
|
||||
|
||||
bool fx = false;
|
||||
int fx_num = 0;
|
||||
|
||||
int palette_fade_steps = 15;
|
||||
|
||||
int diff[256][3];
|
||||
init_step_fade_palette(diff, vga_palette, 0, 255);
|
||||
|
||||
JE_starlib_init();
|
||||
|
||||
int fade_volume = tyrMusicVolume;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (!stopped && !audio_disabled)
|
||||
{
|
||||
if (songlooped && fade_looped_songs)
|
||||
fading_song = true;
|
||||
|
||||
if (fading_song)
|
||||
{
|
||||
if (fade_volume > 5)
|
||||
{
|
||||
fade_volume -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
fade_volume = tyrMusicVolume;
|
||||
|
||||
fading_song = false;
|
||||
}
|
||||
|
||||
set_volume(fade_volume, fxVolume);
|
||||
}
|
||||
|
||||
if (!playing || (songlooped && fade_looped_songs && !fading_song))
|
||||
play_song(mt_rand() % MUSIC_NUM);
|
||||
}
|
||||
|
||||
setdelay(1);
|
||||
|
||||
SDL_FillRect(VGAScreenSeg, NULL, 0);
|
||||
|
||||
// starlib input needs to be rewritten
|
||||
JE_starlib_main();
|
||||
|
||||
push_joysticks_as_keyboard();
|
||||
service_SDL_events(true);
|
||||
|
||||
if (!hide_text)
|
||||
{
|
||||
char buffer[60];
|
||||
|
||||
if (fx)
|
||||
snprintf(buffer, sizeof(buffer), "%d %s", fx_num + 1, soundTitle[fx_num]);
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer), "%d %s", song_playing + 1, musicTitle[song_playing]);
|
||||
|
||||
const int x = VGAScreen->w / 2;
|
||||
|
||||
draw_font_hv(VGAScreen, x, 170, "Press ESC to quit the jukebox.", small_font, centered, 1, 0);
|
||||
draw_font_hv(VGAScreen, x, 180, "Arrow keys change the song being played.", small_font, centered, 1, 0);
|
||||
draw_font_hv(VGAScreen, x, 190, buffer, small_font, centered, 1, 4);
|
||||
}
|
||||
|
||||
if (palette_fade_steps > 0)
|
||||
step_fade_palette(diff, palette_fade_steps--, 0, 255);
|
||||
|
||||
JE_showVGA();
|
||||
|
||||
wait_delay();
|
||||
|
||||
// quit on mouse click
|
||||
Uint16 x, y;
|
||||
if (JE_mousePosition(&x, &y) > 0)
|
||||
trigger_quit = true;
|
||||
|
||||
if (newkey)
|
||||
{
|
||||
switch (lastkey_sym)
|
||||
{
|
||||
case SDLK_ESCAPE: // quit jukebox
|
||||
case SDLK_q:
|
||||
trigger_quit = true;
|
||||
break;
|
||||
|
||||
case SDLK_SPACE:
|
||||
hide_text = !hide_text;
|
||||
break;
|
||||
|
||||
case SDLK_f:
|
||||
fading_song = !fading_song;
|
||||
break;
|
||||
case SDLK_n:
|
||||
fade_looped_songs = !fade_looped_songs;
|
||||
break;
|
||||
|
||||
case SDLK_SLASH: // switch to sfx mode
|
||||
fx = !fx;
|
||||
break;
|
||||
case SDLK_COMMA:
|
||||
if (fx && --fx_num < 0)
|
||||
fx_num = SAMPLE_COUNT - 1;
|
||||
break;
|
||||
case SDLK_PERIOD:
|
||||
if (fx && ++fx_num >= SAMPLE_COUNT)
|
||||
fx_num = 0;
|
||||
break;
|
||||
case SDLK_SEMICOLON:
|
||||
if (fx)
|
||||
JE_playSampleNum(fx_num + 1);
|
||||
break;
|
||||
|
||||
case SDLK_LEFT:
|
||||
case SDLK_UP:
|
||||
play_song((song_playing > 0 ? song_playing : MUSIC_NUM) - 1);
|
||||
stopped = false;
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RIGHT:
|
||||
case SDLK_DOWN:
|
||||
play_song((song_playing + 1) % MUSIC_NUM);
|
||||
stopped = false;
|
||||
break;
|
||||
case SDLK_s: // stop song
|
||||
stop_song();
|
||||
stopped = true;
|
||||
break;
|
||||
case SDLK_r: // restart song
|
||||
restart_song();
|
||||
stopped = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// user wants to quit, start fade-out
|
||||
if (trigger_quit && !quitting)
|
||||
{
|
||||
palette_fade_steps = 15;
|
||||
|
||||
SDL_Color black = { 0, 0, 0 };
|
||||
init_step_fade_solid(diff, black, 0, 255);
|
||||
|
||||
quitting = true;
|
||||
}
|
||||
|
||||
// if fade-out finished, we can finally quit
|
||||
if (quitting && palette_fade_steps == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
set_volume(tyrMusicVolume, fxVolume);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef JUKEBOX_H
|
||||
#define JUKEBOX_H
|
||||
|
||||
#include "opentyr.h"
|
||||
|
||||
void jukebox( void );
|
||||
|
||||
#endif /* JUKEBOX_H */
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* OpenTyrian: A modern cross-platform port of Tyrian
|
||||
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "keyboard.h"
|
||||
|
||||
#include "joystick.h"
|
||||
#include "network.h"
|
||||
#include "opentyr.h"
|
||||
#include "video.h"
|
||||
#include "video_scale.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
JE_boolean ESCPressed;
|
||||
|
||||
JE_boolean newkey, newmouse, keydown, mousedown;
|
||||
SDLKey lastkey_sym;
|
||||
SDLMod lastkey_mod;
|
||||
unsigned char lastkey_char;
|
||||
Uint8 lastmouse_but;
|
||||
Uint16 lastmouse_x, lastmouse_y;
|
||||
JE_boolean mouse_pressed[3] = {false, false, false};
|
||||
Uint16 mouse_x, mouse_y;
|
||||
|
||||
Uint8 keysactive[SDLK_LAST];
|
||||
|
||||
#ifdef NDEBUG
|
||||
bool input_grab_enabled = true;
|
||||
#else
|
||||
bool input_grab_enabled = false;
|
||||
#endif
|
||||
|
||||
|
||||
void flush_events_buffer( void )
|
||||
{
|
||||
SDL_Event ev;
|
||||
|
||||
while (SDL_PollEvent(&ev));
|
||||
}
|
||||
|
||||
void wait_input( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick )
|
||||
{
|
||||
service_SDL_events(false);
|
||||
while (!((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)))
|
||||
{
|
||||
uSDL_Delay(SDL_POLL_INTERVAL);
|
||||
push_joysticks_as_keyboard();
|
||||
service_SDL_events(false);
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
if (isNetworkGame)
|
||||
network_check();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick )
|
||||
{
|
||||
service_SDL_events(false);
|
||||
while ((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown))
|
||||
{
|
||||
uSDL_Delay(SDL_POLL_INTERVAL);
|
||||
poll_joysticks();
|
||||
service_SDL_events(false);
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
if (isNetworkGame)
|
||||
network_check();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void init_keyboard( void )
|
||||
{
|
||||
SDL_EnableKeyRepeat(500, 60);
|
||||
|
||||
newkey = newmouse = false;
|
||||
keydown = mousedown = false;
|
||||
|
||||
SDL_EnableUNICODE(1);
|
||||
}
|
||||
|
||||
void input_grab( bool enable )
|
||||
{
|
||||
#if defined(TARGET_GP2X) || defined(TARGET_DINGUX)
|
||||
enable = true;
|
||||
#endif
|
||||
|
||||
input_grab_enabled = enable || fullscreen_enabled;
|
||||
|
||||
SDL_ShowCursor(input_grab_enabled ? SDL_DISABLE : SDL_ENABLE);
|
||||
#ifdef NDEBUG
|
||||
SDL_WM_GrabInput(input_grab_enabled ? SDL_GRAB_ON : SDL_GRAB_OFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
JE_word JE_mousePosition( JE_word *mouseX, JE_word *mouseY )
|
||||
{
|
||||
service_SDL_events(false);
|
||||
*mouseX = mouse_x;
|
||||
*mouseY = mouse_y;
|
||||
return mousedown ? lastmouse_but : 0;
|
||||
}
|
||||
|
||||
void set_mouse_position( int x, int y )
|
||||
{
|
||||
if (input_grab_enabled)
|
||||
{
|
||||
SDL_WarpMouse(x * scalers[scaler].width / vga_width, y * scalers[scaler].height / vga_height);
|
||||
mouse_x = x;
|
||||
mouse_y = y;
|
||||
}
|
||||
}
|
||||
|
||||
void service_SDL_events( JE_boolean clear_new )
|
||||
{
|
||||
SDL_Event ev;
|
||||
|
||||
if (clear_new)
|
||||
newkey = newmouse = false;
|
||||
|
||||
while (SDL_PollEvent(&ev))
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
case SDL_ACTIVEEVENT:
|
||||
if (ev.active.state == SDL_APPINPUTFOCUS && !ev.active.gain)
|
||||
input_grab(false);
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse_x = ev.motion.x * vga_width / scalers[scaler].width;
|
||||
mouse_y = ev.motion.y * vga_height / scalers[scaler].height;
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (ev.key.keysym.mod & KMOD_CTRL)
|
||||
{
|
||||
/* <ctrl><bksp> emergency kill */
|
||||
if (ev.key.keysym.sym == SDLK_BACKSPACE)
|
||||
{
|
||||
puts("\n\n\nCtrl+Backspace pressed. Doing emergency quit.\n");
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* <ctrl><f10> toggle input grab */
|
||||
if (ev.key.keysym.sym == SDLK_F10)
|
||||
{
|
||||
input_grab(!input_grab_enabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.key.keysym.mod & KMOD_ALT)
|
||||
{
|
||||
/* <alt><enter> toggle fullscreen */
|
||||
if (ev.key.keysym.sym == SDLK_RETURN)
|
||||
{
|
||||
if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state
|
||||
!init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state
|
||||
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* <alt><tab> disable input grab and fullscreen */
|
||||
if (ev.key.keysym.sym == SDLK_TAB)
|
||||
{
|
||||
if (!init_scaler(scaler, false) && // try windowed
|
||||
!init_any_scaler(false) && // try any scaler windowed
|
||||
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||