OpenTyrian: Sources uploaded

git-svn-id: svn://kolibrios.org@9169 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
turbocat
2021-08-31 18:22:39 +00:00
parent a17d3b7653
commit a27452493c
115 changed files with 49569 additions and 0 deletions
+26
View File
@@ -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
+36
View File
@@ -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/
+88
View File
@@ -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
+141
View File
@@ -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 $@ $<
+642
View File
@@ -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);
}
+218
View File
@@ -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;
}
}
+150
View File
@@ -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 */
+591
View File
@@ -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 */
+65
View 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;
+153
View File
@@ -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
+53
View File
@@ -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);
}
+431
View File
@@ -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);
}
+27
View File
@@ -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 */
+248
View File
@@ -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
}
+58
View File
@@ -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 */
+527
View File
@@ -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;
}
}
}
}
+64
View File
@@ -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
+148
View File
@@ -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
+596
View File
@@ -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
+27
View File
@@ -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 */
+92
View File
@@ -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);
}
}
+36
View File
@@ -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 */
+267
View File
@@ -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;
}
+173
View File
@@ -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 */
+208
View File
@@ -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;
}
+44
View File
@@ -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
+275
View File
@@ -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;
}
}
}
+49
View File
@@ -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
+334
View File
@@ -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;
}
+58
View File
@@ -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
+58
View File
@@ -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
+381
View File
@@ -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);
}
+80
View File
@@ -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 */
+653
View File
@@ -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;
}
+98
View File
@@ -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 */
+203
View File
@@ -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);
}
+27
View File
@@ -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 */
+255
View File
@@ -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);
}